From c8078d352a7f54a4a97d25af080155d3f875536a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 16 Jun 2014 22:49:34 -0700 Subject: java: Bump java library versions for next release Prepare for future release by bumping java versions now Signed-off-by: Keith Packard --- altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java index 5e8515cb..147405f6 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_4.*; +import org.altusmetrum.altoslib_5.*; public class AltosVoice { -- cgit v1.2.3 From 59dfe661fcb504f390d9726378c676f2b5b005f3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 17 Aug 2014 20:48:23 -0700 Subject: altosdroid: Skip updating hidden UI elements Instead of updating everything in the UI, only update the visible UI elements to save a bunch of computation. Signed-off-by: Keith Packard --- .../org/altusmetrum/AltosDroid/AltosBluetooth.java | 29 +++++++---- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 56 ++++++++++++++++++---- .../org/altusmetrum/AltosDroid/AltosDroidTab.java | 54 ++++++++++++++++++++- .../src/org/altusmetrum/AltosDroid/AltosVoice.java | 26 ++++++---- .../src/org/altusmetrum/AltosDroid/TabAscent.java | 8 +++- .../src/org/altusmetrum/AltosDroid/TabDescent.java | 6 ++- .../src/org/altusmetrum/AltosDroid/TabLanded.java | 9 ++-- .../src/org/altusmetrum/AltosDroid/TabMap.java | 11 +++-- .../src/org/altusmetrum/AltosDroid/TabPad.java | 6 ++- .../org/altusmetrum/AltosDroid/TabsAdapter.java | 33 +++++++++++-- 10 files changed, 190 insertions(+), 48 deletions(-) (limited to 'altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java') diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index a599698f..484efaf8 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -174,18 +174,29 @@ public class AltosBluetooth extends AltosLink { } catch (InterruptedException e) { connection_lost(); } - } + } + + private static final int buffer_size = 1024; + + private byte[] buffer = new byte[buffer_size]; + private int buffer_len = 0; + private int buffer_off = 0; public int getchar() { - try { - wait_connected(); - return input.read(); - } catch (IOException e) { - connection_lost(); - } catch (java.lang.InterruptedException e) { - connection_lost(); + while (buffer_off == buffer_len) { + try { + wait_connected(); + buffer_len = input.read(buffer); + buffer_off = 0; + } catch (IOException e) { + connection_lost(); + return AltosLink.ERROR; + } catch (java.lang.InterruptedException e) { + connection_lost(); + return AltosLink.ERROR; + } } - return AltosLink.ERROR; + return buffer[buffer_off++]; } public void close() { diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 563ccd5a..c9c38d98 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -37,6 +37,7 @@ import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; import android.util.DisplayMetrics; import android.util.Log; import android.view.Menu; @@ -53,8 +54,8 @@ import org.altusmetrum.altoslib_5.*; public class AltosDroid extends FragmentActivity { // Debugging - private static final String TAG = "AltosDroid"; - private static final boolean D = true; + static final String TAG = "AltosDroid"; + static final boolean D = true; // Message types received by our Handler public static final int MSG_STATE_CHANGE = 1; @@ -67,6 +68,8 @@ public class AltosDroid extends FragmentActivity { private static final int REQUEST_CONNECT_DEVICE = 1; private static final int REQUEST_ENABLE_BT = 2; + public static FragmentManager fm; + // Layout Views private TextView mTitle; @@ -145,6 +148,7 @@ public class AltosDroid extends FragmentActivity { ad.set_location((Location) msg.obj); break; case MSG_CRC_ERROR: + break; case MSG_UPDATE_AGE: if (ad.saved_state != null) { ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.received_time + 500) / 1000)); @@ -206,13 +210,29 @@ public class AltosDroid extends FragmentActivity { void set_location(Location location) { saved_location = location; + Log.d(TAG, "set_location"); update_ui(saved_state); } + boolean same_string(String a, String b) { + if (a == null) { + if (b == null) + return true; + return false; + } else { + if (b == null) + return false; + return a.equals(b); + } + } + void update_ui(AltosState state) { + + Log.d(TAG, "update_ui"); if (state != null && saved_state != null) { if (saved_state.state != state.state) { String currentTab = mTabHost.getCurrentTabTag(); + Log.d(TAG, "switch state"); switch (state.state) { case AltosLib.ao_flight_boost: if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("ascent"); @@ -226,7 +246,6 @@ public class AltosDroid extends FragmentActivity { } } } - saved_state = state; AltosGreatCircle from_receiver = null; @@ -243,18 +262,35 @@ public class AltosDroid extends FragmentActivity { } if (state != null) { - mCallsignView.setText(state.callsign); - mSerialView.setText(String.format("%d", state.serial)); - mFlightView.setText(String.format("%d", state.flight)); - mStateView.setText(state.state_name()); - mRSSIView.setText(String.format("%d", state.rssi)); + if (saved_state == null || !same_string(saved_state.callsign, state.callsign)) { + Log.d(TAG, "update callsign"); + mCallsignView.setText(state.callsign); + } + if (saved_state == null || state.serial != saved_state.serial) { + Log.d(TAG, "update serial"); + mSerialView.setText(String.format("%d", state.serial)); + } + if (saved_state == null || state.flight != saved_state.flight) { + Log.d(TAG, "update flight"); + mFlightView.setText(String.format("%d", state.flight)); + } + if (saved_state == null || state.state != saved_state.state) { + Log.d(TAG, "update state"); + mStateView.setText(state.state_name()); + } + if (saved_state == null || state.rssi != saved_state.rssi) { + Log.d(TAG, "update rssi"); + mRSSIView.setText(String.format("%d", state.rssi)); + } } for (AltosDroidTab mTab : mTabs) - mTab.update_ui(state, from_receiver, saved_location); + mTab.update_ui(state, from_receiver, saved_location, mTab == mTabsAdapter.currentItem()); if (state != null) mAltosVoice.tell(state); + + saved_state = state; } private void onTimerTick() { @@ -294,6 +330,8 @@ public class AltosDroid extends FragmentActivity { super.onCreate(savedInstanceState); if(D) Log.e(TAG, "+++ ON CREATE +++"); + fm = getSupportFragmentManager(); + // Get local Bluetooth adapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java index 20593bd5..b960eb1a 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java @@ -19,7 +19,57 @@ package org.altusmetrum.AltosDroid; import org.altusmetrum.altoslib_5.*; import android.location.Location; +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.support.v4.app.FragmentManager; +import android.location.Location; +import android.util.Log; + +public abstract class AltosDroidTab extends Fragment { + AltosState last_state; + AltosGreatCircle last_from_receiver; + Location last_receiver; + + public abstract void show(AltosState state, AltosGreatCircle from_receiver, Location receiver); + + public abstract String tab_name(); + + public void set_visible(boolean visible) { + FragmentTransaction ft = AltosDroid.fm.beginTransaction(); + if (visible) + ft.show(this); + else + ft.hide(this); + ft.commit(); + } + + public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver, boolean is_current) { + if (is_current) { + Log.d(AltosDroid.TAG, String.format("%s: visible, performing update", tab_name())); + + show(state, from_receiver, receiver); + } else { + Log.d(AltosDroid.TAG, String.format("%s: not visible, skipping update", tab_name())); + last_state = state; + last_from_receiver = from_receiver; + last_receiver = receiver; + return; + } + } + + public void onHiddenChanged(boolean hidden) { + if (last_state != null && isVisible()) { + AltosState state = last_state; + AltosGreatCircle from_receiver = last_from_receiver; + Location receiver = last_receiver; -public interface AltosDroidTab { - public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver); + last_state = null; + last_from_receiver = null; + last_receiver = null; + show(state, from_receiver, receiver); + } + } } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java index 147405f6..b05913b6 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java @@ -45,7 +45,7 @@ public class AltosVoice { } - public void speak(String s) { + public synchronized void speak(String s) { if (!tts_enabled) return; tts.speak(s, TextToSpeech.QUEUE_ADD, null); } @@ -87,7 +87,8 @@ public class AltosVoice { } } old_state = state; - idle_thread.notice(state, spoke); + if (idle_thread != null) + idle_thread.notice(state, spoke); } @@ -117,13 +118,20 @@ public class AltosVoice { state.state == AltosLib.ao_flight_stateless) && state.range >= 0) { - speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n", - (int) (state.height() + 0.5), - state.from_pad.bearing_words( - AltosGreatCircle.BEARING_VOICE), - (int) (state.from_pad.bearing + 0.5), - (int) (state.elevation + 0.5), - (int) (state.range + 0.5))); + if (state.from_pad != null) { + speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n", + (int) (state.height() + 0.5), + state.from_pad.bearing_words( + AltosGreatCircle.BEARING_VOICE), + (int) (state.from_pad.bearing + 0.5), + (int) (state.elevation + 0.5), + (int) (state.range + 0.5))); + } else { + speak(String.format("Height %d, elevation %d, range %d.\n", + (int) (state.height() + 0.5), + (int) (state.elevation + 0.5), + (int) (state.range + 0.5))); + } } else if (state.state > AltosLib.ao_flight_pad) { if (state.height() != AltosLib.MISSING) speak(String.format("%d meters", (int) (state.height() + 0.5))); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java index cb9fd5c8..c146c277 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java @@ -29,7 +29,7 @@ import android.widget.ImageView; import android.widget.TextView; import android.location.Location; -public class TabAscent extends Fragment implements AltosDroidTab { +public class TabAscent extends AltosDroidTab { AltosDroid mAltosDroid; private TextView mHeightView; @@ -85,7 +85,11 @@ public class TabAscent extends Fragment implements AltosDroidTab { mAltosDroid = null; } - public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) { + public String tab_name() { + return "ascent"; + } + + public void show(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())); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java index 2171afa4..6d781efd 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java @@ -29,7 +29,7 @@ import android.widget.ImageView; import android.widget.TextView; import android.location.Location; -public class TabDescent extends Fragment implements AltosDroidTab { +public class TabDescent extends AltosDroidTab { AltosDroid mAltosDroid; private TextView mSpeedView; @@ -89,7 +89,9 @@ public class TabDescent extends Fragment implements AltosDroidTab { mAltosDroid = null; } - public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) { + public String tab_name() { return "descent"; } + + public void show(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())); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java index 47e41d59..16427d8b 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java @@ -28,7 +28,7 @@ import android.view.ViewGroup; import android.widget.TextView; import android.location.Location; -public class TabLanded extends Fragment implements AltosDroidTab { +public class TabLanded extends AltosDroidTab { AltosDroid mAltosDroid; private TextView mBearingView; @@ -73,7 +73,9 @@ public class TabLanded extends Fragment implements AltosDroidTab { mAltosDroid = null; } - public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) { + public String tab_name() { return "landed"; } + + public void show(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)); @@ -87,12 +89,11 @@ public class TabLanded extends Fragment implements AltosDroidTab { 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 index 15dc8bf7..811e5482 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java @@ -42,7 +42,7 @@ import android.view.ViewGroup; import android.widget.TextView; import android.location.Location; -public class TabMap extends Fragment implements AltosDroidTab { +public class TabMap extends AltosDroidTab { AltosDroid mAltosDroid; private SupportMapFragment mMapFragment; @@ -51,6 +51,7 @@ public class TabMap extends Fragment implements AltosDroidTab { private Marker mRocketMarker; private Marker mPadMarker; + private boolean pad_set; private Polyline mPolyline; private TextView mDistanceView; @@ -152,7 +153,9 @@ public class TabMap extends Fragment implements AltosDroidTab { } } - public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) { + public String tab_name() { return "map"; } + + public void show(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)); @@ -168,7 +171,8 @@ public class TabMap extends Fragment implements AltosDroidTab { mPolyline.setVisible(true); } - if (state.state == AltosLib.ao_flight_pad) { + if (!pad_set && state.pad_lat != AltosLib.MISSING) { + pad_set = true; mPadMarker.setPosition(new LatLng(state.pad_lat, state.pad_lon)); mPadMarker.setVisible(true); } @@ -194,5 +198,4 @@ public class TabMap extends Fragment implements AltosDroidTab { } } - } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java index 175a41de..03b78b75 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java @@ -29,7 +29,7 @@ import android.widget.ImageView; import android.widget.TextView; import android.location.Location; -public class TabPad extends Fragment implements AltosDroidTab { +public class TabPad extends AltosDroidTab { AltosDroid mAltosDroid; private TextView mBatteryVoltageView; @@ -101,7 +101,9 @@ public class TabPad extends Fragment implements AltosDroidTab { mAltosDroid = null; } - public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) { + public String tab_name() { return "pad"; } + + public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) { if (state != null) { mBatteryVoltageView.setText(AltosDroid.number("%4.2f V", state.battery_voltage)); mBatteryLights.set(state.battery_voltage >= AltosLib.ao_battery_good, state.battery_voltage == AltosLib.MISSING); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabsAdapter.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabsAdapter.java index a4758c37..1ac34f9d 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabsAdapter.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabsAdapter.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; @@ -28,8 +29,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TabHost; import android.widget.TabWidget; - - +import android.util.Log; /** * This is a helper class that implements the management of tabs and all @@ -48,11 +48,13 @@ public class TabsAdapter extends FragmentPagerAdapter private final TabHost mTabHost; private final ViewPager mViewPager; private final ArrayList mTabs = new ArrayList(); + private int position; - static final class TabInfo { + static class TabInfo { private final String tag; private final Class clss; private final Bundle args; + private Fragment fragment; TabInfo(String _tag, Class _class, Bundle _args) { tag = _tag; @@ -104,11 +106,32 @@ public class TabsAdapter extends FragmentPagerAdapter @Override public Fragment getItem(int position) { TabInfo info = mTabs.get(position); - return Fragment.instantiate(mContext, info.clss.getName(), info.args); + Log.d(AltosDroid.TAG, String.format("TabsAdapter.getItem(%d)", position)); + info.fragment = Fragment.instantiate(mContext, info.clss.getName(), info.args); + return info.fragment; + } + + public Fragment currentItem() { + TabInfo info = mTabs.get(position); + return info.fragment; } public void onTabChanged(String tabId) { - int position = mTabHost.getCurrentTab(); + AltosDroidTab prev_frag = (AltosDroidTab) mTabs.get(position).fragment; + + position = mTabHost.getCurrentTab(); + + AltosDroidTab cur_frag = (AltosDroidTab) mTabs.get(position).fragment; + + if (prev_frag != cur_frag) { + if (prev_frag != null) { + prev_frag.set_visible(false); + } + } + if (cur_frag != null) { + cur_frag.set_visible(true); + } + Log.d(AltosDroid.TAG, String.format("TabsAdapter.onTabChanged(%s) = %d", tabId, position)); mViewPager.setCurrentItem(position); } -- cgit v1.2.3 From 3842735e303f0bf6f46ed8cb659c92d8bb9bd137 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 3 Sep 2014 22:32:49 -0700 Subject: altosdroid: Use single object to pass data to UI Instead of having separate messages for each piece of telemetry state, package the whole mess up in one object and send it for any change. This simplifies tracking within the UI by avoiding corner cases during reconnect. Signed-off-by: Keith Packard --- altosdroid/res/values/strings.xml | 2 +- .../org/altusmetrum/AltosDroid/AltosBluetooth.java | 6 +- .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 246 ++++++++++----------- .../src/org/altusmetrum/AltosDroid/AltosVoice.java | 37 ++-- .../altusmetrum/AltosDroid/TelemetryReader.java | 40 ++-- .../altusmetrum/AltosDroid/TelemetryService.java | 170 +++++++------- 6 files changed, 256 insertions(+), 245 deletions(-) (limited to 'altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java') diff --git a/altosdroid/res/values/strings.xml b/altosdroid/res/values/strings.xml index 0384b9b8..6ea9fec2 100644 --- a/altosdroid/res/values/strings.xml +++ b/altosdroid/res/values/strings.xml @@ -22,7 +22,7 @@ Bluetooth was not enabled. connecting… - connected: + connected not connected diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java index 4a1fc371..51ef5e94 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java @@ -146,16 +146,18 @@ public class AltosBluetooth extends AltosLink { } public void save_frequency() { - AltosPreferences.set_frequency(serial, frequency); + AltosPreferences.set_frequency(0, frequency); } public void save_telemetry_rate() { - AltosPreferences.set_telemetry_rate(serial, telemetry_rate); + AltosPreferences.set_telemetry_rate(0, telemetry_rate); } private synchronized void wait_connected() throws InterruptedException, IOException { if (input == null) { + if (D) Log.d(TAG, "wait_connected..."); wait(); + if (D) Log.d(TAG, "wait_connected done"); if (input == null) throw new IOException(); } } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index db1ca691..d276798e 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -60,20 +60,18 @@ public class AltosDroid extends FragmentActivity { static final boolean D = true; // 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; - public static final int MSG_FREQUENCY = 6; - public static final int MSG_TELEMETRY_RATE = 7; + + public static final int MSG_STATE = 1; + public static final int MSG_UPDATE_AGE = 2; // Intent request codes - private static final int REQUEST_CONNECT_DEVICE = 1; - private static final int REQUEST_ENABLE_BT = 2; + public static final int REQUEST_CONNECT_DEVICE = 1; + public static final int REQUEST_ENABLE_BT = 2; public static FragmentManager fm; + private BluetoothAdapter mBluetoothAdapter = null; + // Layout Views private TextView mTitle; @@ -100,20 +98,14 @@ public class AltosDroid extends FragmentActivity { int tabHeight; // Timer and Saved flight state for Age calculation - private Timer timer = new Timer(); + private Timer timer; AltosState saved_state; - Location saved_location; // Service private boolean mIsBound = false; private Messenger mService = null; final Messenger mMessenger = new Messenger(new IncomingHandler(this)); - // TeleBT Config data - private AltosConfigData mConfigData = null; - // Local Bluetooth adapter - private BluetoothAdapter mBluetoothAdapter = null; - // Text to Speech private AltosVoice mAltosVoice = null; @@ -125,44 +117,21 @@ public class AltosDroid extends FragmentActivity { @Override public void handleMessage(Message msg) { AltosDroid ad = mAltosDroid.get(); + switch (msg.what) { - case MSG_STATE_CHANGE: - if(D) Log.d(TAG, "MSG_STATE_CHANGE: " + msg.arg1); - switch (msg.arg1) { - case TelemetryService.STATE_CONNECTED: - ad.set_config_data((AltosConfigData) msg.obj); - break; - case TelemetryService.STATE_CONNECTING: - ad.mTitle.setText(R.string.title_connecting); - break; - case TelemetryService.STATE_READY: - case TelemetryService.STATE_NONE: - ad.mConfigData = null; - ad.mTitle.setText(R.string.title_not_connected); - String active_device = AltosDroidPreferences.active_device(); - if (active_device != null) - ad.connectDevice(active_device); - break; + case MSG_STATE: + if(D) Log.d(TAG, "MSG_STATE"); + TelemetryState telemetry_state = (TelemetryState) msg.obj; + if (telemetry_state == null) { + Log.d(TAG, "telemetry_state null!"); + return; } - break; - case MSG_TELEMETRY: - ad.update_ui((AltosState) msg.obj); - break; - case MSG_LOCATION: - ad.set_location((Location) msg.obj); - break; - case MSG_CRC_ERROR: + + ad.update_state(telemetry_state); break; case MSG_UPDATE_AGE: - if (ad.saved_state != null) { - ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.received_time + 500) / 1000)); - } - break; - case MSG_FREQUENCY: - ad.set_frequency((Double) msg.obj); - break; - case MSG_TELEMETRY_RATE: - ad.set_telemetry_rate((Integer) msg.obj); + if(D) Log.d(TAG, "MSG_UPDATE_AGE"); + ad.update_age(); break; } } @@ -218,37 +187,52 @@ public class AltosDroid extends FragmentActivity { mTabs.remove(mTab); } - void set_location(Location location) { - saved_location = location; - Log.d(TAG, "set_location"); - update_ui(saved_state); - } - - void set_title() { - if (mConfigData != null) { - String str = String.format("S/N %d %6.3f MHz", mConfigData.serial, frequency); - - if (telemetry_rate != AltosLib.ao_telemetry_rate_38400) - str = str.concat(String.format(" %d bps", AltosLib.ao_telemetry_rate_values[telemetry_rate])); - mTitle.setText(str); + void update_title(TelemetryState telemetry_state) { + switch (telemetry_state.connect) { + case TelemetryState.CONNECT_CONNECTED: + if (telemetry_state.config != null) { + String str = String.format("S/N %d %6.3f MHz", telemetry_state.config.serial, + telemetry_state.frequency); + if (telemetry_state.telemetry_rate != AltosLib.ao_telemetry_rate_38400) + str = str.concat(String.format(" %d bps", + AltosLib.ao_telemetry_rate_values[telemetry_state.telemetry_rate])); + mTitle.setText(str); + } else { + mTitle.setText(R.string.title_connected_to); + } + break; + case TelemetryState.CONNECT_CONNECTING: + mTitle.setText(R.string.title_connecting); + break; + case TelemetryState.CONNECT_READY: + case TelemetryState.CONNECT_NONE: + mTitle.setText(R.string.title_not_connected); + break; } } - void set_frequency(double frequency) { - if (D) Log.d(TAG, String.format("AltosDroid: set_frequency %f\n", frequency)); - this.frequency = frequency; - set_title(); + void start_timer() { + if (timer == null) { + timer = new Timer(); + timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 1000L, 1000L); + } } - void set_telemetry_rate(int telemetry_rate) { - if (D) Log.d(TAG, String.format("AltosDroid: set_telemetry_rate %d\n", telemetry_rate)); - this.telemetry_rate = telemetry_rate; - set_title(); + void stop_timer() { + if (timer != null) { + timer.cancel(); + timer.purge(); + timer = null; + } } - void set_config_data(AltosConfigData config_data) { - mConfigData = config_data; - set_title(); + void update_state(TelemetryState telemetry_state) { + update_title(telemetry_state); + update_ui(telemetry_state.state, telemetry_state.location); + if (telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) + start_timer(); + else + stop_timer(); } boolean same_string(String a, String b) { @@ -263,52 +247,73 @@ public class AltosDroid extends FragmentActivity { } } - void update_ui(AltosState state) { + void update_age() { + if (saved_state != null) + mAgeView.setText(String.format("%d", (System.currentTimeMillis() - saved_state.received_time + 500) / 1000)); + } + + void update_ui(AltosState state, Location location) { Log.d(TAG, "update_ui"); int prev_state = AltosLib.ao_flight_invalid; + AltosGreatCircle from_receiver = null; + if (saved_state != null) prev_state = saved_state.state; if (state != null) { Log.d(TAG, String.format("prev state %d new state %d\n", prev_state, state.state)); - if (prev_state != state.state) { - String currentTab = mTabHost.getCurrentTabTag(); - Log.d(TAG, "switch state"); - 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; - case AltosLib.ao_flight_stateless: - if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("descent"); - break; + if (state.state == AltosLib.ao_flight_stateless) { + boolean prev_locked = false; + boolean locked = false; + + if(state.gps != null) + locked = state.gps.locked; + if (saved_state != null && saved_state.gps != null) + prev_locked = saved_state.gps.locked; + if (prev_locked != locked) { + String currentTab = mTabHost.getCurrentTabTag(); + if (locked) { + if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("descent"); + } else { + if (currentTab.equals("descent")) mTabHost.setCurrentTabByTag("pad"); + } + } + } else { + if (prev_state != state.state) { + String currentTab = mTabHost.getCurrentTabTag(); + Log.d(TAG, "switch state"); + 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; + case AltosLib.ao_flight_stateless: + if (currentTab.equals("pad")) mTabHost.setCurrentTabByTag("descent"); + break; + } } } - } - - 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 (location != null && state.gps != null && state.gps.locked) { + double altitude = 0; + if (location.hasAltitude()) + altitude = location.getAltitude(); + from_receiver = new AltosGreatCircle(location.getLatitude(), + location.getLongitude(), + altitude, + state.gps.lat, + state.gps.lon, + state.gps.alt); + } - if (state != null) { if (saved_state == null || !same_string(saved_state.callsign, state.callsign)) { Log.d(TAG, "update callsign"); mCallsignView.setText(state.callsign); @@ -337,10 +342,10 @@ public class AltosDroid extends FragmentActivity { } for (AltosDroidTab mTab : mTabs) - mTab.update_ui(state, from_receiver, saved_location, mTab == mTabsAdapter.currentItem()); + mTab.update_ui(state, from_receiver, location, mTab == mTabsAdapter.currentItem()); if (state != null) - mAltosVoice.tell(state); + mAltosVoice.tell(state, from_receiver); saved_state = state; } @@ -382,8 +387,6 @@ public class AltosDroid extends FragmentActivity { super.onCreate(savedInstanceState); if(D) Log.e(TAG, "+++ ON CREATE +++"); - fm = getSupportFragmentManager(); - // Get local Bluetooth adapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); @@ -391,11 +394,9 @@ public class AltosDroid extends FragmentActivity { if (mBluetoothAdapter == null) { Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show(); finish(); - return; } - // Initialise preferences - AltosDroidPreferences.init(this); + fm = getSupportFragmentManager(); // Set up the window layout requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); @@ -438,7 +439,6 @@ public class AltosDroid extends FragmentActivity { 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); @@ -458,8 +458,6 @@ public class AltosDroid extends FragmentActivity { mStateView = (TextView) findViewById(R.id.state_value); mAgeView = (TextView) findViewById(R.id.age_value); - timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 1000L, 100L); - mAltosVoice = new AltosVoice(this); } @@ -468,14 +466,14 @@ public class AltosDroid extends FragmentActivity { super.onStart(); if(D) Log.e(TAG, "++ ON START ++"); + // Start Telemetry Service + startService(new Intent(AltosDroid.this, TelemetryService.class)); + if (!mBluetoothAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); - startActivityForResult(enableIntent, REQUEST_ENABLE_BT); + startActivityForResult(enableIntent, AltosDroid.REQUEST_ENABLE_BT); } - // Start Telemetry Service - startService(new Intent(AltosDroid.this, TelemetryService.class)); - doBindService(); } @@ -506,6 +504,7 @@ public class AltosDroid extends FragmentActivity { if(D) Log.e(TAG, "--- ON DESTROY ---"); if (mAltosVoice != null) mAltosVoice.stop(); + stop_timer(); } public void onActivityResult(int requestCode, int resultCode, Intent data) { @@ -534,12 +533,10 @@ public class AltosDroid extends FragmentActivity { } private void connectDevice(String address) { - // Get the BLuetoothDevice object - BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); // Attempt to connect to the device try { - if (D) Log.d(TAG, "Connecting to " + device.getName()); - mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT, device)); + if (D) Log.d(TAG, "Connecting to " + address); + mService.send(Message.obtain(null, TelemetryService.MSG_CONNECT, address)); } catch (RemoteException e) { } } @@ -547,7 +544,6 @@ public class AltosDroid extends FragmentActivity { private void connectDevice(Intent data) { // Get the device MAC address String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS); - AltosDroidPreferences.set_active_device(address); connectDevice(address); } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java index b05913b6..b8def367 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java @@ -58,7 +58,7 @@ public class AltosVoice { } } - public void tell(AltosState state) { + public void tell(AltosState state, AltosGreatCircle from_receiver) { if (!tts_enabled) return; boolean spoke = false; @@ -88,13 +88,14 @@ public class AltosVoice { } old_state = state; if (idle_thread != null) - idle_thread.notice(state, spoke); + idle_thread.notice(state, from_receiver, spoke); } class IdleThread extends Thread { boolean started; private AltosState state; + private AltosGreatCircle from_receiver; int reported_landing; int report_interval; long report_time; @@ -112,25 +113,26 @@ public class AltosVoice { return; } - /* If the rocket isn't on the pad, then report height */ - if (((AltosLib.ao_flight_drogue <= state.state && + /* If the rocket isn't on the pad, then report location */ + if ((AltosLib.ao_flight_drogue <= state.state && state.state < AltosLib.ao_flight_landed) || - state.state == AltosLib.ao_flight_stateless) && - state.range >= 0) + state.state == AltosLib.ao_flight_stateless) { - if (state.from_pad != null) { + AltosGreatCircle position; + + if (from_receiver != null) + position = from_receiver; + else + position = state.from_pad; + + if (position != null) { speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n", (int) (state.height() + 0.5), - state.from_pad.bearing_words( + position.bearing_words( AltosGreatCircle.BEARING_VOICE), - (int) (state.from_pad.bearing + 0.5), - (int) (state.elevation + 0.5), - (int) (state.range + 0.5))); - } else { - speak(String.format("Height %d, elevation %d, range %d.\n", - (int) (state.height() + 0.5), - (int) (state.elevation + 0.5), - (int) (state.range + 0.5))); + (int) (position.bearing + 0.5), + (int) (position.elevation + 0.5), + (int) (position.range + 0.5))); } } else if (state.state > AltosLib.ao_flight_pad) { if (state.height() != AltosLib.MISSING) @@ -186,9 +188,10 @@ public class AltosVoice { } } - public synchronized void notice(AltosState new_state, boolean spoken) { + public synchronized void notice(AltosState new_state, AltosGreatCircle new_from_receiver, boolean spoken) { AltosState old_state = state; state = new_state; + from_receiver = new_from_receiver; if (!started && state.state > AltosLib.ao_flight_pad) { started = true; start(); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java index bec51851..971c3e80 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java @@ -31,6 +31,7 @@ import org.altusmetrum.altoslib_5.*; public class TelemetryReader extends Thread { private static final String TAG = "TelemetryReader"; + private static final boolean D = true; int crc_errors; @@ -44,12 +45,6 @@ public class TelemetryReader extends Thread { LinkedBlockingQueue telemQueue; public AltosState read() throws ParseException, AltosCRCException, InterruptedException, IOException { - if (stacked != null) { - state = stacked.read(); - if (state != null) - return state; - stacked = null; - } AltosLine l = telemQueue.take(); if (l.line == null) throw new IOException("IO error"); @@ -78,6 +73,26 @@ public class TelemetryReader extends Thread { AltosState state = null; try { + if (D) Log.d(TAG, "starting reader"); + while (stacked != null) { + AltosState stacked_state = null; + try { + stacked_state = stacked.read(); + } catch (ParseException pe) { + continue; + } catch (AltosCRCException ce) { + continue; + } + if (stacked_state != null) + state = stacked_state; + else + stacked = null; + } + if (state != null) { + if (D) Log.d(TAG, "Send initial state"); + handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget(); + } + if (D) Log.d(TAG, "starting loop"); while (telemQueue != null) { try { state = read(); @@ -97,6 +112,7 @@ public class TelemetryReader extends Thread { } public TelemetryReader (AltosLink in_link, Handler in_handler, AltosFlightReader in_stacked) { + if (D) Log.d(TAG, "connected TelemetryReader create started"); link = in_link; handler = in_handler; stacked = in_stacked; @@ -104,15 +120,9 @@ public class TelemetryReader extends Thread { state = null; telemQueue = new LinkedBlockingQueue(); link.add_monitor(telemQueue); - try { - link.set_radio_frequency(AltosPreferences.frequency(link.serial)); - link.set_telemetry(AltosLib.ao_telemetry_standard); - link.set_telemetry_rate(AltosPreferences.telemetry_rate(link.serial)); - } catch (InterruptedException ee) { - close(); - } catch (TimeoutException te) { - close(); - } + link.set_telemetry(AltosLib.ao_telemetry_standard); + + if (D) Log.d(TAG, "connected TelemetryReader created"); } private static AltosFlightReader existing_data(AltosLink link) { diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index 8e5c7903..52fc976a 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -28,6 +28,7 @@ import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothAdapter; import android.content.Intent; import android.content.Context; import android.os.Bundle; @@ -63,11 +64,6 @@ public class TelemetryService extends Service implements LocationListener { static final int MSG_CRC_ERROR = 9; static final int MSG_SETBAUD = 10; - public static final int STATE_NONE = 0; - public static final int STATE_READY = 1; - public static final int STATE_CONNECTING = 2; - public static final int STATE_CONNECTED = 3; - // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. private int NOTIFICATION = R.string.telemetry_service_label; @@ -81,21 +77,17 @@ public class TelemetryService extends Service implements LocationListener { final Messenger mMessenger = new Messenger(mHandler); // Target we publish for clients to send messages to IncomingHandler. // Name of the connected device - private BluetoothDevice device = null; + String address; private AltosBluetooth mAltosBluetooth = null; - private AltosConfigData mConfigData = null; private TelemetryReader mTelemetryReader = null; private TelemetryLogger mTelemetryLogger = null; + // Local Bluetooth adapter + private BluetoothAdapter mBluetoothAdapter = null; - // internally track state of bluetooth connection - private int state = STATE_NONE; + private TelemetryState telemetry_state; // 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 service; @@ -109,16 +101,8 @@ public class TelemetryService extends Service implements LocationListener { s.mClients.add(msg.replyTo); try { // 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)); - if (s.state == STATE_CONNECTED) { - msg.replyTo.send(s.frequency_message()); - msg.replyTo.send(s.telemetry_rate_message()); - } + // we're talking to + msg.replyTo.send(s.message()); } catch (RemoteException e) { s.mClients.remove(msg.replyTo); } @@ -130,8 +114,9 @@ public class TelemetryService extends Service implements LocationListener { break; case MSG_CONNECT: if (D) Log.d(TAG, "Connect command received"); - s.device = (BluetoothDevice) msg.obj; - s.startAltosBluetooth(); + String address = (String) msg.obj; + AltosDroidPreferences.set_active_device(address); + s.startAltosBluetooth(address); break; case MSG_CONNECTED: if (D) Log.d(TAG, "Connected to device"); @@ -142,43 +127,46 @@ public class TelemetryService extends Service implements LocationListener { break; case MSG_CONNECT_FAILED: if (D) Log.d(TAG, "Connection failed... retrying"); - s.startAltosBluetooth(); + if (s.address != null) + s.startAltosBluetooth(s.address); break; case MSG_DISCONNECTED: Log.d(TAG, "MSG_DISCONNECTED"); - // Only do the following if we haven't been shutdown elsewhere.. - if (s.device != null) { - if (D) Log.d(TAG, "Disconnected from " + s.device.getName()); - s.stopAltosBluetooth(); - } + s.stopAltosBluetooth(); break; case MSG_TELEMETRY: // forward telemetry messages - s.last_state = (AltosState) msg.obj; - s.sendMessageToClients(Message.obtain(null, AltosDroid.MSG_TELEMETRY, msg.obj)); + s.telemetry_state.state = (AltosState) msg.obj; + if (D) Log.d(TAG, "MSG_TELEMETRY"); + s.sendMessageToClients(); 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)); + s.telemetry_state.crc_errors = (Integer) msg.obj; + if (D) Log.d(TAG, "MSG_CRC_ERROR"); + s.sendMessageToClients(); break; case MSG_SETFREQUENCY: - if (s.state == STATE_CONNECTED) { + if (D) Log.d(TAG, "MSG_SETFREQUENCY"); + s.telemetry_state.frequency = (Double) msg.obj; + if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) { try { - s.mAltosBluetooth.set_radio_frequency((Double) msg.obj); + s.mAltosBluetooth.set_radio_frequency(s.telemetry_state.frequency); s.mAltosBluetooth.save_frequency(); - s.sendMessageToClients(s.frequency_message()); } catch (InterruptedException e) { } catch (TimeoutException e) { } } + s.sendMessageToClients(); break; case MSG_SETBAUD: - if (s.state == STATE_CONNECTED) { - s.mAltosBluetooth.set_telemetry_rate((Integer) msg.obj); + if (D) Log.d(TAG, "MSG_SETBAUD"); + s.telemetry_state.telemetry_rate = (Integer) msg.obj; + if (s.telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) { + s.mAltosBluetooth.set_telemetry_rate(s.telemetry_state.telemetry_rate); s.mAltosBluetooth.save_telemetry_rate(); - s.sendMessageToClients(s.telemetry_rate_message()); } + s.sendMessageToClients(); break; default: super.handleMessage(msg); @@ -186,9 +174,18 @@ public class TelemetryService extends Service implements LocationListener { } } - private void sendMessageToClients(Message m) { + private Message message() { + if (telemetry_state == null) + Log.d(TAG, "telemetry_state null!"); + return Message.obtain(null, AltosDroid.MSG_STATE, telemetry_state); + } + + private void sendMessageToClients() { + Message m = message(); + if (D) Log.d(TAG, String.format("Send message to %d clients", mClients.size())); for (int i=mClients.size()-1; i>=0; i--) { try { + if (D) Log.d(TAG, String.format("Send message to client %d", i)); mClients.get(i).send(m); } catch (RemoteException e) { mClients.remove(i); @@ -196,19 +193,9 @@ public class TelemetryService extends Service implements LocationListener { } } - private Message frequency_message() { - if (D) Log.d(TAG, String.format("frequency_message %f\n", mAltosBluetooth.frequency())); - return Message.obtain(null, AltosDroid.MSG_FREQUENCY, mAltosBluetooth.frequency()); - } - - private Message telemetry_rate_message() { - if (D) Log.d(TAG, String.format("telemetry_rate_message %d\n", mAltosBluetooth.telemetry_rate())); - return Message.obtain(null, AltosDroid.MSG_TELEMETRY_RATE, mAltosBluetooth.telemetry_rate()); - } - private void stopAltosBluetooth() { if (D) Log.d(TAG, "stopAltosBluetooth(): begin"); - setState(STATE_READY); + telemetry_state.connect = TelemetryState.CONNECT_READY; if (mTelemetryReader != null) { if (D) Log.d(TAG, "stopAltosBluetooth(): stopping TelemetryReader"); mTelemetryReader.interrupt(); @@ -228,18 +215,21 @@ public class TelemetryService extends Service implements LocationListener { mAltosBluetooth.close(); mAltosBluetooth = null; } - device = null; - mConfigData = null; + telemetry_state.config = null; + if (D) Log.d(TAG, "stopAltosBluetooth(): send message to clients"); + sendMessageToClients(); } - private void startAltosBluetooth() { - if (device == null) { - return; - } + private void startAltosBluetooth(String address) { + // Get the BLuetoothDevice object + BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); + + this.address = address; if (mAltosBluetooth == null) { if (D) Log.d(TAG, String.format("startAltosBluetooth(): Connecting to %s (%s)", device.getName(), device.getAddress())); mAltosBluetooth = new AltosBluetooth(device, mHandler); - setState(STATE_CONNECTING); + telemetry_state.connect = TelemetryState.CONNECT_CONNECTING; + sendMessageToClients(); } else { // This is a bit of a hack - if it appears we're still connected, we treat this as a restart. // So, to give a suitable delay to teardown/bringup, we just schedule a resend of a message @@ -247,30 +237,19 @@ public class TelemetryService extends Service implements LocationListener { // ... then we tear down the existing connection. // We do it this way around so that we don't lose a reference to the device when this method // is called on reception of MSG_CONNECT_FAILED in the handler above. - mHandler.sendMessageDelayed(Message.obtain(null, MSG_CONNECT, device), 3000); + mHandler.sendMessageDelayed(Message.obtain(null, MSG_CONNECT, address), 3000); stopAltosBluetooth(); } } - private synchronized void setState(int s) { - if (D) Log.d(TAG, "setState(): " + state + " -> " + s); - state = s; - - // This shouldn't be required - mConfigData should be null for any non-connected - // state, but to be safe and to reduce message size - AltosConfigData acd = (state == STATE_CONNECTED) ? mConfigData : null; - - sendMessageToClients(Message.obtain(null, AltosDroid.MSG_STATE_CHANGE, state, -1, acd)); - } - private void connected() throws InterruptedException { + if (D) Log.d(TAG, "connected top"); try { if (mAltosBluetooth == null) throw new InterruptedException("no bluetooth"); - mConfigData = mAltosBluetooth.config_data(); - if (D) Log.d(TAG, "send frequency/rate messages\n"); - sendMessageToClients(frequency_message()); - sendMessageToClients(telemetry_rate_message()); + telemetry_state.config = mAltosBluetooth.config_data(); + mAltosBluetooth.set_radio_frequency(telemetry_state.frequency); + mAltosBluetooth.set_telemetry_rate(telemetry_state.telemetry_rate); } catch (TimeoutException e) { // If this timed out, then we really want to retry it, but // probably safer to just retry the connection from scratch. @@ -278,21 +257,25 @@ public class TelemetryService extends Service implements LocationListener { return; } - setState(STATE_CONNECTED); + if (D) Log.d(TAG, "connected bluetooth configured"); + telemetry_state.connect = TelemetryState.CONNECT_CONNECTED; mTelemetryReader = new TelemetryReader(mAltosBluetooth, mHandler); mTelemetryReader.start(); + if (D) Log.d(TAG, "connected TelemetryReader started"); + mTelemetryLogger = new TelemetryLogger(this, mAltosBluetooth); - sendMessageToClients(frequency_message()); - sendMessageToClients(telemetry_rate_message()); + if (D) Log.d(TAG, "Notify UI of connection"); + + sendMessageToClients(); } private void onTimerTick() { if (D) Log.d(TAG, "Timer wakeup"); try { - if (mClients.size() <= 0 && state != STATE_CONNECTED) { + if (mClients.size() <= 0 && telemetry_state.connect != TelemetryState.CONNECT_CONNECTED) { stopSelf(); } } catch (Throwable t) { @@ -303,19 +286,35 @@ public class TelemetryService extends Service implements LocationListener { @Override public void onCreate() { + // Get local Bluetooth adapter + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + + // If the adapter is null, then Bluetooth is not supported + if (mBluetoothAdapter == null) { + Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show(); + } + + // Initialise preferences + AltosDroidPreferences.init(this); + + telemetry_state = new TelemetryState(); + // Create a reference to the NotificationManager so that we can update our notifcation text later //mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); - setState(STATE_READY); + telemetry_state.connect = TelemetryState.CONNECT_READY; // 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, 1000, 1, this); -// locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); + + String address = AltosDroidPreferences.active_device(); + if (address != null) + startAltosBluetooth(address); } @Override @@ -371,8 +370,9 @@ public class TelemetryService extends Service implements LocationListener { public void onLocationChanged(Location location) { - last_location = location; - sendMessageToClients(Message.obtain(null, AltosDroid.MSG_LOCATION, location)); + telemetry_state.location = location; + if (D) Log.d(TAG, "location changed"); + sendMessageToClients(); } public void onStatusChanged(String provider, int status, Bundle extras) { -- cgit v1.2.3 From 18671803d078aa798b603c67b741c3ba4374f41d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 6 Sep 2014 00:14:26 -0700 Subject: altosdroid: Add imperial unit support Provides a menu entry to switch units, changes all value displays to use the AltosLib units conversion code. Signed-off-by: Keith Packard --- altosdroid/Notebook | 2 ++ altosdroid/res/menu/option_menu.xml | 3 +++ altosdroid/res/values/strings.xml | 1 + .../src/org/altusmetrum/AltosDroid/AltosDroid.java | 19 ++++++++++++++- .../AltosDroid/AltosDroidPreferences.java | 3 +++ .../org/altusmetrum/AltosDroid/AltosDroidTab.java | 27 ++++++++++++++++------ .../src/org/altusmetrum/AltosDroid/AltosVoice.java | 18 ++++++++------- .../src/org/altusmetrum/AltosDroid/TabAscent.java | 13 ++++++----- .../src/org/altusmetrum/AltosDroid/TabDescent.java | 8 +++---- .../src/org/altusmetrum/AltosDroid/TabLanded.java | 11 ++++----- .../src/org/altusmetrum/AltosDroid/TabMap.java | 2 +- .../src/org/altusmetrum/AltosDroid/TabPad.java | 4 ++-- altoslib/AltosPreferences.java | 4 ++++ 13 files changed, 79 insertions(+), 36 deletions(-) (limited to 'altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java') diff --git a/altosdroid/Notebook b/altosdroid/Notebook index ebb3578d..e6116836 100644 --- a/altosdroid/Notebook +++ b/altosdroid/Notebook @@ -29,4 +29,6 @@ Desired AltosDroid feature list *) Imperial Units mode + Done + *) TeleBT battery voltage diff --git a/altosdroid/res/menu/option_menu.xml b/altosdroid/res/menu/option_menu.xml index 4321d6e7..3bd5a54e 100644 --- a/altosdroid/res/menu/option_menu.xml +++ b/altosdroid/res/menu/option_menu.xml @@ -26,4 +26,7 @@ + diff --git a/altosdroid/res/values/strings.xml b/altosdroid/res/values/strings.xml index 6ea9fec2..0cc99349 100644 --- a/altosdroid/res/values/strings.xml +++ b/altosdroid/res/values/strings.xml @@ -30,6 +30,7 @@ Quit Select radio frequency Select data rate + Change units scanning for devices… diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index d276798e..f6cceac9 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -54,7 +54,7 @@ import android.location.Location; import org.altusmetrum.altoslib_5.*; -public class AltosDroid extends FragmentActivity { +public class AltosDroid extends FragmentActivity implements AltosUnitsListener { // Debugging static final String TAG = "AltosDroid"; static final boolean D = true; @@ -187,6 +187,11 @@ public class AltosDroid extends FragmentActivity { mTabs.remove(mTab); } + public void units_changed(boolean imperial_units) { + for (AltosDroidTab mTab : mTabs) + mTab.units_changed(imperial_units); + } + void update_title(TelemetryState telemetry_state) { switch (telemetry_state.connect) { case TelemetryState.CONNECT_CONNECTED: @@ -226,7 +231,15 @@ public class AltosDroid extends FragmentActivity { } } + boolean registered_units_listener; + void update_state(TelemetryState telemetry_state) { + + if (!registered_units_listener) { + registered_units_listener = true; + AltosPreferences.register_units_listener(this); + } + update_title(telemetry_state); update_ui(telemetry_state.state, telemetry_state.location); if (telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) @@ -656,6 +669,10 @@ public class AltosDroid extends FragmentActivity { AlertDialog alert_rate = builder_rate.create(); alert_rate.show(); return true; + case R.id.change_units: + boolean imperial = AltosPreferences.imperial_units(); + AltosPreferences.set_imperial_units(!imperial); + return true; } return false; } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java index 72b8488b..9cef1319 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java @@ -27,6 +27,9 @@ public class AltosDroidPreferences extends AltosPreferences { static String active_device_address; public static void init(Context context) { + if (backend != null) + return; + AltosPreferences.init(new AltosDroidPreferencesBackend(context)); active_device_address = backend.getString(activeDevicePreference, null); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java index 7b5b01b3..8e625da6 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java @@ -27,8 +27,9 @@ import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentManager; import android.location.Location; import android.util.Log; +import android.widget.TextView; -public abstract class AltosDroidTab extends Fragment { +public abstract class AltosDroidTab extends Fragment implements AltosUnitsListener { AltosState last_state; AltosGreatCircle last_from_receiver; Location last_receiver; @@ -37,6 +38,21 @@ public abstract class AltosDroidTab extends Fragment { public abstract String tab_name(); + public void units_changed(boolean imperial_units) { + if (!isHidden() && last_state != null) + show(last_state, last_from_receiver, last_receiver); + } + + public void set_value(TextView text_view, + AltosUnits units, + int width, + double value) { + if (value == AltosLib.MISSING) + text_view.setText(""); + else + text_view.setText(units.show(width, value)); + } + public void set_visible(boolean visible) { FragmentTransaction ft = AltosDroid.fm.beginTransaction(); if (visible) { @@ -44,9 +60,6 @@ public abstract class AltosDroidTab extends Fragment { AltosGreatCircle from_receiver = last_from_receiver; Location receiver = last_receiver; - last_state = null; - last_from_receiver = null; - last_receiver = null; show(state, from_receiver, receiver); ft.show(this); } else @@ -55,15 +68,15 @@ public abstract class AltosDroidTab extends Fragment { } public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver, boolean is_current) { + last_state = state; + last_from_receiver = from_receiver; + last_receiver = receiver; if (is_current) { if (AltosDroid.D) Log.d(AltosDroid.TAG, String.format("%s: visible, performing update", tab_name())); show(state, from_receiver, receiver); } else { if (AltosDroid.D) Log.d(AltosDroid.TAG, String.format("%s: not visible, skipping update", tab_name())); - last_state = state; - last_from_receiver = from_receiver; - last_receiver = receiver; return; } } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java index b8def367..969992d3 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java @@ -68,12 +68,14 @@ public class AltosVoice { if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) && state.state > AltosLib.ao_flight_boost) { if (state.max_speed() != AltosLib.MISSING) - speak(String.format("max speed: %d meters per second.", (int) (state.max_speed() + 0.5))); + speak(String.format("Max speed: %s.", + AltosConvert.speed.say_units(state.max_speed()))); spoke = true; } else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) && state.state >= AltosLib.ao_flight_drogue) { if (state.max_height() != AltosLib.MISSING) - speak(String.format("max height: %d meters.", (int) (state.max_height() + 0.5))); + speak(String.format("Max height: %s.", + AltosConvert.height.say_units(state.max_height()))); spoke = true; } } @@ -126,17 +128,17 @@ public class AltosVoice { position = state.from_pad; if (position != null) { - speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n", - (int) (state.height() + 0.5), + speak(String.format("Height %s, bearing %s %d, elevation %d, range %s.\n", + AltosConvert.height.say_units(state.height()), position.bearing_words( AltosGreatCircle.BEARING_VOICE), (int) (position.bearing + 0.5), (int) (position.elevation + 0.5), - (int) (position.range + 0.5))); + AltosConvert.distance.say_units(position.range))); } } else if (state.state > AltosLib.ao_flight_pad) { if (state.height() != AltosLib.MISSING) - speak(String.format("%d meters", (int) (state.height() + 0.5))); + speak(AltosConvert.height.say_units(state.height())); } else { reported_landing = 0; } @@ -155,9 +157,9 @@ public class AltosVoice { else speak("rocket may have crashed"); if (state.from_pad != null) - speak(String.format("Bearing %d degrees, range %d meters.", + speak(String.format("Bearing %d degrees, range %s.", (int) (state.from_pad.bearing + 0.5), - (int) (state.from_pad.distance + 0.5))); + AltosConvert.distance.say_units(state.from_pad.distance))); ++reported_landing; } } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java index c146c277..fa4e3c8b 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java @@ -91,12 +91,13 @@ public class TabAscent extends AltosDroidTab { public void show(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())); + set_value(mHeightView, AltosConvert.height, 6, state.height()); + set_value(mHeightView, AltosConvert.height, 6, state.height()); + set_value(mMaxHeightView, AltosConvert.height, 6, state.max_height()); + set_value(mSpeedView, AltosConvert.speed, 6, state.speed()); + set_value(mMaxSpeedView, AltosConvert.speed, 6, state.max_speed()); + set_value(mAccelView, AltosConvert.accel, 6, state.acceleration()); + set_value(mMaxAccelView, AltosConvert.accel, 6, state.max_acceleration()); if (state.gps != null) { mLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S")); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java index 6d781efd..28068666 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java @@ -93,14 +93,14 @@ public class TabDescent extends AltosDroidTab { public void show(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())); + set_value(mSpeedView, AltosConvert.speed, 6, state.speed()); + set_value(mHeightView, AltosConvert.height, 6, 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)); + set_value(mRangeView, AltosConvert.distance, 6, 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)); + set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance); } else { mElevationView.setText(""); mRangeView.setText(""); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java index 32c235e1..b257b936 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java @@ -78,7 +78,7 @@ public class TabLanded extends AltosDroidTab { public void show(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)); + set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance); } if (state != null && state.gps != null) { mTargetLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S")); @@ -91,12 +91,9 @@ public class TabLanded extends AltosDroidTab { } if (state != null) { - mMaxHeightView.setText(String.format("%6.0f m", state.max_height())); - if (state.max_acceleration() != AltosLib.MISSING) - mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration())); - else - mMaxAccelView.setText("missing"); - mMaxSpeedView.setText(String.format("%6.0f m/s", state.max_speed())); + set_value(mMaxHeightView, AltosConvert.height, 6, state.max_height()); + set_value(mMaxAccelView, AltosConvert.accel, 6, state.max_acceleration()); + set_value(mMaxSpeedView, AltosConvert.speed, 6, state.max_speed()); } } } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java index 811e5482..ab338ac2 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java @@ -158,7 +158,7 @@ public class TabMap extends AltosDroidTab { public void show(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)); + set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance); } if (state != null) { diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java index 1068fa46..32df71d7 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java @@ -159,12 +159,12 @@ public class TabPad extends AltosDroidTab { } if (receiver != null) { - double altitude = 0; + double altitude = AltosLib.MISSING; 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)); + set_value(mPadAltitudeView, AltosConvert.height, 6, altitude); } } diff --git a/altoslib/AltosPreferences.java b/altoslib/AltosPreferences.java index af87b213..dba57dcb 100644 --- a/altoslib/AltosPreferences.java +++ b/altoslib/AltosPreferences.java @@ -157,6 +157,10 @@ public class AltosPreferences { public static int launcher_channel; public static void init(AltosPreferencesBackend in_backend) { + + if (backend != null) + return; + backend = in_backend; /* Initialize logdir from preferences */ -- cgit v1.2.3