diff options
| -rw-r--r-- | altosdroid/res/layout/tab_map_offline.xml | 185 | ||||
| -rw-r--r-- | altosdroid/src/org/altusmetrum/AltosDroid/AltosMapView.java | 163 | ||||
| -rw-r--r-- | altosdroid/src/org/altusmetrum/AltosDroid/TabMapOffline.java | 222 | 
3 files changed, 433 insertions, 137 deletions
| 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +     Copyright © 2013 Mike Beattie <mike@ethernal.org> + +     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. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +	android:layout_width="match_parent" +	android:layout_height="match_parent" +	android:orientation="vertical" > + +  <org.altusmetrum.AltosDroid.AltosMapView android:id="@+id/map_view_offline" +					   android:layout_width="fill_parent" +					   android:layout_height="wrap_content" +					   android:layout_weight="1" +					   /> +   +  <LinearLayout +      xmlns:android="http://schemas.android.com/apk/res/android" +      android:layout_width="fill_parent" +      android:layout_height="wrap_content" +      android:baselineAligned="true" +      android:orientation="horizontal" > + +    <RelativeLayout +	android:layout_width="0dp" +	android:layout_height="wrap_content" +	android:layout_weight="1" +	android:paddingTop="5dp" > + +      <TextView +	  android:id="@+id/distance_label_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:paddingRight="4dp" +	  android:text="@string/distance_label" /> + +      <TextView +	  android:id="@+id/distance_value_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:layout_toRightOf="@id/distance_label_offline" +	  android:text="" +	  android:textAppearance="?android:attr/textAppearanceSmall" /> +    </RelativeLayout> + +    <RelativeLayout +	android:layout_width="0dp" +	android:layout_height="wrap_content" +	android:layout_weight="1" +	android:paddingTop="5dp" > + +      <TextView +	  android:id="@+id/bearing_label_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:paddingRight="4dp" +	  android:text="@string/bearing_label" /> + +      <TextView +	  android:id="@+id/bearing_value_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:layout_toRightOf="@id/bearing_label_offline" +	  android:text="" +	  android:textAppearance="?android:attr/textAppearanceSmall" /> +    </RelativeLayout> + +  </LinearLayout> + +  <LinearLayout +      xmlns:android="http://schemas.android.com/apk/res/android" +      android:layout_width="fill_parent" +      android:layout_height="wrap_content" +      android:baselineAligned="true" +      android:orientation="horizontal" > + +    <RelativeLayout +	android:layout_width="0dp" +	android:layout_height="wrap_content" +	android:layout_weight="1" +	android:paddingTop="5dp" > + +      <TextView +	  android:id="@+id/target_lat_label_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:paddingRight="4dp" +	  android:text="@string/target_latitude_label" /> + +      <TextView +	  android:id="@+id/target_lat_value_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:layout_toRightOf="@id/target_lat_label_offline" +	  android:text="" +	  android:textAppearance="?android:attr/textAppearanceSmall" /> +    </RelativeLayout> + +    <RelativeLayout +	android:layout_width="0dp" +	android:layout_height="wrap_content" +	android:layout_weight="1" +	android:paddingTop="5dp" > + +      <TextView +	  android:id="@+id/target_lon_label_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:paddingRight="4dp" +	  android:text="@string/target_longitude_label" /> + +      <TextView +	  android:id="@+id/target_lon_value_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:layout_toRightOf="@id/target_lon_label_offline" +	  android:text="" +	  android:textAppearance="?android:attr/textAppearanceSmall" /> +    </RelativeLayout> +  </LinearLayout> + +  <LinearLayout +      xmlns:android="http://schemas.android.com/apk/res/android" +      android:layout_width="fill_parent" +      android:layout_height="wrap_content" +      android:baselineAligned="true" +      android:orientation="horizontal" > + +    <RelativeLayout +	android:layout_width="0dp" +	android:layout_height="wrap_content" +	android:layout_weight="1" +	android:paddingTop="5dp" > + +      <TextView +	  android:id="@+id/receiver_lat_label_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:paddingRight="4dp" +	  android:text="@string/receiver_latitude_label" /> + +      <TextView +	  android:id="@+id/receiver_lat_value_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:layout_toRightOf="@id/receiver_lat_label_offline" +	  android:text="" +	  android:textAppearance="?android:attr/textAppearanceSmall" /> +    </RelativeLayout> + +    <RelativeLayout +	android:layout_width="0dp" +	android:layout_height="wrap_content" +	android:layout_weight="1" +	android:paddingTop="5dp" > + +      <TextView +	  android:id="@+id/receiver_lon_label_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:paddingRight="4dp" +	  android:text="@string/receiver_longitude_label" /> + +      <TextView +	  android:id="@+id/receiver_lon_value_offline" +	  android:layout_width="wrap_content" +	  android:layout_height="wrap_content" +	  android:layout_toRightOf="@id/receiver_lon_label_offline" +	  android:text="" +	  android:textAppearance="?android:attr/textAppearanceSmall" /> +    </RelativeLayout> +  </LinearLayout> +</LinearLayout> 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 <keithp@keithp.com> + * + * 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<Integer,Rocket> rockets = new HashMap<Integer,Rocket>();  	/* 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); @@ -410,46 +348,40 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {  	}  	@Override +	public void onDetach() { +		mAltosDroid = null; +	} + +	@Override  	public void onCreate(Bundle savedInstanceState) {  		super.onCreate(savedInstanceState);  	}  	@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); | 
