From 50e709a4088f3d6846fd66cbe9b8c437b3f9c88b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 May 2015 22:13:39 -0700 Subject: [PATCH 1/1] altosdroid: Split out AltosMapView into separate file This lets us use the regular layout configuration bits in the .xml file instead of needing to patch the map object into the display. That was causing problems when re-entering the map tab as the map view would somehow end up with a zero width. Signed-off-by: Keith Packard --- altosdroid/res/layout/tab_map_offline.xml | 185 +++++++++++++++ .../altusmetrum/AltosDroid/AltosMapView.java | 163 +++++++++++++ .../altusmetrum/AltosDroid/TabMapOffline.java | 222 +++++++----------- 3 files changed, 433 insertions(+), 137 deletions(-) create mode 100644 altosdroid/res/layout/tab_map_offline.xml create mode 100644 altosdroid/src/org/altusmetrum/AltosDroid/AltosMapView.java diff --git a/altosdroid/res/layout/tab_map_offline.xml b/altosdroid/res/layout/tab_map_offline.xml new file mode 100644 index 00000000..e6f134d8 --- /dev/null +++ b/altosdroid/res/layout/tab_map_offline.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosMapView.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosMapView.java new file mode 100644 index 00000000..460a3a25 --- /dev/null +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosMapView.java @@ -0,0 +1,163 @@ +/* + * Copyright © 2015 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.AltosDroid; + +import java.util.*; +import java.io.*; + +import org.altusmetrum.altoslib_7.*; + +import android.app.Activity; +import android.graphics.*; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.view.*; +import android.widget.*; +import android.location.Location; +import android.content.*; +import android.util.*; + +public class AltosMapView extends View implements ScaleGestureDetector.OnScaleGestureListener { + ScaleGestureDetector scale_detector; + boolean scaling; + TabMapOffline tab; + + class Line { + AltosLatLon a, b; + + void paint() { + if (a != null && b != null) { + AltosPointDouble a_screen = tab.map.transform.screen(a); + AltosPointDouble b_screen = tab.map.transform.screen(b); + tab.paint.setColor(0xff8080ff); + tab.canvas.drawLine((float) a_screen.x, (float) a_screen.y, + (float) b_screen.x, (float) b_screen.y, + tab.paint); + } + } + + void set_a(AltosLatLon a) { + this.a = a; + } + + void set_b(AltosLatLon b) { + this.b = b; + } + + Line() { + } + } + + Line line = new Line(); + + private void draw_bitmap(AltosLatLon lat_lon, Bitmap bitmap, int off_x, int off_y) { + if (lat_lon != null && tab.map != null && tab.map.transform != null) { + AltosPointInt pt = new AltosPointInt(tab.map.transform.screen(lat_lon)); + + tab.canvas.drawBitmap(bitmap, pt.x - off_x, pt.y - off_y, tab.paint); + } + } + + private void draw_positions() { + line.set_a(tab.map.last_position); + line.set_b(tab.here); + line.paint(); + draw_bitmap(tab.pad, tab.pad_bitmap, tab.pad_off_x, tab.pad_off_y); + for (Rocket rocket : tab.rockets.values()) + rocket.paint(); + draw_bitmap(tab.here, tab.here_bitmap, tab.here_off_x, tab.here_off_y); + } + + @Override public void invalidate() { + Rect r = new Rect(); + getDrawingRect(r); + super.invalidate(); + } + + @Override public void invalidate(int l, int t, int r, int b) { + Rect rect = new Rect(); + getDrawingRect(rect); + super.invalidate(); + } + + @Override + protected void onDraw(Canvas view_canvas) { + tab.canvas = view_canvas; + tab.paint = new Paint(Paint.ANTI_ALIAS_FLAG); + tab.paint.setStrokeWidth(tab.stroke_width); + tab.paint.setStrokeCap(Paint.Cap.ROUND); + tab.paint.setStrokeJoin(Paint.Join.ROUND); + tab.paint.setTextSize(40); + tab.map.paint(); + draw_positions(); + tab.canvas = null; + } + + public boolean onScale(ScaleGestureDetector detector) { + float f = detector.getScaleFactor(); + if (f <= 0.8) { + tab.map.set_zoom(tab.map.get_zoom() - 1); + return true; + } + if (f >= 1.2) { + tab.map.set_zoom(tab.map.get_zoom() + 1); + return true; + } + return false; + } + + public boolean onScaleBegin(ScaleGestureDetector detector) { + return true; + } + + public void onScaleEnd(ScaleGestureDetector detector) { + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + scale_detector.onTouchEvent(event); + + if (scale_detector.isInProgress()) { + scaling = true; + } + + if (scaling) { + if (event.getAction() == MotionEvent.ACTION_UP) { + scaling = false; + } + return true; + } + + if (event.getAction() == MotionEvent.ACTION_DOWN) { + tab.map.touch_start((int) event.getX(), (int) event.getY(), true); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + tab.map.touch_continue((int) event.getX(), (int) event.getY(), true); + } + return true; + } + + public void set_tab(TabMapOffline tab) { + this.tab = tab; + } + + public AltosMapView(Context context, AttributeSet attrs) { + super(context, attrs); + scale_detector = new ScaleGestureDetector(context, this); + } +} diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabMapOffline.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabMapOffline.java index cbf50018..90b41156 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabMapOffline.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabMapOffline.java @@ -17,7 +17,7 @@ package org.altusmetrum.AltosDroid; -import java.util.Arrays; +import java.util.*; import java.io.*; import org.altusmetrum.altoslib_7.*; @@ -32,6 +32,26 @@ import android.widget.*; import android.location.Location; import android.content.*; +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; + } +} + public class TabMapOffline extends AltosDroidTab implements AltosMapInterface { AltosDroid mAltosDroid; @@ -59,117 +79,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; - private void draw_bitmap(AltosLatLon lat_lon, Bitmap bitmap, int off_x, int off_y) { - if (lat_lon != null) { - AltosPointInt pt = new AltosPointInt(map.transform.screen(lat_lon)); - - canvas.drawBitmap(bitmap, pt.x - off_x, pt.y - off_y, paint); - } - } - - class MapView extends View implements ScaleGestureDetector.OnScaleGestureListener { - - ScaleGestureDetector scale_detector; - boolean scaling; - private void draw_positions() { - if (map.last_position != null && here != null) { - AltosPointDouble rocket_screen = map.transform.screen(map.last_position); - AltosPointDouble here_screen = map.transform.screen(here); - paint.setColor(0xff8080ff); - canvas.drawLine((float) rocket_screen.x, (float) rocket_screen.y, - (float) here_screen.x, (float) here_screen.y, paint); - } - draw_bitmap(pad, pad_bitmap, pad_off_x, pad_off_y); - draw_bitmap(map.last_position, rocket_bitmap, rocket_off_x, rocket_off_y); - draw_bitmap(here, here_bitmap, here_off_x, here_off_y); - } - - 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(); - draw_positions(); - canvas = null; - } - - public boolean onScale(ScaleGestureDetector detector) { - float f = detector.getScaleFactor(); - AltosDebug.debug("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) { - AltosDebug.debug("onScaleBegin %f\n", detector.getScaleFactor()); - return true; - } - - public void onScaleEnd(ScaleGestureDetector detector) { - AltosDebug.debug("onScaleEnd %f\n", detector.getScaleFactor()); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - scale_detector.onTouchEvent(event); - - if (scale_detector.isInProgress()) { - scaling = true; - } + 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 (scaling) { - if(AltosDebug.D) AltosDebug.debug("scale in progress\n"); - if (event.getAction() == MotionEvent.ACTION_UP) { - AltosDebug.debug("scale finished\n"); - scaling = false; - } - return true; - } + Rect bounds = new Rect(); + paint.getTextBounds(text, 0, text.length(), bounds); - if (event.getAction() == MotionEvent.ACTION_DOWN) { - AltosDebug.debug("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) { - AltosDebug.debug("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; - - public View onCreateView(LayoutInflater inflator, ViewGroup container, Bundle savedInstanceState) { - map_view = new MapView(container.getContext()); - return 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 MapFragment() { + canvas.drawBitmap(bitmap, pt.x - off_x, pt.y - off_y, paint); } } - MapFragment map_fragment; + HashMap rockets = new HashMap(); /* AltosMapInterface */ @@ -337,7 +281,6 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface { } } } - } public MapTile(AltosMapTileListener listener, AltosLatLon upper_left, AltosLatLon center, int zoom, int maptype, int px_size) { @@ -351,39 +294,34 @@ 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); @@ -409,6 +347,11 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface { here_off_y = here_bitmap.getHeight() / 2; } + @Override + public void onDetach() { + mAltosDroid = null; + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -416,40 +359,29 @@ 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() { } private void center(double lat, double lon, double accuracy) { @@ -478,6 +410,21 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface { } if (state.pad_lat != AltosLib.MISSING && pad == null) pad = new AltosLatLon(state.pad_lat, state.pad_lon); + + int serial = state.serial; + if (serial == AltosLib.MISSING) + serial = 0; + + Rocket rocket = null; + + if (state.gps != null && state.gps.locked) { + if (!rockets.containsKey(serial)) { + rocket = new Rocket(String.format("%d", serial), this); + rockets.put(serial, rocket); + } else + rocket = rockets.get(serial); + rocket.set_position(new AltosLatLon(state.gps.lat, state.gps.lon)); + } } if (receiver != null) { @@ -495,6 +442,7 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface { } + @Override public void set_map_type(int map_type) { if (map != null) map.set_maptype(map_type); -- 2.30.2