summaryrefslogtreecommitdiff
path: root/altosdroid
diff options
context:
space:
mode:
authorBdale Garbee <bdale@gag.com>2013-05-16 00:36:23 -0600
committerBdale Garbee <bdale@gag.com>2013-05-16 00:36:23 -0600
commit02d111b1b53ef01fc6e9ab6c4bc60b8af1be0067 (patch)
tree8356f4a019969ee99a45e264c87d38555cf316cc /altosdroid
parent7a2e1f05adad990a6b161865267abf07ffec7a7e (diff)
parent7699a55aed3a9a7daeb4c6a5a9a280f43edf455f (diff)
Merge branch 'branch-1.2' into debian
Diffstat (limited to 'altosdroid')
-rw-r--r--altosdroid/.classpath4
-rw-r--r--altosdroid/.externalToolBuilders/Generate BuildInfo.java.launch11
-rw-r--r--altosdroid/.gitignore4
-rw-r--r--altosdroid/.project10
-rw-r--r--altosdroid/AndroidManifest.xml33
-rw-r--r--altosdroid/Makefile.am79
-rw-r--r--altosdroid/Notebook30
-rwxr-xr-xaltosdroid/buildinfo.sh42
-rw-r--r--altosdroid/libs/.gitignore1
-rw-r--r--altosdroid/project.properties3
-rw-r--r--altosdroid/release.keystorebin0 -> 1243 bytes
-rw-r--r--altosdroid/res/drawable/pad.pngbin0 -> 584 bytes
-rw-r--r--altosdroid/res/drawable/rocket.pngbin0 -> 1286 bytes
-rw-r--r--altosdroid/res/layout/altosdroid.xml535
-rw-r--r--altosdroid/res/layout/main.xml33
-rw-r--r--altosdroid/res/layout/message.xml21
-rw-r--r--altosdroid/res/layout/tab_ascent.xml299
-rw-r--r--altosdroid/res/layout/tab_descent.xml339
-rw-r--r--altosdroid/res/layout/tab_landed.xml211
-rw-r--r--altosdroid/res/layout/tab_map.xml188
-rw-r--r--altosdroid/res/layout/tab_pad.xml320
-rw-r--r--altosdroid/res/values/strings.xml113
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java2
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java236
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java101
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java25
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosViewPager.java43
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java5
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/BuildInfo.java.in30
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java10
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/GoNoGoLights.java64
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java112
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java122
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java98
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java198
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java149
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TabsAdapter.java133
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TelemetryLogger.java73
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java4
-rw-r--r--altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java64
40 files changed, 3195 insertions, 550 deletions
diff --git a/altosdroid/.classpath b/altosdroid/.classpath
index 0ca188f9..fce248e6 100644
--- a/altosdroid/.classpath
+++ b/altosdroid/.classpath
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
- <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry kind="lib" path="libs/android-support-v4.jar"/>
+ <classpathentry kind="lib" path="libs/altoslib_1.jar"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
diff --git a/altosdroid/.externalToolBuilders/Generate BuildInfo.java.launch b/altosdroid/.externalToolBuilders/Generate BuildInfo.java.launch
new file mode 100644
index 00000000..3b8eff45
--- /dev/null
+++ b/altosdroid/.externalToolBuilders/Generate BuildInfo.java.launch
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
+<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/AltosDroid/src/org/altusmetrum/AltosDroid/BuildInfo.java&quot; type=&quot;1&quot;/&gt;&#10;&lt;/resources&gt;}"/>
+<booleanAttribute key="org.eclipse.debug.core.capture_output" value="false"/>
+<booleanAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON" value="false"/>
+<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/AltosDroid/buildinfo.sh}"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
+<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/AltosDroid}"/>
+</launchConfiguration>
diff --git a/altosdroid/.gitignore b/altosdroid/.gitignore
index c0bb8dd4..7f0858ea 100644
--- a/altosdroid/.gitignore
+++ b/altosdroid/.gitignore
@@ -1,3 +1,7 @@
local.properties
bin
gen
+libs
+google-play-services_lib
+src/org/altusmetrum/AltosDroid/BuildInfo.java
+res/drawable/*led.png
diff --git a/altosdroid/.project b/altosdroid/.project
index 7b56596a..ebe4a4bb 100644
--- a/altosdroid/.project
+++ b/altosdroid/.project
@@ -6,6 +6,16 @@
</projects>
<buildSpec>
<buildCommand>
+ <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+ <triggers>auto,full,incremental,</triggers>
+ <arguments>
+ <dictionary>
+ <key>LaunchConfigHandle</key>
+ <value>&lt;project&gt;/.externalToolBuilders/Generate BuildInfo.java.launch</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
diff --git a/altosdroid/AndroidManifest.xml b/altosdroid/AndroidManifest.xml
index 12391759..04a679e1 100644
--- a/altosdroid/AndroidManifest.xml
+++ b/altosdroid/AndroidManifest.xml
@@ -16,17 +16,34 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.altusmetrum.AltosDroid"
- android:versionCode="1"
- android:versionName="1.0">
+ package="org.altusmetrum.AltosDroid"
+ android:versionCode="3"
+ android:versionName="1.2">
<uses-sdk android:targetSdkVersion="10" android:minSdkVersion="10"/>
+ <!-- Google Maps -->
+ <uses-feature android:glEsVersion="0x00020000" android:required="true"/>
+
+ <!-- Permissions needed to access bluetooth -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
+ <!-- Permissions needed to save Telemetry logs to SD card -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <!-- Permissions needed for GoogleMaps -->
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+
+ <permission android:name="org.altusmetrum.AltosDroid.permission.MAPS_RECEIVE"
+ android:protectionLevel="signature"/>
+ <uses-permission android:name="org.altusmetrum.AltosDroid.permission.MAPS_RECEIVE"/>
+
<application android:label="@string/app_name"
- android:icon="@drawable/app_icon" >
- <activity android:label="@string/app_name"
- android:configChanges="orientation|keyboardHidden" android:name="org.altusmetrum.AltosDroid.AltosDroid">
+ android:icon="@drawable/app_icon"
+ android:allowBackup="true" >
+ <activity android:name="org.altusmetrum.AltosDroid.AltosDroid"
+ android:label="@string/app_name"
+ android:configChanges="orientation|keyboardHidden" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -37,9 +54,9 @@
android:theme="@android:style/Theme.Dialog"
android:configChanges="orientation|keyboardHidden" />
-
<service android:name=".TelemetryService" />
-
+ <meta-data android:name="com.google.android.maps.v2.API_KEY"
+ android:value="AIzaSyDSr6u4i9TJmVGhgGk4g0wUUhTy9FGyn0s"/>
</application>
</manifest>
diff --git a/altosdroid/Makefile.am b/altosdroid/Makefile.am
index 36d28ca2..0473c17a 100644
--- a/altosdroid/Makefile.am
+++ b/altosdroid/Makefile.am
@@ -1,12 +1,11 @@
if ANDROID
-all_target=bin/AltosDroid-debug.apk bin/AltosDroid-release.apk
-clean_command=ant clean
+all_target=bin/AltosDroid-debug.apk bin/AltosDroid-release-unsigned.apk
else
all_target=
-clean_command=echo done
endif
SDK=$(ANDROID_SDK)
+SDK_TARGET=$(shell sed -ne 's/^target=//p' project.properties)
DX=$(SDK)/platform-tools/dx
ADB=$(SDK)/platform-tools/adb
@@ -14,26 +13,51 @@ AAPT=$(SDK)/platform-tools/aapt
APKBUILDER=$(SDK)/tools/apkbuilder
ZIPALIGN=$(SDK)/tools/zipalign
-SRC_DIR=src/org/altusmetrum/AltosDroid
+JAVA_SRC_DIR=src/org/altusmetrum/AltosDroid
EXT_LIBDIR=libs
+DRAWABLE_DIR=res/drawable
ALTOSLIB_SRCDIR=../altoslib
-ALTOSLIB_JAR=AltosLib.jar
+ALTOSLIB_JAR=altoslib_$(ALTOSLIB_VERSION).jar
ALTOSLIB=$(EXT_LIBDIR)/$(ALTOSLIB_JAR)
-SRC=\
- $(SRC_DIR)/AltosDroid.java \
- $(SRC_DIR)/TelemetryService.java \
- $(SRC_DIR)/TelemetryReader.java \
- $(SRC_DIR)/AltosBluetooth.java \
- $(SRC_DIR)/DeviceListActivity.java \
- $(SRC_DIR)/Dumper.java
+SUPPORT_V4_SRCDIR=$(SDK)/extras/android/support/v4
+SUPPORT_V4_JAR=android-support-v4.jar
+
+SUPPORT_V4=$(EXT_LIBDIR)/$(SUPPORT_V4_JAR)
+
+GOOGLE_PLAY_SERVICES_LIB_SRCDIR=$(SDK)/extras/google/google_play_services/libproject
+GOOGLE_PLAY_SERVICES_LIB=google-play-services_lib
+
+JAVA_SRC=$(JAVA_SRC_DIR)/*.java
+
+DRAWABLES=\
+ $(DRAWABLE_DIR)/redled.png \
+ $(DRAWABLE_DIR)/greenled.png \
+ $(DRAWABLE_DIR)/grayled.png
+
+SRC=$(JAVA_SRC) $(DRAWABLES)
all: $(all_target)
-$(ALTOSLIB): $(ALTOSLIB_SRCDIR)/$(ALTOSLIB_JAR)
+$(EXT_LIBDIR):
mkdir -p $(EXT_LIBDIR)
- cd $(EXT_LIBDIR) && ln -s $(shell echo $(EXT_LIBDIR) | sed 's|[^/]\+|..|g')/$(ALTOSLIB_SRCDIR)/$(ALTOSLIB_JAR) .
+
+$(ALTOSLIB): $(EXT_LIBDIR) $(ALTOSLIB_SRCDIR)/$(ALTOSLIB_JAR)
+ cd $(EXT_LIBDIR) && ln -sf $(shell echo $(EXT_LIBDIR) | sed 's|[^/]\+|..|g')/$(ALTOSLIB_SRCDIR)/$(ALTOSLIB_JAR) .
+
+$(SUPPORT_V4): $(EXT_LIBDIR) $(SUPPORT_V4_SRCDIR)/$(SUPPORT_V4_JAR)
+ cd $(EXT_LIBDIR) && ln -sf $(SUPPORT_V4_SRCDIR)/$(SUPPORT_V4_JAR) .
+
+$(GOOGLE_PLAY_SERVICES_LIB): $(GOOGLE_PLAY_SERVICES_LIB_SRCDIR)/$(GOOGLE_PLAY_SERVICES_LIB)
+ cp -a $(GOOGLE_PLAY_SERVICES_LIB_SRCDIR)/$(GOOGLE_PLAY_SERVICES_LIB) .
+ cd $(GOOGLE_PLAY_SERVICES_LIB) && $(SDK)/tools/android update project --target $(SDK_TARGET) --path .
+
+$(JAVA_SRC_DIR)/BuildInfo.java: $(JAVA_SRC)
+ ./buildinfo.sh
+
+$(DRAWABLE_DIR)/%.png: ../icon/%.png
+ cd $(DRAWABLE_DIR) && ln -sf $(shell echo $(DRAWABLE_DIR) | sed 's|[^/]\+|..|g')/$< .
if ANDROID
install-release: bin/AltosDroid-release.apk
@@ -42,13 +66,30 @@ install-release: bin/AltosDroid-release.apk
install-debug: bin/AltosDroid-debug.apk
$(ADB) install -r bin/AltosDroid-debug.apk
-bin/AltosDroid-debug.apk: $(SRC) $(ALTOSLIB)
+bin/AltosDroid-debug.apk: $(SRC) $(ALTOSLIB) $(SUPPORT_V4) $(GOOGLE_PLAY_SERVICES_LIB)
ant debug
-bin/AltosDroid-release.apk: $(SRC) $(ALTOSLIB)
+bin/AltosDroid-release-unsigned.apk: $(SRC) $(ALTOSLIB) $(SUPPORT_V4) $(GOOGLE_PLAY_SERVICES_LIB)
ant release
-endif
-clean:
- $(clean_command)
+release: bin/AltosDroid-release-unsigned.apk
+ jarsigner -keystore release.keystore \
+ -signedjar bin/AltosDroid-release-signed.apk \
+ bin/AltosDroid-release-unsigned.apk AltosDroid
+ $(ZIPALIGN) -f 4 \
+ bin/AltosDroid-release-signed.apk \
+ bin/AltosDroid-release.apk
+
+clean-local: $(GOOGLE_PLAY_SERVICES_LIB)
+ ant clean
+ rm -rf $(EXT_LIBDIR)
+ rm -f $(DRAWABLES)
+ rm -rf $(GOOGLE_PLAY_SERVICES_LIB)
+
+else
+
+clean-local:
+
+endif
+clean: clean-local
diff --git a/altosdroid/Notebook b/altosdroid/Notebook
new file mode 100644
index 00000000..b4ae2b7f
--- /dev/null
+++ b/altosdroid/Notebook
@@ -0,0 +1,30 @@
+Desired AltosDroid feature list
+
+ *) GPS satellite status tab. Monitor GPS C/N0 numbers and
+ SVIDs. Provides more info before GPS lock is acquired.
+
+ *) Channel scanning. Provide the ability to search for telemetry
+ signals like AltosUI does.
+
+ *) Highlight current frequency in the frequency list.
+
+ *) Random frequency selection. Provide some mechanism to input
+ arbitrary radio frequencies. Could be like AltosUI which allows
+ you to edit the list of frequencies and assign names to them,
+ or perhaps something better.
+
+ *) TM configuration from the droid
+
+ *) Monitor-idle mode
+
+ *) Frequency scanning
+
+ *) Select satellite imaging mode
+
+ *) Remember most-recently-used TBT and frequency, perhaps
+ auto-connect at startup.
+
+ *) Re-loading flight data from .telem file to get back to
+ 'find my rocket' mode after shutting down the application.
+
+ *) Imperial Units mode
diff --git a/altosdroid/buildinfo.sh b/altosdroid/buildinfo.sh
new file mode 100755
index 00000000..ac97b7bd
--- /dev/null
+++ b/altosdroid/buildinfo.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# Author: Mike Beattie <mike@ethernal.org>
+#
+# Script to parse result from git describe, and push values into
+# BuildInfo.java for use within altosdroid (to display the current
+# version and build information, primarily).
+#
+
+infile=src/org/altusmetrum/AltosDroid/BuildInfo.java.in
+outfile=src/org/altusmetrum/AltosDroid/BuildInfo.java
+
+. ../src/Version
+version=$VERSION
+branch=''
+commitnum=''
+commithash=''
+builddate=$(date "+%Y-%m-%d")
+buildtime=$(date "+%H:%M")
+buildtz=$(date "+%z")
+
+
+describe=$(git describe --match "$version" --long --always 2>/dev/null || echo '')
+if [ -n "$describe" ]; then
+ branch=$(git branch | sed -ne 's/^\* //p')
+ commitdetails=$(echo $describe | sed -e "s/^$version-//")
+ commitnum=$(echo $commitdetails | cut -s -d- -f1)
+ commithash=$(echo $commitdetails | cut -d- -f2)
+fi
+
+
+echo "Version $describe, built on $builddate $buildtime $buildtz"
+
+sed -e "s/@VERSION@/$version/" \
+ -e "s/@DESCRIBE@/$describe/" \
+ -e "s/@BRANCH@/$branch/" \
+ -e "s/@COMMITNUM@/$commitnum/" \
+ -e "s/@COMMITHASH@/$commithash/" \
+ -e "s/@BUILDDATE@/$builddate/" \
+ -e "s/@BUILDTIME@/$buildtime/" \
+ -e "s/@BUILDTZ@/$buildtz/" \
+ $infile > $outfile
diff --git a/altosdroid/libs/.gitignore b/altosdroid/libs/.gitignore
deleted file mode 100644
index b4e68f63..00000000
--- a/altosdroid/libs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-AltosLib.jar
diff --git a/altosdroid/project.properties b/altosdroid/project.properties
index 0a80e644..96b9551c 100644
--- a/altosdroid/project.properties
+++ b/altosdroid/project.properties
@@ -8,4 +8,5 @@
# project structure.
# Project target.
-target=Google Inc.:Google APIs:10
+target=android-10
+android.library.reference.1=google-play-services_lib/
diff --git a/altosdroid/release.keystore b/altosdroid/release.keystore
new file mode 100644
index 00000000..53607dcb
--- /dev/null
+++ b/altosdroid/release.keystore
Binary files differ
diff --git a/altosdroid/res/drawable/pad.png b/altosdroid/res/drawable/pad.png
new file mode 100644
index 00000000..b2e65c8a
--- /dev/null
+++ b/altosdroid/res/drawable/pad.png
Binary files differ
diff --git a/altosdroid/res/drawable/rocket.png b/altosdroid/res/drawable/rocket.png
new file mode 100644
index 00000000..7e62f6c4
--- /dev/null
+++ b/altosdroid/res/drawable/rocket.png
Binary files differ
diff --git a/altosdroid/res/layout/altosdroid.xml b/altosdroid/res/layout/altosdroid.xml
index f185ea9f..71b7ad05 100644
--- a/altosdroid/res/layout/altosdroid.xml
+++ b/altosdroid/res/layout/altosdroid.xml
@@ -1,349 +1,196 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
+<!--
+ Copyright © 2012-2013 Mike Beattie <mike@ethernal.org>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
- http://www.apache.org/licenses/LICENSE-2.0
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-->
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0" >
-
- <RelativeLayout
- android:id="@+id/strut"
- android:layout_width="10dip"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true" >
-
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/callsign_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@+id/strut" >
-
- <TextView
- android:id="@+id/callsign_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/callsign_label" />
-
- <TextView
- android:id="@+id/callsign_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/callsign_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/rssi_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/strut"
- android:layout_alignParentRight="true" >
-
- <TextView
- android:id="@+id/rssi_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/rssi_label" />
-
- <TextView
- android:id="@+id/rssi_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/rssi_label"
- android:textAppearance="?android:attr/textAppearanceLarge" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/serial_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/callsign_container"
- android:layout_toLeftOf="@+id/strut" >
-
- <TextView
- android:id="@+id/serial_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/serial_label" />
-
- <TextView
- android:id="@+id/serial_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/serial_label"
- android:textAppearance="?android:attr/textAppearanceLarge" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/flight_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/callsign_container"
- android:layout_toRightOf="@+id/strut"
- android:layout_alignParentRight="true" >
-
- <TextView
- android:id="@+id/flight_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/flight_label" />
-
- <TextView
- android:id="@+id/flight_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/flight_label"
- android:textAppearance="?android:attr/textAppearanceLarge" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/state_container"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@+id/serial_container" >
-
- <TextView
- android:id="@+id/state_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/state_label" />
-
- <TextView
- android:id="@+id/state_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/state_label"
- android:layout_centerInParent="true"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textSize="50dip" />
-
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/speed_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_below="@+id/state_container"
- android:layout_toLeftOf="@+id/strut" >
-
- <TextView
- android:id="@+id/speed_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/speed_label" />
-
- <TextView
- android:id="@+id/speed_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/speed_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/accel_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/state_container"
- android:layout_toRightOf="@+id/strut" >
-
- <TextView
- android:id="@+id/accel_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/accel_label" />
-
- <TextView
- android:id="@+id/accel_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/accel_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/range_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_below="@+id/speed_container"
- android:layout_toLeftOf="@+id/strut" >
-
- <TextView
- android:id="@+id/range_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/range_label" />
-
- <TextView
- android:id="@+id/range_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/range_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/height_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/speed_container"
- android:layout_toRightOf="@id/strut" >
-
- <TextView
- android:id="@+id/height_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/height_label" />
-
- <TextView
- android:id="@+id/height_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/height_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/elevation_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_below="@id/range_container"
- android:layout_toLeftOf="@id/strut" >
-
- <TextView
- android:id="@+id/elevation_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/elevation_label" />
-
- <TextView
- android:id="@+id/elevation_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/elevation_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/bearing_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/range_container"
- android:layout_toRightOf="@+id/strut" >
-
- <TextView
- android:id="@+id/bearing_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/bearing_label" />
-
- <TextView
- android:id="@+id/bearing_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/bearing_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/latitude_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/elevation_container" >
-
- <TextView
- android:id="@+id/latitude_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/latitude_label" />
-
- <TextView
- android:id="@+id/latitude_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/latitude_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/longitude_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/latitude_container" >
-
- <TextView
- android:id="@+id/longitude_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/longitude_label" />
-
- <TextView
- android:id="@+id/longitude_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/longitude_label"
- android:text=""
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- </RelativeLayout>
-
-
- <TextView
- android:id="@+id/text"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_alignParentBottom="true"
- android:layout_below="@+id/longitude_container"
- android:gravity="bottom"
- android:scrollbars="vertical"
- android:textSize="7dp"
- android:typeface="monospace" />
-
- </RelativeLayout>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:id="@+id/callsign_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/callsign_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/callsign_label" />
+
+ <TextView
+ android:id="@+id/callsign_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/callsign_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/serial_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/serial_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/serial_label" />
+
+ <TextView
+ android:id="@+id/serial_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/serial_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/flight_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/flight_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/flight_label" />
+
+ <TextView
+ android:id="@+id/flight_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/flight_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/state_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/state_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/state_label" />
+
+ <TextView
+ android:id="@+id/state_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/state_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/rssi_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/rssi_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/rssi_label" />
+
+ <TextView
+ android:id="@+id/rssi_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/rssi_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/age_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/age_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/age_label" />
+
+ <TextView
+ android:id="@+id/age_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/age_label"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <TabHost
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/tabhost"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:orientation="horizontal" />
+
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="0" />
+
+ <org.altusmetrum.AltosDroid.AltosViewPager
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+ </LinearLayout>
+ </TabHost>
+
+ <TextView
+ android:id="@+id/version"
+ android:layout_width="fill_parent"
+ android:layout_height="10dip"
+ android:layout_weight="0"
+ android:gravity="bottom|right"
+ android:textSize="7sp"
+ android:typeface="monospace" />
+
+</LinearLayout>
diff --git a/altosdroid/res/layout/main.xml b/altosdroid/res/layout/main.xml
deleted file mode 100644
index 00ca63c8..00000000
--- a/altosdroid/res/layout/main.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
-
- <TextView
- android:id="@+id/in"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:gravity="bottom"
- android:scrollbars="vertical"
- android:textSize="7dp"
- android:typeface="monospace" />
-
-</LinearLayout>
diff --git a/altosdroid/res/layout/message.xml b/altosdroid/res/layout/message.xml
deleted file mode 100644
index 8fa358c9..00000000
--- a/altosdroid/res/layout/message.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:padding="5dp"
-/> \ No newline at end of file
diff --git a/altosdroid/res/layout/tab_ascent.xml b/altosdroid/res/layout/tab_ascent.xml
new file mode 100644
index 00000000..b21ec426
--- /dev/null
+++ b/altosdroid/res/layout/tab_ascent.xml
@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2013 Mike Beattie <mike@ethernal.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingTop="5dp" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/height_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/height_label" />
+
+ <TextView
+ android:id="@+id/height_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/height_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/max_height_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_height_label" />
+
+ <TextView
+ android:id="@+id/max_height_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_height_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingTop="5dp" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/speed_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/speed_label" />
+
+ <TextView
+ android:id="@+id/speed_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/speed_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/max_speed_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_speed_label" />
+
+ <TextView
+ android:id="@+id/max_speed_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_speed_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingTop="5dp" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/accel_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/accel_label" />
+
+ <TextView
+ android:id="@+id/accel_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/accel_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/max_accel_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_accel_label" />
+
+ <TextView
+ android:id="@+id/max_accel_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_accel_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/latitude_label" />
+
+ <TextView
+ android:id="@+id/lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/longitude_label" />
+
+ <TextView
+ android:id="@+id/lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/apogee_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/apogee_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/apogee_redled"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/apogee_greenled"
+ android:text="@string/apogee_voltage_label" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/apogee_voltage_label"
+ android:layout_toRightOf="@id/apogee_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/main_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/main_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/main_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/main_redled"
+ android:contentDescription="@string/main_voltage_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/main_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/main_greenled"
+ android:text="@string/main_voltage_label" />
+
+ <TextView
+ android:id="@+id/main_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/main_voltage_label"
+ android:layout_toRightOf="@id/main_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/altosdroid/res/layout/tab_descent.xml b/altosdroid/res/layout/tab_descent.xml
new file mode 100644
index 00000000..9e1fc820
--- /dev/null
+++ b/altosdroid/res/layout/tab_descent.xml
@@ -0,0 +1,339 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2013 Mike Beattie <mike@ethernal.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/speed_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/speed_label" />
+
+ <TextView
+ android:id="@+id/speed_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/speed_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/height_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/height_label" />
+
+ <TextView
+ android:id="@+id/height_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/height_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingTop="5dp" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/elevation_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/elevation_label" />
+
+ <TextView
+ android:id="@+id/elevation_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/elevation_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/range_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/range_label" />
+
+ <TextView
+ android:id="@+id/range_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/range_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingTop="5dp" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/bearing_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bearing_label" />
+
+ <TextView
+ android:id="@+id/bearing_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/bearing_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/compass_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="" />
+
+ <TextView
+ android:id="@+id/compass_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/compass_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:baselineAligned="true"
+ android:orientation="horizontal"
+ android:paddingTop="5dp" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+
+ <TextView
+ android:id="@+id/distance_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/gnd_distance_label" />
+
+ <TextView
+ android:id="@+id/distance_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/distance_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" >
+ </TextView>
+
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/latitude_label" />
+
+ <TextView
+ android:id="@+id/lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/longitude_label" />
+
+ <TextView
+ android:id="@+id/lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/apogee_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/apogee_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/apogee_redled"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/apogee_greenled"
+ android:text="@string/apogee_voltage_label" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/apogee_voltage_label"
+ android:layout_toRightOf="@id/apogee_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/main_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/main_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/main_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/main_redled"
+ android:contentDescription="@string/main_voltage_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/main_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/main_greenled"
+ android:text="@string/main_voltage_label" />
+
+ <TextView
+ android:id="@+id/main_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/main_voltage_label"
+ android:layout_toRightOf="@id/main_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/altosdroid/res/layout/tab_landed.xml b/altosdroid/res/layout/tab_landed.xml
new file mode 100644
index 00000000..f27baa9e
--- /dev/null
+++ b/altosdroid/res/layout/tab_landed.xml
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2013 Mike Beattie <mike@ethernal.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:id="@+id/bearing_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bearing_label" />
+
+ <TextView
+ android:id="@+id/bearing_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/bearing_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/distance_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/distance_label" />
+
+ <TextView
+ android:id="@+id/distance_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/distance_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/target_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/target_latitude_label" />
+
+ <TextView
+ android:id="@+id/target_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/target_lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/target_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/target_longitude_label" />
+
+ <TextView
+ android:id="@+id/target_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/target_lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/receiver_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/receiver_latitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/receiver_lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/receiver_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/receiver_longitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/receiver_lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/max_height_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_height_label" />
+
+ <TextView
+ android:id="@+id/max_height_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_height_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/max_speed_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_speed_label" />
+
+ <TextView
+ android:id="@+id/max_speed_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_speed_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/max_accel_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/max_accel_label" />
+
+ <TextView
+ android:id="@+id/max_accel_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/max_accel_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/altosdroid/res/layout/tab_map.xml b/altosdroid/res/layout/tab_map.xml
new file mode 100644
index 00000000..f611ae48
--- /dev/null
+++ b/altosdroid/res/layout/tab_map.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2013 Mike Beattie <mike@ethernal.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:id="@+id/map"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/distance_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/distance_label" />
+
+ <TextView
+ android:id="@+id/distance_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/distance_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/bearing_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/bearing_label" />
+
+ <TextView
+ android:id="@+id/bearing_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/bearing_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/target_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/target_latitude_label" />
+
+ <TextView
+ android:id="@+id/target_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/target_lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/target_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/target_longitude_label" />
+
+ <TextView
+ android:id="@+id/target_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/target_lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="true"
+ android:orientation="horizontal" >
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/receiver_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/receiver_latitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/receiver_lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="5dp" >
+
+ <TextView
+ android:id="@+id/receiver_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="4dp"
+ android:text="@string/receiver_longitude_label" />
+
+ <TextView
+ android:id="@+id/receiver_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/receiver_lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/altosdroid/res/layout/tab_pad.xml b/altosdroid/res/layout/tab_pad.xml
new file mode 100644
index 00000000..38e61f83
--- /dev/null
+++ b/altosdroid/res/layout/tab_pad.xml
@@ -0,0 +1,320 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright © 2013 Mike Beattie <mike@ethernal.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:orientation="vertical" >
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/battery_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/battery_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/battery_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/battery_redled"
+ android:contentDescription="@string/battery_voltage_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/battery_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/battery_greenled"
+ android:text="@string/battery_voltage_label" />
+
+ <TextView
+ android:id="@+id/battery_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/battery_voltage_label"
+ android:layout_toRightOf="@id/battery_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/apogee_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/apogee_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/apogee_redled"
+ android:contentDescription="@string/apogee_voltage_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/apogee_greenled"
+ android:text="@string/apogee_voltage_label" />
+
+ <TextView
+ android:id="@+id/apogee_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/apogee_voltage_label"
+ android:layout_toRightOf="@id/apogee_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/main_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/main_voltage_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/main_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/main_redled"
+ android:contentDescription="@string/main_voltage_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/main_voltage_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/main_greenled"
+ android:text="@string/main_voltage_label" />
+
+ <TextView
+ android:id="@+id/main_voltage_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/main_voltage_label"
+ android:layout_toRightOf="@id/main_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/logging_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/logging_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/logging_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/logging_redled"
+ android:contentDescription="@string/logging_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/logging_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/logging_greenled"
+ android:text="@string/logging_label" />
+
+ <TextView
+ android:id="@+id/logging_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/logging_label"
+ android:layout_toRightOf="@id/logging_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/gps_locked_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/gps_locked_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/gps_locked_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/gps_locked_redled"
+ android:contentDescription="@string/gps_locked_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/gps_locked_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/gps_locked_greenled"
+ android:text="@string/gps_locked_label" />
+
+ <TextView
+ android:id="@+id/gps_locked_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/gps_locked_label"
+ android:layout_toRightOf="@id/gps_locked_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dp" >
+
+ <ImageView
+ android:id="@+id/gps_ready_redled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/gps_ready_label"
+ android:src="@drawable/grayled" />
+
+ <ImageView
+ android:id="@+id/gps_ready_greenled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/gps_ready_redled"
+ android:contentDescription="@string/gps_ready_label"
+ android:paddingRight="5dp"
+ android:src="@drawable/grayled" />
+
+ <TextView
+ android:id="@+id/gps_ready_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/gps_ready_greenled"
+ android:text="@string/gps_ready_label" />
+
+ <TextView
+ android:id="@+id/gps_ready_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/gps_ready_label"
+ android:layout_toRightOf="@id/gps_ready_greenled"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="69dp">
+
+ <TextView
+ android:id="@+id/pad_lat_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:width="100sp"
+ android:paddingRight="10sp"
+ android:layout_toRightOf="@id/gps_ready_greenled"
+ android:text="@string/pad_lat_label" />
+
+ <TextView
+ android:id="@+id/pad_lat_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/pad_lat_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="69dp">
+
+ <TextView
+ android:id="@+id/pad_lon_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:width="100sp"
+ android:paddingRight="10sp"
+ android:layout_toRightOf="@id/gps_ready_greenled"
+ android:text="@string/pad_lon_label" />
+
+ <TextView
+ android:id="@+id/pad_lon_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/pad_lon_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="69dp">
+
+ <TextView
+ android:id="@+id/pad_alt_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:width="100sp"
+ android:paddingRight="10sp"
+ android:layout_toRightOf="@id/gps_ready_greenled"
+ android:text="@string/pad_alt_label" />
+
+ <TextView
+ android:id="@+id/pad_alt_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/pad_alt_label"
+ android:text=""
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+ </RelativeLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/altosdroid/res/values/strings.xml b/altosdroid/res/values/strings.xml
index 1b28284a..90da617b 100644
--- a/altosdroid/res/values/strings.xml
+++ b/altosdroid/res/values/strings.xml
@@ -1,60 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
+<!--
+ Copyright © 2012-2013 Mike Beattie <mike@ethernal.org>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
- http://www.apache.org/licenses/LICENSE-2.0
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-->
-
<resources>
- <string name="app_name">AltosDroid</string>
- <!-- AltosDroid -->
- <string name="bt_not_enabled">Bluetooth was not enabled.</string>
- <string name="title_connecting">connecting…</string>
- <string name="title_connected_to">connected: </string>
- <string name="title_not_connected">not connected</string>
+ <string name="app_name">AltosDroid</string>
- <!-- Options Menu -->
- <string name="connect_device">Connect a device</string>
- <string name="select_freq">Select radio frequency</string>
+ <!-- AltosDroid -->
+ <string name="bt_not_enabled">Bluetooth was not enabled.</string>
+ <string name="title_connecting">connecting…</string>
+ <string name="title_connected_to">connected: </string>
+ <string name="title_not_connected">not connected</string>
- <!-- DeviceListActivity -->
- <string name="scanning">scanning for devices…</string>
- <string name="select_device">select a device to connect</string>
- <string name="none_paired">No devices have been paired</string>
- <string name="none_found">No devices found</string>
- <string name="title_paired_devices">Paired Devices</string>
- <string name="title_other_devices">Other Available Devices</string>
- <string name="button_scan">Scan for devices</string>
+ <!-- Options Menu -->
+ <string name="connect_device">Connect a device</string>
+ <string name="select_freq">Select radio frequency</string>
- <!-- Service -->
- <string name="telemetry_service_label">AltosDroid Telemetry Service</string>
- <string name="telemetry_service_started">Telemetry Service Started</string>
- <string name="telemetry_service_stopped">Telemetry Service Stopped</string>
+ <!-- DeviceListActivity -->
+ <string name="scanning">scanning for devices…</string>
+ <string name="select_device">select a device to connect</string>
+ <string name="none_paired">No devices have been paired</string>
+ <string name="none_found">No devices found</string>
+ <string name="title_paired_devices">Paired Devices</string>
+ <string name="title_other_devices">Other Available Devices</string>
+ <string name="button_scan">Scan for devices</string>
+ <!-- Service -->
+ <string name="telemetry_service_label">AltosDroid Telemetry Service</string>
+ <string name="telemetry_service_started">Telemetry Service Started</string>
+ <string name="telemetry_service_stopped">Telemetry Service Stopped</string>
<!-- UI fields -->
- <string name="callsign_label">Callsign</string>
- <string name="serial_label">Serial no.</string>
- <string name="flight_label">Flight no.</string>
- <string name="rssi_label">RSSI</string>
- <string name="state_label">State</string>
- <string name="speed_label">Speed</string>
- <string name="accel_label">Acceleration</string>
- <string name="range_label">Range</string>
- <string name="height_label">Height</string>
- <string name="elevation_label">Elevation</string>
- <string name="bearing_label">Bearing</string>
- <string name="latitude_label">Latitude</string>
- <string name="longitude_label">Longitude</string>
+ <!-- Header -->
+ <string name="callsign_label">Callsign</string>
+ <string name="serial_label">Serial</string>
+ <string name="flight_label">Flight</string>
+ <string name="state_label">State</string>
+ <string name="rssi_label">RSSI</string>
+ <string name="age_label">Age</string>
+
+ <!-- Tab fields -->
+ <string name="height_label">Height</string>
+ <string name="speed_label">Speed</string>
+ <string name="accel_label">Acceleration</string>
+ <string name="bearing_label">Bearing</string>
+ <string name="elevation_label">Elevation</string>
+ <string name="range_label">Range</string>
+ <string name="distance_label">Distance</string>
+ <string name="gnd_distance_label">Ground Distance</string>
+ <string name="max_height_label">Max Height</string>
+ <string name="max_speed_label">Max Speed</string>
+ <string name="max_accel_label">Max Accel</string>
+ <string name="battery_voltage_label">Battery Voltage</string>
+ <string name="apogee_voltage_label">Apogee Igniter Voltage</string>
+ <string name="main_voltage_label">Main Igniter Voltage</string>
+ <string name="logging_label">On-board Data Logging</string>
+ <string name="gps_locked_label">GPS Locked</string>
+ <string name="gps_ready_label">GPS Ready</string>
+ <string name="latitude_label">Latitude</string>
+ <string name="longitude_label">Longitude</string>
+ <string name="target_latitude_label">Tar Lat</string>
+ <string name="target_longitude_label">Tar Lon</string>
+ <string name="receiver_latitude_label">My Lat</string>
+ <string name="receiver_longitude_label">My Lon</string>
+ <string name="pad_lat_label">Pad Lat</string>
+ <string name="pad_lon_label">Pad Lon</string>
+ <string name="pad_alt_label">Pad Alt</string>
</resources>
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java
index 9fcc4eba..0aea06f1 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java
@@ -31,7 +31,7 @@ import android.os.Handler;
//import android.os.Message;
import android.util.Log;
-import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altoslib_1.*;
public class AltosBluetooth extends AltosLink {
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
index 00689684..e10982f7 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
@@ -1,5 +1,5 @@
/*
- * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ * Copyright © 2012-2013 Mike Beattie <mike@ethernal.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,6 +18,9 @@
package org.altusmetrum.AltosDroid;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Timer;
+import java.util.TimerTask;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
@@ -33,22 +36,22 @@ import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.text.method.ScrollingMovementMethod;
+import android.support.v4.app.FragmentActivity;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Window;
+import android.widget.TabHost;
import android.widget.TextView;
import android.widget.Toast;
import android.app.AlertDialog;
+import android.location.Location;
-import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altoslib_1.*;
-/**
- * This is the main Activity that displays the current chat session.
- */
-public class AltosDroid extends Activity {
+public class AltosDroid extends FragmentActivity {
// Debugging
private static final String TAG = "AltosDroid";
private static final boolean D = true;
@@ -56,6 +59,9 @@ public class AltosDroid extends Activity {
// Message types received by our Handler
public static final int MSG_STATE_CHANGE = 1;
public static final int MSG_TELEMETRY = 2;
+ public static final int MSG_UPDATE_AGE = 3;
+ public static final int MSG_LOCATION = 4;
+ public static final int MSG_CRC_ERROR = 5;
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
@@ -70,23 +76,31 @@ public class AltosDroid extends Activity {
private TextView mSerialView;
private TextView mFlightView;
private TextView mStateView;
- private TextView mSpeedView;
- private TextView mAccelView;
- private TextView mRangeView;
- private TextView mHeightView;
- private TextView mElevationView;
- private TextView mBearingView;
- private TextView mLatitudeView;
- private TextView mLongitudeView;
-
- // Generic field for extras at the bottom
- private TextView mTextView;
+ private TextView mAgeView;
+
+ // field to display the version at the bottom of the screen
+ private TextView mVersion;
+
+ // Tabs
+ TabHost mTabHost;
+ AltosViewPager mViewPager;
+ TabsAdapter mTabsAdapter;
+ ArrayList<AltosDroidTab> mTabs = new ArrayList<AltosDroidTab>();
+ int tabHeight;
+
+ // Timer and Saved flight state for Age calculation
+ private Timer timer = new Timer();
+ AltosState saved_state;
+ Location saved_location;
// Service
private boolean mIsBound = false;
private Messenger mService = null;
final Messenger mMessenger = new Messenger(new IncomingHandler(this));
+ // Preferences
+ private AltosDroidPreferences prefs = null;
+
// TeleBT Config data
private AltosConfigData mConfigData = null;
// Local Bluetooth adapter
@@ -113,9 +127,6 @@ public class AltosDroid extends Activity {
ad.mTitle.setText(R.string.title_connected_to);
ad.mTitle.append(str);
Toast.makeText(ad.getApplicationContext(), "Connected to " + str, Toast.LENGTH_SHORT).show();
- ad.mAltosVoice.speak("Connected");
- //TEST!
- ad.mTextView.setText(Dumper.dump(ad.mConfigData));
break;
case TelemetryService.STATE_CONNECTING:
ad.mTitle.setText(R.string.title_connecting);
@@ -124,14 +135,20 @@ public class AltosDroid extends Activity {
case TelemetryService.STATE_NONE:
ad.mConfigData = null;
ad.mTitle.setText(R.string.title_not_connected);
- ad.mTextView.setText("");
break;
}
break;
case MSG_TELEMETRY:
ad.update_ui((AltosState) msg.obj);
- // TEST!
- ad.mTextView.setText(Dumper.dump(msg.obj));
+ break;
+ case MSG_LOCATION:
+ ad.set_location((Location) msg.obj);
+ break;
+ case MSG_CRC_ERROR:
+ case MSG_UPDATE_AGE:
+ if (ad.saved_state != null) {
+ ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.report_time + 500) / 1000));
+ }
break;
}
}
@@ -156,7 +173,6 @@ public class AltosDroid extends Activity {
}
};
-
void doBindService() {
bindService(new Intent(this, TelemetryService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
@@ -180,37 +196,97 @@ public class AltosDroid extends Activity {
}
}
+ public void registerTab(AltosDroidTab mTab) {
+ mTabs.add(mTab);
+ }
+
+ public void unregisterTab(AltosDroidTab mTab) {
+ mTabs.remove(mTab);
+ }
+
+ void set_location(Location location) {
+ saved_location = location;
+ update_ui(saved_state);
+ }
+
void update_ui(AltosState state) {
- mCallsignView.setText(state.data.callsign);
- mRSSIView.setText(String.format("%d", state.data.rssi));
- mSerialView.setText(String.format("%d", state.data.serial));
- mFlightView.setText(String.format("%d", state.data.flight));
- mStateView.setText(state.data.state());
- double speed = state.speed;
- if (!state.ascent)
- speed = state.baro_speed;
- mSpeedView.setText(String.format("%6.0f m/s", speed));
- mAccelView.setText(String.format("%6.0f m/s²", state.acceleration));
- mRangeView.setText(String.format("%6.0f m", state.range));
- mHeightView.setText(String.format("%6.0f m", state.height));
- mElevationView.setText(String.format("%3.0f°", state.elevation));
- if (state.from_pad != null)
- mBearingView.setText(String.format("%3.0f°", state.from_pad.bearing));
- mLatitudeView.setText(pos(state.gps.lat, "N", "S"));
- mLongitudeView.setText(pos(state.gps.lon, "W", "E"));
-
- mAltosVoice.tell(state);
+ if (state != null && saved_state != null) {
+ if (saved_state.state != state.state) {
+ String currentTab = mTabHost.getCurrentTabTag();
+ switch (state.state) {
+ case AltosLib.ao_flight_boost:
+ if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("ascent");
+ break;
+ case AltosLib.ao_flight_drogue:
+ if (currentTab.equals("ascent")) mTabHost.setCurrentTabByTag("descent");
+ break;
+ case AltosLib.ao_flight_landed:
+ if (currentTab.equals("descent")) mTabHost.setCurrentTabByTag("landed");
+ break;
+ }
+ }
+ }
+ saved_state = state;
+
+ AltosGreatCircle from_receiver = null;
+
+ if (state != null && saved_location != null && state.gps != null && state.gps.locked) {
+ double altitude = 0;
+ if (saved_location.hasAltitude())
+ altitude = saved_location.getAltitude();
+ from_receiver = new AltosGreatCircle(saved_location.getLatitude(),
+ saved_location.getLongitude(),
+ altitude,
+ state.gps.lat,
+ state.gps.lon,
+ state.gps.alt);
+ }
+
+ if (state != null) {
+ mCallsignView.setText(state.data.callsign);
+ mSerialView.setText(String.format("%d", state.data.serial));
+ mFlightView.setText(String.format("%d", state.data.flight));
+ mStateView.setText(state.data.state());
+ mRSSIView.setText(String.format("%d", state.data.rssi));
+ }
+
+ for (AltosDroidTab mTab : mTabs)
+ mTab.update_ui(state, from_receiver, saved_location);
+
+ if (state != null)
+ mAltosVoice.tell(state);
+ }
+
+ private void onTimerTick() {
+ try {
+ mMessenger.send(Message.obtain(null, MSG_UPDATE_AGE));
+ } catch (RemoteException e) {
+ }
}
- String pos(double p, String pos, String neg) {
+ static String pos(double p, String pos, String neg) {
String h = pos;
+ if (p == AltosRecord.MISSING)
+ return "";
if (p < 0) {
h = neg;
p = -p;
}
int deg = (int) Math.floor(p);
double min = (p - Math.floor(p)) * 60.0;
- return String.format("%d° %9.6f\" %s", deg, min, h);
+ return String.format("%d°%9.4f\" %s", deg, min, h);
+ }
+
+ static String number(String format, double value) {
+ if (value == AltosRecord.MISSING)
+ return "";
+ return String.format(format, value);
+ }
+
+ static String integer(String format, int value) {
+ if (value == AltosRecord.MISSING)
+ return "";
+ return String.format(format, value);
}
@Override
@@ -228,36 +304,71 @@ public class AltosDroid extends Activity {
return;
}
+ // Initialise preferences
+ prefs = new AltosDroidPreferences(this);
+ AltosPreferences.init(prefs);
+
// Set up the window layout
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
- //setContentView(R.layout.main);
setContentView(R.layout.altosdroid);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
+ // Create the Tabs and ViewPager
+ mTabHost = (TabHost)findViewById(android.R.id.tabhost);
+ mTabHost.setup();
+
+ mViewPager = (AltosViewPager)findViewById(R.id.pager);
+ mViewPager.setOffscreenPageLimit(4);
+
+ mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
+
+ mTabsAdapter.addTab(mTabHost.newTabSpec("pad").setIndicator("Pad"), TabPad.class, null);
+ mTabsAdapter.addTab(mTabHost.newTabSpec("ascent").setIndicator("Ascent"), TabAscent.class, null);
+ mTabsAdapter.addTab(mTabHost.newTabSpec("descent").setIndicator("Descent"), TabDescent.class, null);
+ mTabsAdapter.addTab(mTabHost.newTabSpec("landed").setIndicator("Landed"), TabLanded.class, null);
+ mTabsAdapter.addTab(mTabHost.newTabSpec("map").setIndicator("Map"), TabMap.class, null);
+
+
+ // Scale the size of the Tab bar for different screen densities
+ // This probably won't be needed when we start supporting ICS+ tabs.
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ int density = metrics.densityDpi;
+
+ if (density==DisplayMetrics.DENSITY_XHIGH)
+ tabHeight = 65;
+ else if (density==DisplayMetrics.DENSITY_HIGH)
+ tabHeight = 45;
+ else if (density==DisplayMetrics.DENSITY_MEDIUM)
+ tabHeight = 35;
+ else if (density==DisplayMetrics.DENSITY_LOW)
+ tabHeight = 25;
+ else
+ tabHeight = 65;
+
+ for (int i = 0; i < 5; i++)
+ mTabHost.getTabWidget().getChildAt(i).getLayoutParams().height = tabHeight;
+
+
// Set up the custom title
mTitle = (TextView) findViewById(R.id.title_left_text);
mTitle.setText(R.string.app_name);
mTitle = (TextView) findViewById(R.id.title_right_text);
- // Set up the temporary Text View
- mTextView = (TextView) findViewById(R.id.text);
- mTextView.setMovementMethod(new ScrollingMovementMethod());
- mTextView.setClickable(false);
- mTextView.setLongClickable(false);
+ // Display the Version
+ mVersion = (TextView) findViewById(R.id.version);
+ mVersion.setText("Version: " + BuildInfo.version +
+ " Built: " + BuildInfo.builddate + " " + BuildInfo.buildtime + " " + BuildInfo.buildtz +
+ " (" + BuildInfo.branch + "-" + BuildInfo.commitnum + "-" + BuildInfo.commithash + ")");
mCallsignView = (TextView) findViewById(R.id.callsign_value);
mRSSIView = (TextView) findViewById(R.id.rssi_value);
mSerialView = (TextView) findViewById(R.id.serial_value);
mFlightView = (TextView) findViewById(R.id.flight_value);
mStateView = (TextView) findViewById(R.id.state_value);
- mSpeedView = (TextView) findViewById(R.id.speed_value);
- mAccelView = (TextView) findViewById(R.id.accel_value);
- mRangeView = (TextView) findViewById(R.id.range_value);
- mHeightView = (TextView) findViewById(R.id.height_value);
- mElevationView = (TextView) findViewById(R.id.elevation_value);
- mBearingView = (TextView) findViewById(R.id.bearing_value);
- mLatitudeView = (TextView) findViewById(R.id.latitude_value);
- mLongitudeView = (TextView) findViewById(R.id.longitude_value);
+ mAgeView = (TextView) findViewById(R.id.age_value);
+
+ timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 1000L, 100L);
mAltosVoice = new AltosVoice(this);
}
@@ -303,12 +414,9 @@ public class AltosDroid extends Activity {
super.onDestroy();
if(D) Log.e(TAG, "--- ON DESTROY ---");
- mAltosVoice.stop();
+ if (mAltosVoice != null) mAltosVoice.stop();
}
-
-
-
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(D) Log.d(TAG, "onActivityResult " + resultCode);
switch (requestCode) {
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java
new file mode 100644
index 00000000..fd4b0768
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.io.File;
+import java.util.Map;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Environment;
+
+import org.altusmetrum.altoslib_1.*;
+
+public class AltosDroidPreferences implements AltosPreferencesBackend {
+ public final static String NAME = "org.altusmetrum.AltosDroid";
+ private Context context = null;
+ private SharedPreferences prefs = null;
+ private SharedPreferences.Editor editor = null;
+
+ public AltosDroidPreferences(Context in_context) {
+ this(in_context, NAME);
+ }
+
+ public AltosDroidPreferences(Context in_context, String in_prefs) {
+ context = in_context;
+ prefs = context.getSharedPreferences(in_prefs, 0);
+ editor = prefs.edit();
+ }
+
+ public String[] keys() {
+ Map<String, ?> all = prefs.getAll();
+ return (String[])all.keySet().toArray();
+ }
+
+ public AltosPreferencesBackend node(String key) {
+ return new AltosDroidPreferences(context, key);
+ }
+
+ public boolean nodeExists(String key) {
+ return prefs.contains(key);
+ }
+
+ public boolean getBoolean(String key, boolean def) {
+ return prefs.getBoolean(key, def);
+ }
+
+ public double getDouble(String key, double def) {
+ Float f = Float.valueOf(prefs.getFloat(key, (float)def));
+ return f.doubleValue();
+ }
+
+ public int getInt(String key, int def) {
+ return prefs.getInt(key, def);
+ }
+
+ public String getString(String key, String def) {
+ return prefs.getString(key, def);
+ }
+
+ public void putBoolean(String key, boolean value) {
+ editor.putBoolean(key, value);
+ }
+
+ public void putDouble(String key, double value) {
+ editor.putFloat(key, (float)value);
+ }
+
+ public void putInt(String key, int value) {
+ editor.putInt(key, value);
+ }
+
+ public void putString(String key, String value) {
+ editor.putString(key, value);
+ }
+
+ public void remove(String key) {
+ editor.remove(key);
+ }
+
+ public void flush() {
+ editor.apply();
+ }
+
+ public File homeDirectory() {
+ return Environment.getExternalStorageDirectory();
+ }
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java
new file mode 100644
index 00000000..6ebb47f7
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright © 2013 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_1.*;
+import android.location.Location;
+
+public interface AltosDroidTab {
+ public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver);
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosViewPager.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosViewPager.java
new file mode 100644
index 00000000..ebddc266
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosViewPager.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2013 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.content.Context;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class AltosViewPager extends ViewPager {
+
+ public AltosViewPager(Context context) {
+ super(context);
+ }
+
+ public AltosViewPager(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
+ if(v.getClass().getPackage().getName().startsWith("maps.")){
+ return true;
+ }
+ return super.canScroll(v, checkV, dx, x, y);
+ }
+
+} \ No newline at end of file
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
index 3382d551..b3dba626 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
@@ -21,7 +21,7 @@ package org.altusmetrum.AltosDroid;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
-import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altoslib_1.*;
public class AltosVoice {
@@ -38,7 +38,6 @@ public class AltosVoice {
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) tts_enabled = true;
if (tts_enabled) {
- speak("AltosDroid ready");
idle_thread = new IdleThread();
}
}
@@ -67,7 +66,7 @@ public class AltosVoice {
speak(state.data.state());
if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&
state.state > AltosLib.ao_flight_boost) {
- speak(String.format("max speed: %d meters per second.", (int) (state.max_speed + 0.5)));
+ speak(String.format("max speed: %d meters per second.", (int) (state.max_speed() + 0.5)));
spoke = true;
} else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&
state.state >= AltosLib.ao_flight_drogue) {
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/BuildInfo.java.in b/altosdroid/src/org/altusmetrum/AltosDroid/BuildInfo.java.in
new file mode 100644
index 00000000..e9b3011a
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/BuildInfo.java.in
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+public class BuildInfo {
+ public static final String version = "@VERSION@";
+ public static final String git_describe = "@DESCRIBE@";
+ public static final String branch = "@BRANCH@";
+ public static final String commitnum = "@COMMITNUM@";
+ public static final String commithash = "@COMMITHASH@";
+ public static final String builddate = "@BUILDDATE@";
+ public static final String buildtime = "@BUILDTIME@";
+ public static final String buildtz = "@BUILDTZ@";
+}
+
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java b/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java
index 7b9cbde7..71692122 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java
@@ -109,9 +109,10 @@ public class DeviceListActivity extends Activity {
// If there are paired devices, add each one to the ArrayAdapter
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
- for (BluetoothDevice device : pairedDevices) {
- mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
- }
+ for (BluetoothDevice device : pairedDevices)
+ if (device.getName().startsWith("TeleBT"))
+ mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
+
} else {
String noDevices = getResources().getText(R.string.none_paired).toString();
mPairedDevicesArrayAdapter.add(noDevices);
@@ -185,7 +186,8 @@ public class DeviceListActivity extends Activity {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If it's already paired, skip it, because it's been listed already
- if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
+ if ( device.getBondState() != BluetoothDevice.BOND_BONDED
+ && device.getName().startsWith("TeleBT") ) {
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
// When discovery is finished, change the Activity title
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/GoNoGoLights.java b/altosdroid/src/org/altusmetrum/AltosDroid/GoNoGoLights.java
new file mode 100644
index 00000000..8e8d9c03
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/GoNoGoLights.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 2013 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.widget.ImageView;
+
+public class GoNoGoLights {
+ private Boolean state;
+ private Boolean missing;
+ private Boolean set;
+
+ private ImageView red;
+ private ImageView green;
+
+ private Drawable dRed;
+ private Drawable dGreen;
+ private Drawable dGray;
+
+ public GoNoGoLights(ImageView in_red, ImageView in_green, Resources r) {
+ red = in_red;
+ green = in_green;
+ state = false;
+ missing = true;
+ set = false;
+
+ dRed = r.getDrawable(R.drawable.redled);
+ dGreen = r.getDrawable(R.drawable.greenled);
+ dGray = r.getDrawable(R.drawable.grayled);
+ }
+
+ public void set(Boolean s, Boolean m) {
+ if (set && s == state && m == missing) return;
+ state = s;
+ missing = m;
+ set = true;
+ if (missing) {
+ red.setImageDrawable(dGray);
+ green.setImageDrawable(dGray);
+ } else if (state) {
+ red.setImageDrawable(dGray);
+ green.setImageDrawable(dGreen);
+ } else {
+ red.setImageDrawable(dRed);
+ green.setImageDrawable(dGray);
+ }
+ }
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
new file mode 100644
index 00000000..0e141ae4
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2013 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_1.*;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.location.Location;
+
+public class TabAscent extends Fragment implements AltosDroidTab {
+ AltosDroid mAltosDroid;
+
+ private TextView mHeightView;
+ private TextView mMaxHeightView;
+ private TextView mSpeedView;
+ private TextView mMaxSpeedView;
+ private TextView mAccelView;
+ private TextView mMaxAccelView;
+ private TextView mLatitudeView;
+ private TextView mLongitudeView;
+ private TextView mApogeeVoltageView;
+ private GoNoGoLights mApogeeLights;
+ private TextView mMainVoltageView;
+ private GoNoGoLights mMainLights;
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mAltosDroid = (AltosDroid) activity;
+ mAltosDroid.registerTab(this);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.tab_ascent, container, false);
+
+ mHeightView = (TextView) v.findViewById(R.id.height_value);
+ mMaxHeightView = (TextView) v.findViewById(R.id.max_height_value);
+ mSpeedView = (TextView) v.findViewById(R.id.speed_value);
+ mMaxSpeedView = (TextView) v.findViewById(R.id.max_speed_value);
+ mAccelView = (TextView) v.findViewById(R.id.accel_value);
+ mMaxAccelView = (TextView) v.findViewById(R.id.max_accel_value);
+ mLatitudeView = (TextView) v.findViewById(R.id.lat_value);
+ mLongitudeView = (TextView) v.findViewById(R.id.lon_value);
+
+ mApogeeVoltageView = (TextView) v.findViewById(R.id.apogee_voltage_value);
+ mApogeeLights = new GoNoGoLights((ImageView) v.findViewById(R.id.apogee_redled),
+ (ImageView) v.findViewById(R.id.apogee_greenled),
+ getResources());
+
+ mMainVoltageView = (TextView) v.findViewById(R.id.main_voltage_value);
+ mMainLights = new GoNoGoLights((ImageView) v.findViewById(R.id.main_redled),
+ (ImageView) v.findViewById(R.id.main_greenled),
+ getResources());
+
+ return v;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mAltosDroid.unregisterTab(this);
+ mAltosDroid = null;
+ }
+
+ public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ if (state != null) {
+ mHeightView.setText(AltosDroid.number("%6.0f m", state.height));
+ mMaxHeightView.setText(AltosDroid.number("%6.0f m", state.max_height));
+ mSpeedView.setText(AltosDroid.number("%6.0f m/s", state.speed()));
+ mMaxSpeedView.setText(AltosDroid.number("%6.0f m/s", state.max_speed()));
+ mAccelView.setText(AltosDroid.number("%6.0f m/s²", state.acceleration));
+ mMaxAccelView.setText(AltosDroid.number("%6.0f m/s²", state.max_acceleration));
+
+ if (state.gps != null) {
+ mLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
+ mLongitudeView.setText(AltosDroid.pos(state.gps.lon, "W", "E"));
+ } else {
+ mLatitudeView.setText("");
+ mLongitudeView.setText("");
+ }
+
+ mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.drogue_sense));
+ mApogeeLights.set(state.drogue_sense > 3.2, state.drogue_sense == AltosRecord.MISSING);
+
+ mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_sense));
+ mMainLights.set(state.main_sense > 3.2, state.main_sense == AltosRecord.MISSING);
+ }
+ }
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
new file mode 100644
index 00000000..09e7169b
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2013 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_1.*;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.location.Location;
+
+public class TabDescent extends Fragment implements AltosDroidTab {
+ AltosDroid mAltosDroid;
+
+ private TextView mSpeedView;
+ private TextView mHeightView;
+ private TextView mElevationView;
+ private TextView mRangeView;
+ private TextView mBearingView;
+ private TextView mCompassView;
+ private TextView mDistanceView;
+ private TextView mLatitudeView;
+ private TextView mLongitudeView;
+ private TextView mApogeeVoltageView;
+ private GoNoGoLights mApogeeLights;
+ private TextView mMainVoltageView;
+ private GoNoGoLights mMainLights;
+
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mAltosDroid = (AltosDroid) activity;
+ mAltosDroid.registerTab(this);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.tab_descent, container, false);
+
+ mSpeedView = (TextView) v.findViewById(R.id.speed_value);
+ mHeightView = (TextView) v.findViewById(R.id.height_value);
+ mElevationView = (TextView) v.findViewById(R.id.elevation_value);
+ mRangeView = (TextView) v.findViewById(R.id.range_value);
+ mBearingView = (TextView) v.findViewById(R.id.bearing_value);
+ mCompassView = (TextView) v.findViewById(R.id.compass_value);
+ mDistanceView = (TextView) v.findViewById(R.id.distance_value);
+ mLatitudeView = (TextView) v.findViewById(R.id.lat_value);
+ mLongitudeView = (TextView) v.findViewById(R.id.lon_value);
+
+ mApogeeVoltageView = (TextView) v.findViewById(R.id.apogee_voltage_value);
+ mApogeeLights = new GoNoGoLights((ImageView) v.findViewById(R.id.apogee_redled),
+ (ImageView) v.findViewById(R.id.apogee_greenled),
+ getResources());
+
+ mMainVoltageView = (TextView) v.findViewById(R.id.main_voltage_value);
+ mMainLights = new GoNoGoLights((ImageView) v.findViewById(R.id.main_redled),
+ (ImageView) v.findViewById(R.id.main_greenled),
+ getResources());
+
+ return v;
+ }
+
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mAltosDroid.unregisterTab(this);
+ mAltosDroid = null;
+ }
+
+ public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ if (state != null) {
+ mSpeedView.setText(AltosDroid.number("%6.0f m/s", state.speed()));
+ mHeightView.setText(AltosDroid.number("%6.0f m", state.height));
+ if (from_receiver != null) {
+ mElevationView.setText(AltosDroid.number("%3.0f°", from_receiver.elevation));
+ mRangeView.setText(AltosDroid.number("%6.0f m", from_receiver.range));
+ mBearingView.setText(AltosDroid.number("%3.0f°", from_receiver.bearing));
+ mCompassView.setText(from_receiver.bearing_words(AltosGreatCircle.BEARING_LONG));
+ mDistanceView.setText(AltosDroid.number("%6.0f m", from_receiver.distance));
+ } else {
+ mElevationView.setText("<unknown>");
+ mRangeView.setText("<unknown>");
+ mBearingView.setText("<unknown>");
+ mCompassView.setText("<unknown>");
+ mDistanceView.setText("<unknown>");
+ }
+ if (state.gps != null) {
+ mLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
+ mLongitudeView.setText(AltosDroid.pos(state.gps.lon, "W", "E"));
+ }
+
+ mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.drogue_sense));
+ mApogeeLights.set(state.drogue_sense > 3.2, state.drogue_sense == AltosRecord.MISSING);
+
+ mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_sense));
+ mMainLights.set(state.main_sense > 3.2, state.main_sense == AltosRecord.MISSING);
+ }
+ }
+
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java
new file mode 100644
index 00000000..f42b46b5
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 2013 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_1.*;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.location.Location;
+
+public class TabLanded extends Fragment implements AltosDroidTab {
+ AltosDroid mAltosDroid;
+
+ private TextView mBearingView;
+ private TextView mDistanceView;
+ private TextView mTargetLatitudeView;
+ private TextView mTargetLongitudeView;
+ private TextView mReceiverLatitudeView;
+ private TextView mReceiverLongitudeView;
+ private TextView mMaxHeightView;
+ private TextView mMaxSpeedView;
+ private TextView mMaxAccelView;
+
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mAltosDroid = (AltosDroid) activity;
+ mAltosDroid.registerTab(this);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.tab_landed, container, false);
+
+ mBearingView = (TextView) v.findViewById(R.id.bearing_value);
+ mDistanceView = (TextView) v.findViewById(R.id.distance_value);
+ mTargetLatitudeView = (TextView) v.findViewById(R.id.target_lat_value);
+ mTargetLongitudeView = (TextView) v.findViewById(R.id.target_lon_value);
+ mReceiverLatitudeView = (TextView) v.findViewById(R.id.receiver_lat_value);
+ mReceiverLongitudeView = (TextView) v.findViewById(R.id.receiver_lon_value);
+ mMaxHeightView = (TextView) v.findViewById(R.id.max_height_value);
+ mMaxSpeedView = (TextView) v.findViewById(R.id.max_speed_value);
+ mMaxAccelView = (TextView) v.findViewById(R.id.max_accel_value);
+
+ return v;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mAltosDroid.unregisterTab(this);
+ mAltosDroid = null;
+ }
+
+ public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ if (from_receiver != null) {
+ mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
+ mDistanceView.setText(String.format("%6.0f m", from_receiver.distance));
+ }
+ if (state != null && state.gps != null) {
+ mTargetLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
+ mTargetLongitudeView.setText(AltosDroid.pos(state.gps.lon, "W", "E"));
+ }
+
+ if (receiver != null) {
+ mReceiverLatitudeView.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
+ mReceiverLongitudeView.setText(AltosDroid.pos(receiver.getLongitude(), "W", "E"));
+ }
+
+ if (state != null) {
+ mMaxHeightView.setText(String.format("%6.0f m", state.max_height));
+ mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration));
+ mMaxSpeedView.setText(String.format("%6.0f m/s", state.max_speed()));
+ }
+ }
+
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java
new file mode 100644
index 00000000..d831f117
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright © 2013 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.util.Arrays;
+
+import org.altusmetrum.altoslib_1.*;
+
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.SupportMapFragment;
+import com.google.android.gms.maps.model.BitmapDescriptorFactory;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Marker;
+import com.google.android.gms.maps.model.MarkerOptions;
+import com.google.android.gms.maps.model.Polyline;
+import com.google.android.gms.maps.model.PolylineOptions;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+//import android.support.v4.app.FragmentTransaction;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.location.Location;
+
+public class TabMap extends Fragment implements AltosDroidTab {
+ AltosDroid mAltosDroid;
+
+ private SupportMapFragment mMapFragment;
+ private GoogleMap mMap;
+ private boolean mapLoaded = false;
+
+ private Marker mRocketMarker;
+ private Marker mPadMarker;
+ private Polyline mPolyline;
+
+ private TextView mDistanceView;
+ private TextView mBearingView;
+ private TextView mTargetLatitudeView;
+ private TextView mTargetLongitudeView;
+ private TextView mReceiverLatitudeView;
+ private TextView mReceiverLongitudeView;
+
+ private double mapAccuracy = -1;
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mAltosDroid = (AltosDroid) activity;
+ mAltosDroid.registerTab(this);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mMapFragment = new SupportMapFragment() {
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ setupMap();
+ }
+ };
+
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.tab_map, container, false);
+ mDistanceView = (TextView)v.findViewById(R.id.distance_value);
+ mBearingView = (TextView)v.findViewById(R.id.bearing_value);
+ mTargetLatitudeView = (TextView)v.findViewById(R.id.target_lat_value);
+ mTargetLongitudeView = (TextView)v.findViewById(R.id.target_lon_value);
+ mReceiverLatitudeView = (TextView)v.findViewById(R.id.receiver_lat_value);
+ mReceiverLongitudeView = (TextView)v.findViewById(R.id.receiver_lon_value);
+ return v;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ getChildFragmentManager().beginTransaction().add(R.id.map, mMapFragment).commit();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+
+ mAltosDroid.unregisterTab(this);
+ mAltosDroid = null;
+
+ //Fragment fragment = (getFragmentManager().findFragmentById(R.id.map));
+ //FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
+ //ft.remove(fragment);
+ //ft.commit();
+ }
+
+ private void setupMap() {
+ mMap = mMapFragment.getMap();
+ if (mMap != null) {
+ mMap.setMyLocationEnabled(true);
+ mMap.getUiSettings().setTiltGesturesEnabled(false);
+ mMap.getUiSettings().setZoomControlsEnabled(false);
+
+ mRocketMarker = mMap.addMarker(
+ // From: http://mapicons.nicolasmollet.com/markers/industry/military/missile-2/
+ new MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.rocket))
+ .position(new LatLng(0,0))
+ .visible(false)
+ );
+
+ mPadMarker = mMap.addMarker(
+ new MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.pad))
+ .position(new LatLng(0,0))
+ .visible(false)
+ );
+
+ mPolyline = mMap.addPolyline(
+ new PolylineOptions().add(new LatLng(0,0), new LatLng(0,0))
+ .width(3)
+ .color(Color.BLUE)
+ .visible(false)
+ );
+
+ mapLoaded = true;
+ }
+ }
+
+ private void center(double lat, double lon, double accuracy) {
+ if (mapAccuracy < 0 || accuracy < mapAccuracy/10) {
+ mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon),14));
+ mapAccuracy = accuracy;
+ }
+ }
+
+ public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ if (from_receiver != null) {
+ mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
+ mDistanceView.setText(String.format("%6.0f m", from_receiver.distance));
+ }
+
+ if (state != null) {
+ if (mapLoaded) {
+ if (state.gps != null) {
+ mRocketMarker.setPosition(new LatLng(state.gps.lat, state.gps.lon));
+ mRocketMarker.setVisible(true);
+
+ mPolyline.setPoints(Arrays.asList(new LatLng(state.pad_lat, state.pad_lon), new LatLng(state.gps.lat, state.gps.lon)));
+ mPolyline.setVisible(true);
+ }
+
+ if (state.state == AltosLib.ao_flight_pad) {
+ mPadMarker.setPosition(new LatLng(state.pad_lat, state.pad_lon));
+ mPadMarker.setVisible(true);
+ }
+ }
+ if (state.gps != null) {
+ mTargetLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
+ mTargetLongitudeView.setText(AltosDroid.pos(state.gps.lon, "W", "E"));
+ if (state.gps.locked && state.gps.nsat >= 4)
+ center (state.gps.lat, state.gps.lon, 10);
+ }
+ }
+
+ if (receiver != null) {
+ double accuracy;
+
+ if (receiver.hasAccuracy())
+ accuracy = receiver.getAccuracy();
+ else
+ accuracy = 1000;
+ mReceiverLatitudeView.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
+ mReceiverLongitudeView.setText(AltosDroid.pos(receiver.getLongitude(), "W", "E"));
+ center (receiver.getLatitude(), receiver.getLongitude(), accuracy);
+ }
+
+ }
+
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
new file mode 100644
index 00000000..066c1353
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2013 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_1.*;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.location.Location;
+
+public class TabPad extends Fragment implements AltosDroidTab {
+ AltosDroid mAltosDroid;
+
+ private TextView mBatteryVoltageView;
+ private GoNoGoLights mBatteryLights;
+ private TextView mApogeeVoltageView;
+ private GoNoGoLights mApogeeLights;
+ private TextView mMainVoltageView;
+ private GoNoGoLights mMainLights;
+ private TextView mDataLoggingView;
+ private GoNoGoLights mDataLoggingLights;
+ private TextView mGPSLockedView;
+ private GoNoGoLights mGPSLockedLights;
+ private TextView mGPSReadyView;
+ private GoNoGoLights mGPSReadyLights;
+ private TextView mPadLatitudeView;
+ private TextView mPadLongitudeView;
+ private TextView mPadAltitudeView;
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mAltosDroid = (AltosDroid) activity;
+ mAltosDroid.registerTab(this);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.tab_pad, container, false);
+ mBatteryVoltageView = (TextView) v.findViewById(R.id.battery_voltage_value);
+ mBatteryLights = new GoNoGoLights((ImageView) v.findViewById(R.id.battery_redled),
+ (ImageView) v.findViewById(R.id.battery_greenled),
+ getResources());
+
+ mApogeeVoltageView = (TextView) v.findViewById(R.id.apogee_voltage_value);
+ mApogeeLights = new GoNoGoLights((ImageView) v.findViewById(R.id.apogee_redled),
+ (ImageView) v.findViewById(R.id.apogee_greenled),
+ getResources());
+
+ mMainVoltageView = (TextView) v.findViewById(R.id.main_voltage_value);
+ mMainLights = new GoNoGoLights((ImageView) v.findViewById(R.id.main_redled),
+ (ImageView) v.findViewById(R.id.main_greenled),
+ getResources());
+
+ mDataLoggingView = (TextView) v.findViewById(R.id.logging_value);
+ mDataLoggingLights = new GoNoGoLights((ImageView) v.findViewById(R.id.logging_redled),
+ (ImageView) v.findViewById(R.id.logging_greenled),
+ getResources());
+
+ mGPSLockedView = (TextView) v.findViewById(R.id.gps_locked_value);
+ mGPSLockedLights = new GoNoGoLights((ImageView) v.findViewById(R.id.gps_locked_redled),
+ (ImageView) v.findViewById(R.id.gps_locked_greenled),
+ getResources());
+
+ mGPSReadyView = (TextView) v.findViewById(R.id.gps_ready_value);
+ mGPSReadyLights = new GoNoGoLights((ImageView) v.findViewById(R.id.gps_ready_redled),
+ (ImageView) v.findViewById(R.id.gps_ready_greenled),
+ getResources());
+
+ mPadLatitudeView = (TextView) v.findViewById(R.id.pad_lat_value);
+ mPadLongitudeView = (TextView) v.findViewById(R.id.pad_lon_value);
+ mPadAltitudeView = (TextView) v.findViewById(R.id.pad_alt_value);
+ return v;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mAltosDroid.unregisterTab(this);
+ mAltosDroid = null;
+ }
+
+ public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+ if (state != null) {
+ mBatteryVoltageView.setText(AltosDroid.number("%4.2f V", state.battery));
+ mBatteryLights.set(state.battery > 3.7, state.battery == AltosRecord.MISSING);
+
+ mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.drogue_sense));
+ mApogeeLights.set(state.drogue_sense > 3.2, state.drogue_sense == AltosRecord.MISSING);
+
+ mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_sense));
+ mMainLights.set(state.main_sense > 3.2, state.main_sense == AltosRecord.MISSING);
+
+ if (state.data.flight != 0) {
+ if (state.data.state <= AltosLib.ao_flight_pad)
+ mDataLoggingView.setText("Ready to record");
+ else if (state.data.state < AltosLib.ao_flight_landed)
+ mDataLoggingView.setText("Recording data");
+ else
+ mDataLoggingView.setText("Recorded data");
+ } else {
+ mDataLoggingView.setText("Storage full");
+ }
+ mDataLoggingLights.set(state.data.flight != 0, state.data.flight == AltosRecord.MISSING);
+
+ if (state.gps != null) {
+ mGPSLockedView.setText(AltosDroid.integer("%4d sats", state.gps.nsat));
+ mGPSLockedLights.set(state.gps.locked && state.gps.nsat >= 4, false);
+ if (state.gps_ready)
+ mGPSReadyView.setText("Ready");
+ else
+ mGPSReadyView.setText(AltosDroid.integer("Waiting %d", state.gps_waiting));
+ } else
+ mGPSLockedLights.set(false, true);
+ mGPSReadyLights.set(state.gps_ready, state.gps == null);
+ }
+
+ if (receiver != null) {
+ double altitude = 0;
+ if (receiver.hasAltitude())
+ altitude = receiver.getAltitude();
+ mPadLatitudeView.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
+ mPadLongitudeView.setText(AltosDroid.pos(receiver.getLongitude(), "W", "E"));
+ mPadAltitudeView.setText(AltosDroid.number("%4.0f m", altitude));
+ }
+ }
+
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabsAdapter.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabsAdapter.java
new file mode 100644
index 00000000..a4758c37
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabsAdapter.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+
+
+
+/**
+ * This is a helper class that implements the management of tabs and all
+ * details of connecting a ViewPager with associated TabHost. It relies on a
+ * trick. Normally a tab host has a simple API for supplying a View or
+ * Intent that each tab will show. This is not sufficient for switching
+ * between pages. So instead we make the content part of the tab host
+ * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
+ * view to show as the tab content. It listens to changes in tabs, and takes
+ * care of switch to the correct paged in the ViewPager whenever the selected
+ * tab changes.
+ */
+public class TabsAdapter extends FragmentPagerAdapter
+ implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
+ private final Context mContext;
+ private final TabHost mTabHost;
+ private final ViewPager mViewPager;
+ private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
+
+ static final class TabInfo {
+ private final String tag;
+ private final Class<?> clss;
+ private final Bundle args;
+
+ TabInfo(String _tag, Class<?> _class, Bundle _args) {
+ tag = _tag;
+ clss = _class;
+ args = _args;
+ }
+ }
+
+ static class DummyTabFactory implements TabHost.TabContentFactory {
+ private final Context mContext;
+
+ public DummyTabFactory(Context context) {
+ mContext = context;
+ }
+
+ public View createTabContent(String tag) {
+ View v = new View(mContext);
+ v.setMinimumWidth(0);
+ v.setMinimumHeight(0);
+ return v;
+ }
+ }
+
+ public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) {
+ super(activity.getSupportFragmentManager());
+ mContext = activity;
+ mTabHost = tabHost;
+ mViewPager = pager;
+ mTabHost.setOnTabChangedListener(this);
+ mViewPager.setAdapter(this);
+ mViewPager.setOnPageChangeListener(this);
+ }
+
+ public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
+ tabSpec.setContent(new DummyTabFactory(mContext));
+ String tag = tabSpec.getTag();
+
+ TabInfo info = new TabInfo(tag, clss, args);
+ mTabs.add(info);
+ mTabHost.addTab(tabSpec);
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mTabs.size();
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ TabInfo info = mTabs.get(position);
+ return Fragment.instantiate(mContext, info.clss.getName(), info.args);
+ }
+
+ public void onTabChanged(String tabId) {
+ int position = mTabHost.getCurrentTab();
+ mViewPager.setCurrentItem(position);
+ }
+
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ }
+
+ public void onPageSelected(int position) {
+ // Unfortunately when TabHost changes the current tab, it kindly
+ // also takes care of putting focus on it when not in touch mode.
+ // The jerk.
+ // This hack tries to prevent this from pulling focus out of our
+ // ViewPager.
+ TabWidget widget = mTabHost.getTabWidget();
+ int oldFocusability = widget.getDescendantFocusability();
+ widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ mTabHost.setCurrentTab(position);
+ widget.setDescendantFocusability(oldFocusability);
+ }
+
+ public void onPageScrollStateChanged(int state) {
+ }
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryLogger.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryLogger.java
new file mode 100644
index 00000000..3ece04ac
--- /dev/null
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryLogger.java
@@ -0,0 +1,73 @@
+package org.altusmetrum.AltosDroid;
+
+import org.altusmetrum.altoslib_1.*;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Environment;
+import android.util.Log;
+
+public class TelemetryLogger {
+ private static final String TAG = "TelemetryLogger";
+ private static final boolean D = true;
+
+ private Context context = null;
+ private AltosLink link = null;
+ private AltosLog logger = null;
+
+ private BroadcastReceiver mExternalStorageReceiver;
+
+ public TelemetryLogger(Context in_context, AltosLink in_link) {
+ context = in_context;
+ link = in_link;
+
+ startWatchingExternalStorage();
+ }
+
+ public void stop() {
+ stopWatchingExternalStorage();
+ close();
+ }
+
+ private void close() {
+ if (logger != null) {
+ if (D) Log.d(TAG, "Shutting down Telemetry Logging");
+ logger.close();
+ logger = null;
+ }
+ }
+
+ void handleExternalStorageState() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ if (logger == null) {
+ if (D) Log.d(TAG, "Starting up Telemetry Logging");
+ logger = new AltosLog(link);
+ }
+ } else {
+ if (D) Log.d(TAG, "External Storage not present - stopping");
+ close();
+ }
+ }
+
+ void startWatchingExternalStorage() {
+ mExternalStorageReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleExternalStorageState();
+ }
+ };
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
+ filter.addAction(Intent.ACTION_MEDIA_REMOVED);
+ context.registerReceiver(mExternalStorageReceiver, filter);
+ handleExternalStorageState();
+ }
+
+ void stopWatchingExternalStorage() {
+ context.unregisterReceiver(mExternalStorageReceiver);
+ }
+
+}
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java
index 66e9c6bd..716ec589 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java
@@ -25,7 +25,7 @@ import java.util.concurrent.*;
import android.util.Log;
import android.os.Handler;
-import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altoslib_1.*;
public class TelemetryReader extends Thread {
@@ -68,12 +68,12 @@ public class TelemetryReader extends Thread {
if (record == null)
break;
state = new AltosState(record, state);
-
handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget();
} catch (ParseException pp) {
Log.e(TAG, String.format("Parse error: %d \"%s\"", pp.getErrorOffset(), pp.getMessage()));
} catch (AltosCRCException ce) {
++crc_errors;
+ handler.obtainMessage(TelemetryService.MSG_CRC_ERROR, new Integer(crc_errors)).sendToTarget();
}
}
} catch (InterruptedException ee) {
diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java
index 393fd2f6..0236b537 100644
--- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java
+++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java
@@ -29,7 +29,8 @@ import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
-//import android.os.Bundle;
+import android.content.Context;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Handler;
import android.os.Message;
@@ -37,10 +38,14 @@ import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationListener;
-import org.altusmetrum.AltosLib.*;
+import org.altusmetrum.altoslib_1.*;
-public class TelemetryService extends Service {
+
+public class TelemetryService extends Service implements LocationListener {
private static final String TAG = "TelemetryService";
private static final boolean D = true;
@@ -53,6 +58,7 @@ public class TelemetryService extends Service {
static final int MSG_DISCONNECTED = 6;
static final int MSG_TELEMETRY = 7;
static final int MSG_SETFREQUENCY = 8;
+ static final int MSG_CRC_ERROR = 9;
public static final int STATE_NONE = 0;
public static final int STATE_READY = 1;
@@ -76,10 +82,17 @@ public class TelemetryService extends Service {
private AltosBluetooth mAltosBluetooth = null;
private AltosConfigData mConfigData = null;
private TelemetryReader mTelemetryReader = null;
+ private TelemetryLogger mTelemetryLogger = null;
// internally track state of bluetooth connection
private int state = STATE_NONE;
+ // Last data seen; send to UI when it starts
+
+ private AltosState last_state;
+ private Location last_location;
+ private int last_crc_errors;
+
// Handler of incoming messages from clients.
static class IncomingHandler extends Handler {
private final WeakReference<TelemetryService> service;
@@ -95,6 +108,10 @@ public class TelemetryService extends Service {
// Now we try to send the freshly connected UI any relavant information about what
// we're talking to - Basically state and Config Data.
msg.replyTo.send(Message.obtain(null, AltosDroid.MSG_STATE_CHANGE, s.state, -1, s.mConfigData));
+ // We also send any recent telemetry or location data that's cached
+ if (s.last_state != null) msg.replyTo.send(Message.obtain(null, AltosDroid.MSG_TELEMETRY, s.last_state ));
+ if (s.last_location != null) msg.replyTo.send(Message.obtain(null, AltosDroid.MSG_LOCATION , s.last_location ));
+ if (s.last_crc_errors != 0 ) msg.replyTo.send(Message.obtain(null, AltosDroid.MSG_CRC_ERROR, s.last_crc_errors));
} catch (RemoteException e) {
s.mClients.remove(msg.replyTo);
}
@@ -125,8 +142,15 @@ public class TelemetryService extends Service {
}
break;
case MSG_TELEMETRY:
+ // forward telemetry messages
+ s.last_state = (AltosState) msg.obj;
s.sendMessageToClients(Message.obtain(null, AltosDroid.MSG_TELEMETRY, msg.obj));
break;
+ case MSG_CRC_ERROR:
+ // forward crc error messages
+ s.last_crc_errors = (Integer) msg.obj;
+ s.sendMessageToClients(Message.obtain(null, AltosDroid.MSG_CRC_ERROR, msg.obj));
+ break;
case MSG_SETFREQUENCY:
if (s.state == STATE_CONNECTED) {
try {
@@ -164,6 +188,11 @@ public class TelemetryService extends Service {
}
mTelemetryReader = null;
}
+ if (mTelemetryLogger != null) {
+ if (D) Log.d(TAG, "stopAltosBluetooth(): stopping TelemetryLogger");
+ mTelemetryLogger.stop();
+ mTelemetryLogger = null;
+ }
if (mAltosBluetooth != null) {
if (D) Log.d(TAG, "stopAltosBluetooth(): stopping AltosBluetooth");
mAltosBluetooth.close();
@@ -174,6 +203,9 @@ public class TelemetryService extends Service {
}
private void startAltosBluetooth() {
+ if (device == null) {
+ return;
+ }
if (mAltosBluetooth == null) {
if (D) Log.d(TAG, String.format("startAltosBluetooth(): Connecting to %s (%s)", device.getName(), device.getAddress()));
mAltosBluetooth = new AltosBluetooth(device, mHandler);
@@ -203,6 +235,8 @@ public class TelemetryService extends Service {
private void connected() {
try {
+ if (mAltosBluetooth == null)
+ throw new InterruptedException("no bluetooth");
mConfigData = mAltosBluetooth.config_data();
} catch (InterruptedException e) {
} catch (TimeoutException e) {
@@ -216,6 +250,8 @@ public class TelemetryService extends Service {
mTelemetryReader = new TelemetryReader(mAltosBluetooth, mHandler);
mTelemetryReader.start();
+
+ mTelemetryLogger = new TelemetryLogger(this, mAltosBluetooth);
}
@@ -241,6 +277,11 @@ public class TelemetryService extends Service {
// Start our timer - first event in 10 seconds, then every 10 seconds after that.
timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 10000L, 10000L);
+ // Listen for GPS and Network position updates
+ LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
+
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
+ locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
}
@Override
@@ -273,6 +314,9 @@ public class TelemetryService extends Service {
@Override
public void onDestroy() {
+ // Stop listening for location updates
+ ((LocationManager) getSystemService(Context.LOCATION_SERVICE)).removeUpdates(this);
+
// Stop the bluetooth Comms threads
stopAltosBluetooth();
@@ -292,4 +336,18 @@ public class TelemetryService extends Service {
}
+ public void onLocationChanged(Location location) {
+ last_location = location;
+ sendMessageToClients(Message.obtain(null, AltosDroid.MSG_LOCATION, location));
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+
+ public void onProviderEnabled(String provider) {
+ }
+
+ public void onProviderDisabled(String provider) {
+ }
+
}