altosui: Add config and pyro tabs to graph widget
[fw/altos] / altosdroid / app / src / main / java / org / altusmetrum / AltosDroid / AltosDroid.java
index e564e78478612742fe29eb5112bc16eb77f5c7a5..6d70872123954b1a88ba3fc3b897529e9b4da9f8 100644 (file)
@@ -20,6 +20,7 @@ package org.altusmetrum.AltosDroid;
 
 import java.lang.ref.WeakReference;
 import java.util.*;
+import java.io.*;
 
 import android.Manifest;
 import android.app.Activity;
@@ -86,6 +87,7 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
        public static final int MSG_UPDATE_AGE      = 2;
        public static final int MSG_IDLE_MODE       = 3;
        public static final int MSG_IGNITER_STATUS  = 4;
+       public static final int MSG_FILE_FAILED     = 5;
 
        // Intent request codes
        public static final int REQUEST_CONNECT_DEVICE = 1;
@@ -190,19 +192,23 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
                                ad.idle_mode = (Boolean) msg.obj;
                                ad.update_state(null);
                                break;
+                       case MSG_FILE_FAILED:
+                               ad.file_failed((File) msg.obj);
+                               break;
                        }
                }
        };
 
-
        private ServiceConnection mConnection = new ServiceConnection() {
                public void onServiceConnected(ComponentName className, IBinder service) {
+                       AltosDebug.debug("onServiceConnected\n");
                        mService = new Messenger(service);
                        try {
                                Message msg = Message.obtain(null, TelemetryService.MSG_REGISTER_CLIENT);
                                msg.replyTo = mMessenger;
                                mService.send(msg);
                        } catch (RemoteException e) {
+                               AltosDebug.debug("attempt to register telemetry service client failed\n");
                                // In this case the service has crashed before we could even do anything with it
                        }
                        if (pending_usb_device != null) {
@@ -215,17 +221,20 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
                }
 
                public void onServiceDisconnected(ComponentName className) {
+                       AltosDebug.debug("onServiceDisconnected\n");
                        // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
                        mService = null;
                }
        };
 
        void doBindService() {
+               AltosDebug.debug("doBindService\n");
                bindService(new Intent(this, TelemetryService.class), mConnection, Context.BIND_AUTO_CREATE);
                mIsBound = true;
        }
 
        void doUnbindService() {
+               AltosDebug.debug("doUnbindService\n");
                if (mIsBound) {
                        // If we have received the service, and hence registered with it, then now is the time to unregister.
                        if (mService != null) {
@@ -243,6 +252,13 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
                }
        }
 
+       public AltosDroidTab findTab(String name) {
+               for (AltosDroidTab mTab : mTabs)
+                       if (name.equals(mTab.tab_name()))
+                               return mTab;
+               return null;
+       }
+
        public void registerTab(AltosDroidTab mTab) {
                mTabs.add(mTab);
        }
@@ -436,6 +452,12 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
 
        void update_ui(TelemetryState telem_state, AltosState state, boolean quiet) {
 
+               AltosDebug.debug("update_ui telem %b state %b quiet %b saved_state %b\n",
+                                telem_state != null,
+                                state != null,
+                                quiet,
+                                saved_state != null);
+
                this.state = state;
 
                int prev_state = AltosLib.ao_flight_invalid;
@@ -525,8 +547,11 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
                        saved_state = new SavedState(state);
                }
 
-               for (AltosDroidTab mTab : mTabs)
+               for (AltosDroidTab mTab : mTabs) {
+                       AltosDebug.debug("mTab %s current %s\n",
+                                        mTab, mTabsAdapter.currentItem());
                        mTab.update_ui(telem_state, state, from_receiver, location, mTab == mTabsAdapter.currentItem());
+               }
 
                if (mAltosVoice != null && mTabsAdapter.currentItem() != null)
                        mAltosVoice.tell(telem_state, state, from_receiver, location, (AltosDroidTab) mTabsAdapter.currentItem(), quiet);
@@ -589,13 +614,13 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
 
        @Override
        public void onCreate(Bundle savedInstanceState) {
+               AltosDebug.init(this);
+               AltosDebug.debug("+++ ON CREATE +++");
+
                // Initialise preferences
                AltosDroidPreferences.init(this);
                setTheme(themes[AltosDroidPreferences.font_size()]);
                super.onCreate(savedInstanceState);
-               AltosDebug.init(this);
-               AltosDebug.debug("+++ ON CREATE +++");
-
 
                fm = getSupportFragmentManager();
 
@@ -611,10 +636,10 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
 
                mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);
 
-               mTabsAdapter.addTab(mTabHost.newTabSpec(tab_pad_name).setIndicator(create_tab_view("Pad")), TabPad.class, null);
-               mTabsAdapter.addTab(mTabHost.newTabSpec(tab_flight_name).setIndicator(create_tab_view("Flight")), TabFlight.class, null);
-               mTabsAdapter.addTab(mTabHost.newTabSpec(tab_recover_name).setIndicator(create_tab_view("Recover")), TabRecover.class, null);
-               mTabsAdapter.addTab(mTabHost.newTabSpec(tab_map_name).setIndicator(create_tab_view("Map")), TabMap.class, null);
+               mTabsAdapter.addTab(mTabHost.newTabSpec(tab_pad_name).setIndicator(create_tab_view("Pad")), TabPad.class, null, findTab(tab_pad_name));
+               mTabsAdapter.addTab(mTabHost.newTabSpec(tab_flight_name).setIndicator(create_tab_view("Flight")), TabFlight.class, null, findTab(tab_flight_name));
+               mTabsAdapter.addTab(mTabHost.newTabSpec(tab_recover_name).setIndicator(create_tab_view("Recover")), TabRecover.class, null, findTab(tab_recover_name));
+               mTabsAdapter.addTab(mTabHost.newTabSpec(tab_map_name).setIndicator(create_tab_view("Map")), TabMap.class, null, findTab(tab_map_name));
 
                // Display the Version
                mVersion = (TextView) findViewById(R.id.version);
@@ -630,7 +655,7 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
                mStateView     = (TextView) findViewById(R.id.state_value);
                mAgeView       = (TextView) findViewById(R.id.age_value);
                mAgeNewColor   = mAgeView.getTextColors().getDefaultColor();
-               mAgeOldColor   = getResources().getColor(R.color.old_color, getTheme());
+               mAgeOldColor   = getResources().getColor(R.color.old_color);
        }
 
        private void ensureBluetooth() {
@@ -649,7 +674,13 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
 
                if (device != null) {
                        Intent          i = new Intent(this, AltosDroid.class);
-                       PendingIntent   pi = PendingIntent.getActivity(this, 0, new Intent("hello world", null, this, AltosDroid.class), 0);
+                       int             flag;
+
+                       if (android.os.Build.VERSION.SDK_INT >= 31) // android.os.Build.VERSION_CODES.S
+                               flag = 33554432; // PendingIntent.FLAG_MUTABLE
+                       else
+                               flag = 0;
+                       PendingIntent   pi = PendingIntent.getActivity(this, 0, new Intent("hello world", null, this, AltosDroid.class), flag);
 
                        if (AltosUsb.request_permission(this, device, pi)) {
                                connectUsb(device);
@@ -735,31 +766,47 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
        @Override
        public void onNewIntent(Intent intent) {
                super.onNewIntent(intent);
-               AltosDebug.debug("onNewIntent");
+               AltosDebug.debug("+ ON NEW INTENT +");
                noticeIntent(intent);
        }
 
-       private void enable_location_updates() {
+       private void enable_location_updates(boolean do_update) {
                // Listen for GPS and Network position updates
                LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
-               locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
 
-               location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+               if (locationManager != null)
+               {
+                       try {
+                               locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
+                               location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+                       } catch (Exception e) {
+                               locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1, this);
+                               location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+                       }
 
-               if (location != null)
-                       AltosDebug.debug("Resume, location is %f,%f\n",
-                                        location.getLatitude(),
-                                        location.getLongitude());
+                       if (location != null)
+                               AltosDebug.debug("Resume, location is %f,%f\n",
+                                                location.getLatitude(),
+                                                location.getLongitude());
+                       AltosDebug.debug("Failed to get GPS updates\n");
+               }
 
-               update_ui(telemetry_state, state, true);
+               if (do_update)
+                       update_ui(telemetry_state, state, true);
        }
 
        static final int MY_PERMISSION_REQUEST = 1001;
 
        public boolean have_location_permission = false;
        public boolean have_storage_permission = false;
+       public boolean have_bluetooth_permission = false;
+       public boolean have_bluetooth_connect_permission = false;
+       public boolean have_bluetooth_scan_permission = false;
        public boolean asked_permission = false;
 
+       static final String BLUETOOTH_CONNECT = "android.permission.BLUETOOTH_CONNECT";
+       static final String BLUETOOTH_SCAN = "android.permission.BLUETOOTH_SCAN";
+
        AltosMapOnline map_online;
 
        void
@@ -775,13 +822,22 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
                                if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                                        if (permissions[i].equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
                                                have_location_permission = true;
-                                               enable_location_updates();
+                                               enable_location_updates(true);
                                                if (map_online != null)
                                                        map_online.position_permission();
                                        }
                                        if (permissions[i].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                                                have_storage_permission = true;
                                        }
+                                       if (permissions[i].equals(Manifest.permission.BLUETOOTH)) {
+                                               have_bluetooth_permission = true;
+                                       }
+                                       if (permissions[i].equals(BLUETOOTH_CONNECT)) {
+                                               have_bluetooth_connect_permission = true;
+                                       }
+                                       if (permissions[i].equals(BLUETOOTH_SCAN)) {
+                                               have_bluetooth_scan_permission = true;
+                                       }
                                }
                        }
                }
@@ -789,9 +845,10 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
 
        @Override
        public void onResume() {
-               super.onResume();
                AltosDebug.debug("+ ON RESUME +");
 
+               super.onResume();
+
                if (!asked_permission) {
                        asked_permission = true;
                        if (ActivityCompat.checkSelfPermission(this,
@@ -806,26 +863,62 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
                        {
                                have_storage_permission = true;
                        }
-                       int count = (have_location_permission ? 0 : 1) + (have_storage_permission ? 0 : 1);
+                       if (ActivityCompat.checkSelfPermission(this,
+                                                              Manifest.permission.BLUETOOTH)
+                           == PackageManager.PERMISSION_GRANTED)
+                       {
+                               have_bluetooth_permission = true;
+                       }
+                       if (ActivityCompat.checkSelfPermission(this,
+                                                              BLUETOOTH_CONNECT)
+                           == PackageManager.PERMISSION_GRANTED)
+                       {
+                               have_bluetooth_connect_permission = true;
+                       }
+                       if (ActivityCompat.checkSelfPermission(this,
+                                                              BLUETOOTH_SCAN)
+                           == PackageManager.PERMISSION_GRANTED)
+                       {
+                               have_bluetooth_scan_permission = true;
+                       }
+                       int count = 0;
+                       if (!have_location_permission)
+                               count += 1;
+                       if (!have_storage_permission)
+                               count += 1;
+                       if (!have_bluetooth_permission)
+                               count += 1;
+                       if (!have_bluetooth_connect_permission)
+                               count += 1;
+                       if (!have_bluetooth_scan_permission)
+                               count += 1;
                        if (count > 0)
                        {
                                String[] permissions = new String[count];
                                int i = 0;
                                if (!have_location_permission)
                                        permissions[i++] = Manifest.permission.ACCESS_FINE_LOCATION;
-                               if (!have_location_permission)
+                               if (!have_storage_permission)
                                        permissions[i++] = Manifest.permission.WRITE_EXTERNAL_STORAGE;
+                               if (!have_bluetooth_permission)
+                                       permissions[i++] = Manifest.permission.BLUETOOTH;
+                               if (!have_bluetooth_connect_permission)
+                                       permissions[i++] = BLUETOOTH_CONNECT;
+                               if (!have_bluetooth_scan_permission)
+                                       permissions[i++] = BLUETOOTH_SCAN;
                                ActivityCompat.requestPermissions(this, permissions, MY_PERMISSION_REQUEST);
                        }
                }
                if (have_location_permission)
-                       enable_location_updates();
+                       enable_location_updates(false);
        }
 
        @Override
        public void onPause() {
-               super.onPause();
                AltosDebug.debug("- ON PAUSE -");
+
+               super.onPause();
+
                // Stop listening for location updates
                if (have_location_permission)
                        ((LocationManager) getSystemService(Context.LOCATION_SERVICE)).removeUpdates(this);
@@ -833,15 +926,19 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
 
        @Override
        public void onStop() {
-               super.onStop();
                AltosDebug.debug("-- ON STOP --");
+
+               super.onStop();
        }
 
        @Override
        public void onDestroy() {
-               super.onDestroy();
                AltosDebug.debug("--- ON DESTROY ---");
 
+               super.onDestroy();
+
+               saved_state = null;
+
                doUnbindService();
                if (mAltosVoice != null) {
                        mAltosVoice.stop();
@@ -1001,6 +1098,24 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener,
                }
        }
 
+       boolean fail_shown;
+
+       private void file_failed(File file) {
+               if (!fail_shown) {
+                       fail_shown = true;
+                       AlertDialog fail = new AlertDialog.Builder(this).create();
+                       fail.setTitle("Failed to Create Log File");
+                       fail.setMessage(file.getPath());
+                       fail.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
+                                      new DialogInterface.OnClickListener() {
+                                              public void onClick(DialogInterface dialog, int which) {
+                                                      dialog.dismiss();
+                                              }
+                                      });
+                       fail.show();
+               }
+       }
+
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
                MenuInflater inflater = getMenuInflater();