altosdroid: Skip updating hidden UI elements
authorKeith Packard <keithp@keithp.com>
Mon, 18 Aug 2014 03:48:23 +0000 (20:48 -0700)
committerKeith Packard <keithp@keithp.com>
Mon, 18 Aug 2014 03:48:23 +0000 (20:48 -0700)
Instead of updating everything in the UI, only update the visible UI
elements to save a bunch of computation.

Signed-off-by: Keith Packard <keithp@keithp.com>
altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java
altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java
altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
altosdroid/src/org/altusmetrum/AltosDroid/TabsAdapter.java

index a599698faaeb3f37604e23591957e9ab559f675f..484efaf833a6ee4ad2e41ddc13e771d60473e82f 100644 (file)
@@ -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() {
index 563ccd5a69749398e4b7f3bd3764f1475269eb39..c9c38d9819a6e7ac798d3a12a800fdcf93dfe300 100644 (file)
@@ -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();
 
index 20593bd550996d4467ea0e45d36fd723d0cff5d8..b960eb1a2a7d5c5e81f93e75d3640e049bace381 100644 (file)
@@ -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);
+               }
+       }
 }
index 147405f6affd58fb23091181844dda6ec3373044..b05913b68140ce1224f6c028bd3cba3ff4d304fa 100644 (file)
@@ -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)));
index cb9fd5c8dfb27bd484cc8f80499065dcff93ec5f..c146c27746d274dbde683582fff5dc9ee56064fa 100644 (file)
@@ -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()));
index 2171afa461cc62f310b2531a1c387a891b873b94..6d781efd36a3e43dbde3988d02227c33cc302d39 100644 (file)
@@ -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()));
index 47e41d5981350e5bc2c940803eeb27e0568d9a76..16427d8b19204f9d3445007e9504441929472475 100644 (file)
@@ -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()));
                }
        }
-
 }
index 15dc8bf7de029f9437720807fc53ea580a570c23..811e5482bcb442595d36777c9f820355a430ed31 100644 (file)
@@ -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 {
                }
 
        }
-
 }
index 175a41de107ef5abd4716f3622a1c157e1d17ff9..03b78b75dbf29a0cfa9e24b766358bee9d388853 100644 (file)
@@ -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);
index a4758c376a4586df2e093ccda740c71bf895ea21..1ac34f9d5590ea5a2c0b8a16b030b9a9df5ba8fe 100644 (file)
@@ -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<TabInfo> mTabs = new ArrayList<TabInfo>();
+       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);
        }