altosdroid: Add multi-tracker support
[fw/altos] / altosdroid / src / org / altusmetrum / AltosDroid / TabMapOffline.java
index 42d80ad52c4e392437519f101c89475e49741113..4b728c23ffca828488197511db27d9a744a7cb00 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import java.util.Arrays;
+import java.util.*;
 import java.io.*;
 
 import org.altusmetrum.altoslib_7.*;
@@ -31,20 +31,44 @@ import android.view.*;
 import android.widget.*;
 import android.location.Location;
 import android.content.*;
-import android.util.Log;
 
-public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {
-       // Debugging
-       static final String TAG = "AltosDroid";
-       static final boolean D = true;
+class Rocket {
+       AltosLatLon     position;
+       String          name;
+       TabMapOffline   tab;
+
+       void paint() {
+               tab.draw_bitmap(position, tab.rocket_bitmap, tab.rocket_off_x, tab.rocket_off_y);
+               tab.draw_text(position, name, 0, 3*tab.rocket_bitmap.getHeight()/4);
+       }
+
+       void set_position(AltosLatLon position) {
+               this.position = position;
+       }
+
+       Rocket(String name, TabMapOffline tab) {
+               this.name = name;
+               this.tab = tab;
+       }
+}
 
-       AltosDroid mAltosDroid;
+public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {
 
        AltosMap map;
 
+       AltosLatLon     here;
+       AltosLatLon     pad;
+
        Canvas  canvas;
        Paint   paint;
 
+       Bitmap  pad_bitmap;
+       int     pad_off_x, pad_off_y;
+       Bitmap  rocket_bitmap;
+       int     rocket_off_x, rocket_off_y;
+       Bitmap  here_bitmap;
+       int     here_off_x, here_off_y;
+
        private boolean pad_set;
 
        private TextView mDistanceView;
@@ -53,95 +77,41 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {
        private TextView mTargetLongitudeView;
        private TextView mReceiverLatitudeView;
        private TextView mReceiverLongitudeView;
+       private AltosMapView map_view;
 
        private double mapAccuracy = -1;
 
        int     stroke_width = 20;
 
-       class MapView extends View implements ScaleGestureDetector.OnScaleGestureListener {
-
-               ScaleGestureDetector    scale_detector;
-               boolean                 scaling;
-
-               protected void onDraw(Canvas view_canvas) {
-                       canvas = view_canvas;
-                       paint = new Paint(Paint.ANTI_ALIAS_FLAG);
-                       paint.setStrokeWidth(stroke_width);
-                       paint.setStrokeCap(Paint.Cap.ROUND);
-                       paint.setStrokeJoin(Paint.Join.ROUND);
-                       map.paint();
-                       canvas = null;
-               }
-
-               public boolean onScale(ScaleGestureDetector detector) {
-                       float   f = detector.getScaleFactor();
-                       if (D) Log.d(TAG, String.format("onScale %f\n", f));
-                       if (f <= 0.8) {
-                               map.set_zoom(map.get_zoom() - 1);
-                               return true;
-                       }
-                       if (f >= 1.2) {
-                               map.set_zoom(map.get_zoom() + 1);
-                               return true;
-                       }
-                       return false;
-               }
-
-               public boolean onScaleBegin(ScaleGestureDetector detector) {
-                       if (D) Log.d(TAG, String.format("onScaleBegin %f\n", detector.getScaleFactor()));
-                       return true;
-               }
-
-               public void onScaleEnd(ScaleGestureDetector detector) {
-                       if (D) Log.d(TAG, String.format("onScaleEnd %f\n", detector.getScaleFactor()));
-               }
 
-               @Override
-               public boolean dispatchTouchEvent(MotionEvent event) {
-                       scale_detector.onTouchEvent(event);
+       void draw_text(AltosLatLon lat_lon, String text, int off_x, int off_y) {
+               if (lat_lon != null && map != null && map.transform != null) {
+                       AltosPointInt pt = new AltosPointInt(map.transform.screen(lat_lon));
 
-                       if (scale_detector.isInProgress()) {
-                               scaling = true;
-                       }
+                       Rect    bounds = new Rect();
+                       paint.getTextBounds(text, 0, text.length(), bounds);
 
-                       if (scaling) {
-                               if(D) Log.d(TAG, "scale in progress\n");
-                               if (event.getAction() == MotionEvent.ACTION_UP) {
-                                       if (D) Log.d(TAG, "scale finished\n");
-                                       scaling = false;
-                               }
-                               return true;
-                       }
-
-                       if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                               if(D) Log.d(TAG, String.format("down event %g %g\n", event.getX(), event.getY()));
-                               map.touch_start((int) event.getX(), (int) event.getY(), true);
-                       } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                               if(D) Log.d(TAG, String.format("continue event %g %g\n", event.getX(), event.getY()));
-                               map.touch_continue((int) event.getX(), (int) event.getY(), true);
-                       }
-                       return true;
-               }
+                       int     width = bounds.right - bounds.left;
+                       int     height = bounds.bottom - bounds.top;
 
-               public MapView(Context context) {
-                       super(context);
-                       scale_detector = new ScaleGestureDetector(this.getContext(), this);
+                       float x = pt.x;
+                       float y = pt.y;
+                       x = x - width / 2.0f - off_x;
+                       y = y + height / 2.0f - off_y;
+                       paint.setColor(0xff000000);
+                       canvas.drawText(text, 0, text.length(), x, y, paint);
                }
        }
 
-       class MapFragment extends Fragment {
-               MapView map_view;
+       void draw_bitmap(AltosLatLon lat_lon, Bitmap bitmap, int off_x, int off_y) {
+               if (lat_lon != null && map != null && map.transform != null) {
+                       AltosPointInt pt = new AltosPointInt(map.transform.screen(lat_lon));
 
-               public View onCreateView(LayoutInflater inflator, ViewGroup container, Bundle savedInstanceState) {
-                       map_view = new MapView(container.getContext());
-                       return map_view;
-               }
-
-               public MapFragment() {
+                       canvas.drawBitmap(bitmap, pt.x - off_x, pt.y - off_y, paint);
                }
        }
 
-       MapFragment map_fragment;
+       HashMap<Integer,Rocket> rockets = new HashMap<Integer,Rocket>();
 
        /* AltosMapInterface */
 
@@ -209,7 +179,7 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {
        }
 
        public AltosMapPath new_path() {
-               return new MapPath();
+               return null;
        }
 
        class MapLine extends AltosMapLine {
@@ -221,7 +191,7 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {
        }
 
        public AltosMapLine new_line() {
-               return new MapLine();
+               return null;
        }
 
        class MapImage implements AltosImage {
@@ -309,7 +279,6 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {
                                        }
                                }
                        }
-
                }
 
                public MapTile(AltosMapTileListener listener, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size) {
@@ -323,44 +292,55 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {
        }
 
        public int width() {
-               if (map_fragment != null && map_fragment.map_view != null)
-                       return map_fragment.map_view.getWidth();
+               if (map_view != null)
+                       return map_view.getWidth();
                return 500;
        }
 
        public int height() {
-               if (map_fragment != null && map_fragment.map_view != null)
-                       return map_fragment.map_view.getHeight();
+               if (map_view != null)
+                       return map_view.getHeight();
                return 500;
        }
 
        public void repaint() {
-               this.getActivity().runOnUiThread(new Runnable() {
-                               public void run() {
-                                       if (map_fragment != null && map_fragment.map_view != null)
-                                               map_fragment.map_view.invalidate();
-                               }
-                       });
+               if (map_view != null)
+                       map_view.postInvalidate();
        }
 
-       public void repaint(AltosRectangle t_damage) {
-               final AltosRectangle damage = t_damage;
-               this.getActivity().runOnUiThread(new Runnable() {
-                               public void run() {
-                                       if (map_fragment != null && map_fragment.map_view != null)
-                                               map_fragment.map_view.invalidate(damage.x, damage.y, damage.x + damage.width, damage.y + damage.height);
-                               }
-                       });
+       public void repaint(AltosRectangle damage) {
+               if (map_view != null)
+                       map_view.postInvalidate(damage.x, damage.y, damage.x + damage.width, damage.y + damage.height);
        }
 
        public void set_zoom_label(String label) {
        }
 
+       public void debug(String format, Object ... arguments) {
+               AltosDebug.debug(format, arguments);
+       }
+
        @Override
        public void onAttach(Activity activity) {
                super.onAttach(activity);
-               mAltosDroid = (AltosDroid) activity;
-               mAltosDroid.registerTab(this);
+
+               map = new AltosMap(this);
+               map.set_maptype(altos_droid.map_type);
+
+               pad_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pad);
+               /* arrow at the bottom of the launchpad image */
+               pad_off_x = pad_bitmap.getWidth() / 2;
+               pad_off_y = pad_bitmap.getHeight();
+
+               rocket_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rocket);
+               /* arrow at the bottom of the rocket image */
+               rocket_off_x = rocket_bitmap.getWidth() / 2;
+               rocket_off_y = rocket_bitmap.getHeight();
+
+               here_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_maps_indicator_current_position);
+               /* Center of the dot */
+               here_off_x = here_bitmap.getWidth() / 2;
+               here_off_y = here_bitmap.getHeight() / 2;
        }
 
        @Override
@@ -370,83 +350,41 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {
 
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-               View v = inflater.inflate(R.layout.tab_map, container, false);
-
-               map_fragment = new MapFragment();
-               map = new AltosMap(this);
-               mDistanceView  = (TextView)v.findViewById(R.id.distance_value);
-               mBearingView   = (TextView)v.findViewById(R.id.bearing_value);
-               mTargetLatitudeView  = (TextView)v.findViewById(R.id.target_lat_value);
-               mTargetLongitudeView = (TextView)v.findViewById(R.id.target_lon_value);
-               mReceiverLatitudeView  = (TextView)v.findViewById(R.id.receiver_lat_value);
-               mReceiverLongitudeView = (TextView)v.findViewById(R.id.receiver_lon_value);
+               View v = inflater.inflate(R.layout.tab_map_offline, container, false);
+
+               map_view = (AltosMapView)v.findViewById(R.id.map_view_offline);
+               map_view.set_tab(this);
+               mDistanceView  = (TextView)v.findViewById(R.id.distance_value_offline);
+               mBearingView   = (TextView)v.findViewById(R.id.bearing_value_offline);
+               mTargetLatitudeView  = (TextView)v.findViewById(R.id.target_lat_value_offline);
+               mTargetLongitudeView = (TextView)v.findViewById(R.id.target_lon_value_offline);
+               mReceiverLatitudeView  = (TextView)v.findViewById(R.id.receiver_lat_value_offline);
+               mReceiverLongitudeView = (TextView)v.findViewById(R.id.receiver_lon_value_offline);
                return v;
        }
 
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
                super.onActivityCreated(savedInstanceState);
-               getChildFragmentManager().beginTransaction().add(R.id.map, map_fragment).commit();
        }
+
        @Override
        public void onDestroyView() {
                super.onDestroyView();
 
-               mAltosDroid.unregisterTab(this);
-               mAltosDroid = null;
-               map_fragment = null;
-
-//             Fragment fragment = (getFragmentManager().findFragmentById(R.id.map));
-//             FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
-//             ft.remove(fragment);
-//             ft.commit();
-       }
-
-       private void setupMap() {
-/*
-               mMap = mMapFragment.getMap();
-               if (mMap != null) {
-                       mMap.setMyLocationEnabled(true);
-                       mMap.getUiSettings().setTiltGesturesEnabled(false);
-                       mMap.getUiSettings().setZoomControlsEnabled(false);
-
-                       mRocketMarker = mMap.addMarker(
-                                       // From: http://mapicons.nicolasmollet.com/markers/industry/military/missile-2/
-                                       new MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.rocket))
-                                                          .position(new LatLng(0,0))
-                                                          .visible(false)
-                                       );
-
-                       mPadMarker = mMap.addMarker(
-                                       new MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.pad))
-                                                          .position(new LatLng(0,0))
-                                                          .visible(false)
-                                       );
-
-                       mPolyline = mMap.addPolyline(
-                                       new PolylineOptions().add(new LatLng(0,0), new LatLng(0,0))
-                                                            .width(3)
-                                                            .color(Color.BLUE)
-                                                            .visible(false)
-                                       );
-
-                       mapLoaded = true;
-               }
-*/
        }
 
        private void center(double lat, double lon, double accuracy) {
                if (mapAccuracy < 0 || accuracy < mapAccuracy/10) {
                        if (map != null)
-                               map.centre(lat, lon);
+                               map.maybe_centre(lat, lon);
                        mapAccuracy = accuracy;
                }
        }
 
        public String tab_name() { return "offmap"; }
 
-       public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
+       public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {
                if (from_receiver != null) {
                        mBearingView.setText(String.format("%3.0f°", from_receiver.bearing));
                        set_value(mDistanceView, AltosConvert.distance, 6, from_receiver.distance);
@@ -460,22 +398,56 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {
                                if (state.gps.locked && state.gps.nsat >= 4)
                                        center (state.gps.lat, state.gps.lon, 10);
                        }
+                       if (state.pad_lat != AltosLib.MISSING && pad == null)
+                               pad = new AltosLatLon(state.pad_lat, state.pad_lon);
+               }
+
+               if (telem_state != null) {
+                       Integer[] old_serial = rockets.keySet().toArray(new Integer[0]);
+                       Integer[] new_serial = telem_state.states.keySet().toArray(new Integer[0]);
+
+                       /* remove deleted keys */
+                       for (int serial : old_serial) {
+                               if (!telem_state.states.containsKey(serial))
+                                       rockets.remove(serial);
+                       }
+
+                       /* set remaining keys */
+
+                       for (int serial : new_serial) {
+                               Rocket          rocket;
+                               AltosState      t_state = telem_state.states.get(serial);
+                               if (rockets.containsKey(serial))
+                                       rocket = rockets.get(serial);
+                               else {
+                                       rocket = new Rocket(String.format("%d", serial), this);
+                                       rockets.put(serial, rocket);
+                               }
+                               rocket.set_position(new AltosLatLon(t_state.gps.lat, t_state.gps.lon));
+                       }
                }
 
                if (receiver != null) {
                        double accuracy;
 
+                       here = new AltosLatLon(receiver.getLatitude(), receiver.getLongitude());
                        if (receiver.hasAccuracy())
                                accuracy = receiver.getAccuracy();
                        else
                                accuracy = 1000;
-                       mReceiverLatitudeView.setText(AltosDroid.pos(receiver.getLatitude(), "N", "S"));
-                       mReceiverLongitudeView.setText(AltosDroid.pos(receiver.getLongitude(), "E", "W"));
-                       center (receiver.getLatitude(), receiver.getLongitude(), accuracy);
+                       mReceiverLatitudeView.setText(AltosDroid.pos(here.lat, "N", "S"));
+                       mReceiverLongitudeView.setText(AltosDroid.pos(here.lon, "E", "W"));
+                       center (here.lat, here.lon, accuracy);
                }
 
        }
 
+       @Override
+       public void set_map_type(int map_type) {
+               if (map != null)
+                       map.set_maptype(map_type);
+       }
+
        public TabMapOffline() {
        }
 }