altosdroid: Select tracker by clicking on map
authorKeith Packard <keithp@keithp.com>
Tue, 23 Jun 2015 03:08:05 +0000 (20:08 -0700)
committerKeith Packard <keithp@keithp.com>
Tue, 23 Jun 2015 04:04:43 +0000 (21:04 -0700)
This lets you pick a  tracker from the map, rather than having to use
the menu.

Signed-off-by: Keith Packard <keithp@keithp.com>
altosdroid/Notebook
altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidMapInterface.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosMapOffline.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosMapOnline.java
altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java
altoslib/AltosMap.java
altoslib/AltosMapInterface.java
altoslib/AltosMapTransform.java
altosuilib/AltosUIMapNew.java

index c0ba209..6804aa5 100644 (file)
@@ -15,14 +15,6 @@ Desired AltosDroid feature list
 
  *) Monitor-idle mode
 
- *) Select tracker by clicking map
-
- *) Auto select tracker after long delay
-
- *) Evaluate performance issues
-
- *) Merge offline/online maps into single tab with mode
-
  *) Make voice responses depend on selected tab
 
  *) Monitor TeleMega igniters
@@ -96,3 +88,19 @@ Completed features
  *) TeleBT battery voltage
 
        Done
+
+ *) Evaluate performance issues
+
+       Done. Offline maps were duplicating tabs at every redisplay.
+
+ *) Merge offline/online maps into single tab with mode
+
+       Done.
+
+ *) Auto select tracker after long delay
+
+       Done.
+
+ *) Select tracker by clicking map
+
+       Done.
index f664510..c5da6d0 100644 (file)
 package org.altusmetrum.AltosDroid;
 
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.text.*;
+import java.util.*;
+import java.io.*;
 
 import android.app.Activity;
 import android.app.PendingIntent;
@@ -248,11 +247,13 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {
                }
        }
 
+       int     selected_serial = 0;
        int     current_serial;
        long    switch_time;
 
        void set_switch_time() {
                switch_time = System.currentTimeMillis();
+               selected_serial = 0;
        }
 
        boolean registered_units_listener;
@@ -262,6 +263,9 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {
                if (new_telemetry_state != null)
                        telemetry_state = new_telemetry_state;
 
+               if (selected_serial != 0)
+                       current_serial = selected_serial;
+
                if (current_serial == 0)
                        current_serial = telemetry_state.latest_serial;
 
@@ -271,6 +275,7 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {
                }
 
                serials = telemetry_state.states.keySet().toArray(new Integer[0]);
+               Arrays.sort(serials);
 
                update_title(telemetry_state);
 
@@ -282,7 +287,9 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {
                        int age = state_age(state);
                        if (age < 20)
                                aged = false;
-                       if (switch_time != 0 && (switch_time - state.received_time) > 0)
+                       if (current_serial == selected_serial)
+                               aged = false;
+                       else if (switch_time != 0 && (switch_time - state.received_time) > 0)
                                aged = true;
                }
 
@@ -828,13 +835,26 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {
 
        void select_tracker(int serial) {
                int i;
-               for (i = 0; i < serials.length; i++)
-                       if (serials[i] == serial)
-                               break;
-               if (i == serials.length)
+
+               AltosDebug.debug("select tracker %d\n", serial);
+
+               if (serial == selected_serial) {
+                       AltosDebug.debug("%d already selected\n", serial);
                        return;
+               }
+
+               if (serial != 0) {
+                       for (i = 0; i < serials.length; i++)
+                               if (serials[i] == serial)
+                                       break;
 
-               current_serial = serial;
+                       if (i == serials.length) {
+                               AltosDebug.debug("attempt to select unknown tracker %d\n", serial);
+                               return;
+                       }
+               }
+
+               current_serial = selected_serial = serial;
                update_state(null);
        }
 
@@ -933,15 +953,19 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {
                        return true;
                case R.id.select_tracker:
                        if (serials != null) {
-                               String[] trackers = new String[serials.length];
+                               String[] trackers = new String[serials.length+1];
+                               trackers[0] = "Auto";
                                for (int i = 0; i < serials.length; i++)
-                                       trackers[i] = String.format("%d", serials[i]);
+                                       trackers[i+1] = String.format("%d", serials[i]);
                                AlertDialog.Builder builder_serial = new AlertDialog.Builder(this);
                                builder_serial.setTitle("Select a tracker");
                                builder_serial.setItems(trackers,
                                                        new DialogInterface.OnClickListener() {
                                                                public void onClick(DialogInterface dialog, int item) {
-                                                                       select_tracker(serials[item]);
+                                                                       if (item == 0)
+                                                                               select_tracker(0);
+                                                                       else
+                                                                               select_tracker(serials[item-1]);
                                                                }
                                                        });
                                AlertDialog alert_serial = builder_serial.create();
index 681cd31..7aff134 100644 (file)
@@ -23,7 +23,7 @@ import android.location.Location;
 import org.altusmetrum.altoslib_7.*;
 
 public interface AltosDroidMapInterface {
-       public void onCreateView(int map_type);
+       public void onCreateView(AltosDroid altos_droid);
 
        public void set_visible(boolean visible);
 
index 3ff6ff2..12dd2f2 100644 (file)
@@ -36,7 +36,9 @@ import android.util.*;
 class Rocket implements Comparable {
        AltosLatLon     position;
        String          name;
+       int             serial;
        long            last_packet;
+       boolean         active;
        AltosMapOffline map_offline;
 
        void paint() {
@@ -49,14 +51,18 @@ class Rocket implements Comparable {
                this.last_packet = last_packet;
        }
 
-       Rocket(String name, AltosMapOffline map_offline) {
-               this.name = name;
-               this.map_offline = map_offline;
+       void set_active(boolean active) {
+               this.active = active;
        }
 
        public int compareTo(Object o) {
                Rocket other = (Rocket) o;
 
+               if (active && !other.active)
+                       return 1;
+               if (other.active && !active)
+                       return -1;
+
                long    diff = last_packet - other.last_packet;
 
                if (diff > 0)
@@ -65,12 +71,19 @@ class Rocket implements Comparable {
                        return -1;
                return 0;
        }
+
+       Rocket(int serial, AltosMapOffline map_offline) {
+               this.serial = serial;
+               this.name = String.format("%d", serial);
+               this.map_offline = map_offline;
+       }
 }
 
 public class AltosMapOffline extends View implements ScaleGestureDetector.OnScaleGestureListener, AltosMapInterface, AltosDroidMapInterface {
        ScaleGestureDetector    scale_detector;
        boolean                 scaling;
        AltosMap                map;
+       AltosDroid              altos_droid;
 
        AltosLatLon     here;
        AltosLatLon     pad;
@@ -236,6 +249,24 @@ public class AltosMapOffline extends View implements ScaleGestureDetector.OnScal
        public void set_zoom_label(String label) {
        }
 
+       public void select_object(AltosLatLon latlon) {
+               if (map.transform == null)
+                       return;
+               for (Rocket rocket : sorted_rockets()) {
+                       if (rocket.position == null) {
+                               debug("rocket %d has no position\n", rocket.serial);
+                               continue;
+                       }
+                       double distance = map.transform.hypot(latlon, rocket.position);
+                       debug("check select %d distance %g width %d\n", rocket.serial, distance, rocket_bitmap.getWidth());
+                       if (distance < rocket_bitmap.getWidth() * 2.0) {
+                               debug("selecting %d\n", rocket.serial);
+                               altos_droid.select_tracker(rocket.serial);
+                               break;
+                       }
+               }
+       }
+
        class Line {
                AltosLatLon     a, b;
 
@@ -295,16 +326,20 @@ public class AltosMapOffline extends View implements ScaleGestureDetector.OnScal
                }
        }
 
+       private Rocket[] sorted_rockets() {
+               Rocket[]        rocket_array = rockets.values().toArray(new Rocket[0]);
+
+               Arrays.sort(rocket_array);
+               return rocket_array;
+       }
+
        private void draw_positions() {
                line.set_a(map.last_position);
                line.set_b(here);
                line.paint();
                draw_bitmap(pad, pad_bitmap, pad_off_x, pad_off_y);
 
-               Rocket[]        rocket_array = rockets.values().toArray(new Rocket[0]);
-
-               Arrays.sort(rocket_array);
-               for (Rocket rocket : rocket_array)
+               for (Rocket rocket : sorted_rockets())
                        rocket.paint();
                draw_bitmap(here, here_bitmap, here_off_x, here_off_y);
        }
@@ -379,6 +414,8 @@ public class AltosMapOffline extends View implements ScaleGestureDetector.OnScal
                        map.touch_start((int) event.getX(), (int) event.getY(), true);
                } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                        map.touch_continue((int) event.getX(), (int) event.getY(), true);
+               } else if (event.getAction() == MotionEvent.ACTION_UP) {
+                       map.touch_stop((int) event.getX(), (int) event.getY(), true);
                }
                return true;
        }
@@ -425,11 +462,13 @@ public class AltosMapOffline extends View implements ScaleGestureDetector.OnScal
                                if (rockets.containsKey(serial))
                                        rocket = rockets.get(serial);
                                else {
-                                       rocket = new Rocket(String.format("%d", serial), this);
+                                       rocket = new Rocket(serial, this);
                                        rockets.put(serial, rocket);
                                }
                                if (t_state.gps != null)
                                        rocket.set_position(new AltosLatLon(t_state.gps.lat, t_state.gps.lon), t_state.received_time);
+                               if (state != null)
+                                       rocket.set_active(state.serial == serial);
                        }
                }
                if (receiver != null) {
@@ -437,9 +476,10 @@ public class AltosMapOffline extends View implements ScaleGestureDetector.OnScal
                }
        }
 
-       public void onCreateView(int map_type) {
+       public void onCreateView(AltosDroid altos_droid) {
+               this.altos_droid = altos_droid;
                map = new AltosMap(this);
-               map.set_maptype(map_type);
+               map.set_maptype(altos_droid.map_type);
 
                pad_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pad);
                /* arrow at the bottom of the launchpad image */
@@ -464,6 +504,7 @@ public class AltosMapOffline extends View implements ScaleGestureDetector.OnScal
 
        public AltosMapOffline(Context context, AttributeSet attrs) {
                super(context, attrs);
+               this.altos_droid = altos_droid;
                scale_detector = new ScaleGestureDetector(context, this);
        }
 }
index 9503a0b..3f5f32b 100644 (file)
@@ -121,7 +121,11 @@ public class AltosMapOnline implements AltosDroidMapInterface {
        private AltosLatLon my_position = null;
        private AltosLatLon target_position = null;
 
-       public void onCreateView(final int map_type) {
+       private AltosDroid altos_droid;
+
+       public void onCreateView(AltosDroid altos_droid) {
+               this.altos_droid = altos_droid;
+               final int map_type = altos_droid.map_type;
                mMapFragment = new SupportMapFragment() {
                        @Override
                        public void onActivityCreated(Bundle savedInstanceState) {
index 9c39e10..cd59dfe 100644 (file)
@@ -57,14 +57,6 @@ public class TabMap extends AltosDroidTab {
                super.onCreate(savedInstanceState);
        }
 
-       private void make_offline_map() {
-       }
-
-       private void make_online_map() {
-               map_online = new AltosMapOnline(view.getContext());
-               map_online.onCreateView(altos_droid.map_type);
-       }
-
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                view = inflater.inflate(R.layout.tab_map, container, false);
@@ -77,9 +69,9 @@ public class TabMap extends AltosDroidTab {
                mReceiverLatitudeView  = (TextView)view.findViewById(R.id.receiver_lat_value);
                mReceiverLongitudeView = (TextView)view.findViewById(R.id.receiver_lon_value);
                map_offline = (AltosMapOffline)view.findViewById(R.id.map_offline);
-               map_offline.onCreateView(altos_droid.map_type);
+               map_offline.onCreateView(altos_droid);
                map_online = new AltosMapOnline(view.getContext());
-               map_online.onCreateView(altos_droid.map_type);
+               map_online.onCreateView(altos_droid);
                set_map_source(AltosDroidPreferences.map_source());
                return view;
        }
index adf52ab..8d12a18 100644 (file)
@@ -391,6 +391,10 @@ public class AltosMap implements AltosMapTileListener, AltosMapStoreListener {
 
        AltosPointInt   drag_start;
 
+       boolean         dragged;
+
+       static final double drag_far = 20;
+
        private void drag(int x, int y) {
                if (drag_start == null)
                        return;
@@ -398,6 +402,11 @@ public class AltosMap implements AltosMapTileListener, AltosMapStoreListener {
                int dx = x - drag_start.x;
                int dy = y - drag_start.y;
 
+               double distance = Math.hypot(dx, dy);
+
+               if (distance > drag_far)
+                       dragged = true;
+
                if (transform == null) {
                        debug("Transform not set in drag\n");
                        return;
@@ -410,6 +419,12 @@ public class AltosMap implements AltosMapTileListener, AltosMapStoreListener {
 
        private void drag_start(int x, int y) {
                drag_start = new AltosPointInt(x, y);
+               dragged = false;
+       }
+
+       private void drag_stop(int x, int y) {
+               if (!dragged)
+                       map_interface.select_object (transform.screen_lat_lon(new AltosPointInt(x,y)));
        }
 
        private void line_start(int x, int y) {
@@ -442,6 +457,12 @@ public class AltosMap implements AltosMapTileListener, AltosMapStoreListener {
                        line(x, y);
        }
 
+       public void touch_stop(int x, int y, boolean is_drag) {
+               notice_user_input();
+               if (is_drag)
+                       drag_stop(x, y);
+       }
+
        public AltosMap(AltosMapInterface map_interface) {
                this.map_interface = map_interface;
                cache = new AltosMapCache(map_interface);
index e6cb597..7e8dd23 100644 (file)
@@ -42,4 +42,6 @@ public interface AltosMapInterface {
        public abstract void set_zoom_label(String label);
 
        public abstract void debug(String format, Object ... arguments);
+
+       public abstract void select_object(AltosLatLon latlon);
 }
index 30994ec..11ed4eb 100644 (file)
@@ -51,6 +51,13 @@ public class AltosMapTransform {
                return new AltosPointDouble(screen.x + offset_x, screen.y + offset_y);
        }
 
+       public double hypot(AltosLatLon a, AltosLatLon b) {
+               AltosPointDouble        a_pt = point(a);
+               AltosPointDouble        b_pt = point(b);
+
+               return Math.hypot(a_pt.x - b_pt.x, a_pt.y - b_pt.y);
+       }
+
        public AltosLatLon screen_lat_lon(AltosPointInt screen) {
                return lat_lon(screen_point(screen));
        }
index 246222b..8ac1829 100644 (file)
@@ -358,10 +358,15 @@ public class AltosUIMapNew extends JComponent implements AltosFlightDisplay, Alt
                zoom_label.setText(label);
        }
 
+       public void select_object(AltosLatLon latlon) {
+               debug("select at %f,%f\n", latlon.lat, latlon.lon);
+       }
+
        public void debug(String format, Object ... arguments) {
                System.out.printf(format, arguments);
        }
 
+
        /* AltosFlightDisplay interface */
 
        public void set_font() {