diff options
| author | Keith Packard <keithp@keithp.com> | 2015-06-06 20:36:18 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2015-06-06 20:36:18 -0700 | 
| commit | c813c2c8f71017a686128e06b5178fc99ece251c (patch) | |
| tree | c341e42af6080e3d48fb3f4c3c6f1a762ea53add | |
| parent | f79d569dfe333621d63a1d4001c85a88f736ad58 (diff) | |
altosdroid: Add multi-tracker support
This lets you view multiple trackers in the offline maps tab (online
maps not done yet), saves state of each tracker to preferences.
Signed-off-by: Keith Packard <keithp@keithp.com>
14 files changed, 316 insertions, 203 deletions
| diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java index 8c9ff31f..942ebbd5 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java @@ -42,16 +42,8 @@ import android.content.res.Resources;  import android.support.v4.app.FragmentActivity;  import android.support.v4.app.FragmentManager;  import android.util.DisplayMetrics; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.Window; -import android.view.View; -import android.view.LayoutInflater; -import android.widget.TabHost; -import android.widget.TextView; -import android.widget.RelativeLayout; -import android.widget.Toast; +import android.view.*; +import android.widget.*;  import android.app.AlertDialog;  import android.location.Location;  import android.hardware.usb.*; @@ -112,6 +104,8 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {  	// Timer and Saved flight state for Age calculation  	private Timer timer;  	AltosState saved_state; +	TelemetryState	telemetry_state; +	Integer[] 	serials;  	UsbDevice	pending_usb_device;  	boolean		start_with_usb; @@ -136,13 +130,11 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {  			switch (msg.what) {  			case MSG_STATE:  				AltosDebug.debug("MSG_STATE"); -				TelemetryState telemetry_state = (TelemetryState) msg.obj; -				if (telemetry_state == null) { +				if (msg.obj == null) {  					AltosDebug.debug("telemetry_state null!");  					return;  				} - -				ad.update_state(telemetry_state); +				ad.update_state((TelemetryState) msg.obj);  				break;  			case MSG_UPDATE_AGE:  				AltosDebug.debug("MSG_UPDATE_AGE"); @@ -258,17 +250,34 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {  	boolean	registered_units_listener; -	void update_state(TelemetryState telemetry_state) { +	int	current_serial; + +	void update_state(TelemetryState new_telemetry_state) { + +		if (new_telemetry_state != null) +			telemetry_state = new_telemetry_state; + +		if (current_serial == 0) +			current_serial = telemetry_state.latest_serial;  		if (!registered_units_listener) {  			registered_units_listener = true;  			AltosPreferences.register_units_listener(this);  		} +		serials = telemetry_state.states.keySet().toArray(new Integer[0]); +  		update_title(telemetry_state); -		update_ui(telemetry_state.state, telemetry_state.location); -		if (telemetry_state.connect == TelemetryState.CONNECT_CONNECTED) -			start_timer(); + +		AltosDebug.debug("update state current serial %d\n", current_serial); + +		AltosState	state = null; +		if (telemetry_state.states.containsKey(current_serial)) +			state = telemetry_state.states.get(current_serial); + +		update_ui(telemetry_state, state, telemetry_state.location); + +		start_timer();  	}  	boolean same_string(String a, String b) { @@ -283,22 +292,55 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {  		}  	} + +	private int blend_component(int a, int b, double r, int shift, int mask) { +		return ((int) (((a >> shift) & mask) * r + ((b >> shift) & mask) * (1 - r)) & mask) << shift; +	} +	private int blend_color(int a, int b, double r) { +		return (blend_component(a, b, r, 0, 0xff) | +			blend_component(a, b, r, 8, 0xff) | +			blend_component(a, b, r, 16, 0xff) | +			blend_component(a, b, r, 24, 0xff)); +	} + +	int state_age(AltosState state) { +		return (int) ((System.currentTimeMillis() - state.received_time + 500) / 1000); +	} + +	void set_screen_on(int age) { +		if (age < 60) +			getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); +		else +			getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); +	} +  	void update_age() {  		if (saved_state != null) { -			int age = (int) ((System.currentTimeMillis() - saved_state.received_time + 500) / 1000); -			boolean old = age >= 10; -			if (old != mAgeViewOld) { -				if (old) -					mAgeView.setTextColor(mAgeOldColor); -				else -					mAgeView.setTextColor(mAgeNewColor); -				mAgeViewOld = old; -			} -			mAgeView.setText(String.format("%d", age)); +			int age = state_age(saved_state); + +			double age_scale = age / 100.0; + +			if (age_scale > 1.0) +				age_scale = 1.0; + +			mAgeView.setTextColor(blend_color(mAgeOldColor, mAgeNewColor, age_scale)); + +			set_screen_on(age); + +			String	text; +			if (age < 60) +				text = String.format("%ds", age); +			else if (age < 60 * 60) +				text = String.format("%dm", age / 60); +			else if (age < 60 * 60 * 24) +				text = String.format("%dh", age / (60 * 60)); +			else +				text = String.format("%dd", age / (24 * 60 * 60)); +			mAgeView.setText(text);  		}  	} -	void update_ui(AltosState state, Location location) { +	void update_ui(TelemetryState telem_state, AltosState state, Location location) {  		int prev_state = AltosLib.ao_flight_invalid; @@ -308,6 +350,8 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {  			prev_state = saved_state.state;  		if (state != null) { +			set_screen_on(state_age(state)); +  			if (state.state == AltosLib.ao_flight_stateless) {  				boolean	prev_locked = false;  				boolean locked = false; @@ -382,7 +426,7 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {  		}  		for (AltosDroidTab mTab : mTabs) -			mTab.update_ui(state, from_receiver, location, mTab == mTabsAdapter.currentItem()); +			mTab.update_ui(telem_state, state, from_receiver, location, mTab == mTabsAdapter.currentItem());  		if (state != null && mAltosVoice != null)  			mAltosVoice.tell(state, from_receiver); @@ -744,6 +788,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) +			return; + +		AltosDebug.debug("Switching to serial %d\n", serial); +		current_serial = serial; +		update_state(null); +	} + +	void delete_track(int serial) { +		try { +			mService.send(Message.obtain(null, TelemetryService.MSG_DELETE_SERIAL, (Integer) serial)); +		} catch (Exception ex) { +		} +	} +  	@Override  	public boolean onOptionsItemSelected(MenuItem item) {  		Intent serverIntent = null; @@ -824,8 +888,43 @@ public class AltosDroid extends FragmentActivity implements AltosUnitsListener {  			serverIntent = new Intent(this, MapTypeActivity.class);  			startActivityForResult(serverIntent, REQUEST_MAP_TYPE);  			return true; +		case R.id.select_tracker: +			if (serials != null) { +				String[] trackers = new String[serials.length]; +				for (int i = 0; i < serials.length; i++) +					trackers[i] = 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]); +								} +							}); +				AlertDialog alert_serial = builder_serial.create(); +				alert_serial.show(); + +			} +			return true; +		case R.id.delete_track: +			if (serials != null) { +				String[] trackers = new String[serials.length]; +				for (int i = 0; i < serials.length; i++) +					trackers[i] = String.format("%d", serials[i]); +				AlertDialog.Builder builder_serial = new AlertDialog.Builder(this); +				builder_serial.setTitle("Delete a track"); +				builder_serial.setItems(trackers, +							new DialogInterface.OnClickListener() { +								public void onClick(DialogInterface dialog, int item) { +									delete_track(serials[item]); +								} +							}); +				AlertDialog alert_serial = builder_serial.create(); +				alert_serial.show(); + +			} +			return true;  		}  		return false;  	} -  } diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferencesBackend.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferencesBackend.java index 75676e28..dfc37153 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferencesBackend.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferencesBackend.java @@ -44,7 +44,12 @@ public class AltosDroidPreferencesBackend implements AltosPreferencesBackend {  	public String[] keys() {  		Map<String, ?> all = prefs.getAll(); -		return (String[])all.keySet().toArray(); +		Object[] ao = all.keySet().toArray(); + +		String[] as = new String[ao.length]; +		for (int i = 0; i < ao.length; i++) +			as[i] = (String) ao[i]; +		return as;  	}  	public AltosPreferencesBackend node(String key) { @@ -104,6 +109,7 @@ public class AltosDroidPreferencesBackend implements AltosPreferencesBackend {  	}  	public void remove(String key) { +		AltosDebug.debug("remove preference %s\n", key);  		editor.remove(key);  	} diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java index f1f1b6de..017315af 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java @@ -29,11 +29,13 @@ import android.location.Location;  import android.widget.TextView;  public abstract class AltosDroidTab extends Fragment implements AltosUnitsListener { +	TelemetryState		last_telem_state;  	AltosState		last_state;  	AltosGreatCircle	last_from_receiver;  	Location		last_receiver; +	AltosDroid		altos_droid; -	public abstract void show(AltosState state, AltosGreatCircle from_receiver, Location receiver); +	public abstract void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver);  	public abstract String tab_name(); @@ -41,8 +43,8 @@ public abstract class AltosDroidTab extends Fragment implements AltosUnitsListen  	}  	public void units_changed(boolean imperial_units) { -		if (!isHidden() && last_state != null) -			show(last_state, last_from_receiver, last_receiver); +		if (!isHidden()) +			show(last_telem_state, last_state, last_from_receiver, last_receiver);  	}  	public void set_value(TextView text_view, @@ -59,30 +61,44 @@ public abstract class AltosDroidTab extends Fragment implements AltosUnitsListen  		FragmentTransaction	ft = AltosDroid.fm.beginTransaction();  		AltosDebug.debug("set visible %b %s\n", visible, tab_name());  		if (visible) { -			AltosState		state = last_state; -			AltosGreatCircle	from_receiver = last_from_receiver; -			Location		receiver = last_receiver; -  			ft.show(this); -			show(state, from_receiver, receiver); +			show(last_telem_state, last_state, last_from_receiver, last_receiver);  		} else  			ft.hide(this);  		ft.commitAllowingStateLoss();  	}  	@Override +	public void onAttach(Activity activity) { +		super.onAttach(activity); +		altos_droid = (AltosDroid) activity; +		altos_droid.registerTab(this); +	} + +	@Override +	public void onDetach() { +		super.onDetach(); +		altos_droid.unregisterTab(this); +		altos_droid = null; +	} + +	@Override  	public void onResume() {  		super.onResume();  		AltosDebug.debug("onResume tab %s\n", tab_name());  		set_visible(true);  	} -	public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver, boolean is_current) { +	public void update_ui(TelemetryState telem_state, AltosState state, +			      AltosGreatCircle from_receiver, Location receiver, boolean is_current) +	{ +		last_telem_state = telem_state;  		last_state = state;  		last_from_receiver = from_receiver;  		last_receiver = receiver; +		AltosDebug.debug("update_ui tab %s is_current %b\n", tab_name(), is_current);  		if (is_current) -			show(state, from_receiver, receiver); +			show(telem_state, state, from_receiver, receiver);  		else  			return;  	} diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java b/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java index 4af117a2..f36ef267 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/DeviceListActivity.java @@ -191,14 +191,22 @@ public class DeviceListActivity extends Activity {  			// When discovery finds a device  			if (BluetoothDevice.ACTION_FOUND.equals(action)) { -				// Get the BluetoothDevice object from the Intent + +				/* Get the BluetoothDevice object from the Intent +				 */  				BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); -				// If it's already paired, skip it, because it's been listed already -				if (   device.getBondState() != BluetoothDevice.BOND_BONDED -				    && device.getName().startsWith("TeleBT")               ) { -					mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); + +				/* If it's already paired, skip it, because it's been listed already +				 */ +				if (device != null && device.getBondState() != BluetoothDevice.BOND_BONDED) +				{ +					String	name = device.getName(); +					if (name != null && name.startsWith("TeleBT")) +						mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());  				} -			// When discovery is finished, change the Activity title + +			/* When discovery is finished, change the Activity title +			 */  			} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {  				setProgressBarIndeterminateVisibility(false);  				setTitle(R.string.select_device); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java index 797dc7c3..afce937f 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java @@ -30,8 +30,6 @@ import android.widget.TextView;  import android.location.Location;  public class TabAscent extends AltosDroidTab { -	AltosDroid mAltosDroid; -  	private TextView mHeightView;  	private TextView mMaxHeightView;  	private TextView mSpeedView; @@ -46,13 +44,6 @@ public class TabAscent extends AltosDroidTab {  	private GoNoGoLights mMainLights;  	@Override -	public void onAttach(Activity activity) { -		super.onAttach(activity); -		mAltosDroid = (AltosDroid) activity; -		mAltosDroid.registerTab(this); -	} - -	@Override  	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  		View v = inflater.inflate(R.layout.tab_ascent, container, false); @@ -78,18 +69,11 @@ public class TabAscent extends AltosDroidTab {  		return v;  	} -	@Override -	public void onDestroy() { -		super.onDestroy(); -		mAltosDroid.unregisterTab(this); -		mAltosDroid = null; -	} -  	public String tab_name() {  		return "ascent";  	} -	public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) { +	public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {  		if (state != null) {  			set_value(mHeightView, AltosConvert.height, 6, state.height());  			set_value(mHeightView, AltosConvert.height, 6, state.height()); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java index f3f5a0f1..3429ee72 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java @@ -30,8 +30,6 @@ import android.widget.TextView;  import android.location.Location;  public class TabDescent extends AltosDroidTab { -	AltosDroid mAltosDroid; -  	private TextView mSpeedView;  	private TextView mHeightView;  	private TextView mElevationView; @@ -46,14 +44,6 @@ public class TabDescent extends AltosDroidTab {  	private TextView mMainVoltageView;  	private GoNoGoLights mMainLights; - -	@Override -	public void onAttach(Activity activity) { -		super.onAttach(activity); -		mAltosDroid = (AltosDroid) activity; -		mAltosDroid.registerTab(this); -	} -  	@Override  	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  		View v = inflater.inflate(R.layout.tab_descent, container, false); @@ -81,17 +71,9 @@ public class TabDescent extends AltosDroidTab {  		return v;  	} - -	@Override -	public void onDestroy() { -		super.onDestroy(); -		mAltosDroid.unregisterTab(this); -		mAltosDroid = null; -	} -  	public String tab_name() { return "descent"; } -	public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) { +	public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {  		if (state != null) {  			set_value(mSpeedView, AltosConvert.speed, 6, state.speed());  			set_value(mHeightView, AltosConvert.height, 6, state.height()); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java index d37891f7..dd3f938e 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java @@ -29,8 +29,6 @@ import android.widget.TextView;  import android.location.Location;  public class TabLanded extends AltosDroidTab { -	AltosDroid mAltosDroid; -  	private TextView mBearingView;  	private TextView mDistanceView;  	private TextView mTargetLatitudeView; @@ -41,14 +39,6 @@ public class TabLanded extends AltosDroidTab {  	private TextView mMaxSpeedView;  	private TextView mMaxAccelView; - -	@Override -	public void onAttach(Activity activity) { -		super.onAttach(activity); -		mAltosDroid = (AltosDroid) activity; -		mAltosDroid.registerTab(this); -	} -  	@Override  	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  		View v = inflater.inflate(R.layout.tab_landed, container, false); @@ -66,16 +56,9 @@ public class TabLanded extends AltosDroidTab {  		return v;  	} -	@Override -	public void onDestroy() { -		super.onDestroy(); -		mAltosDroid.unregisterTab(this); -		mAltosDroid = null; -	} -  	public String tab_name() { return "landed"; } -	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); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java index cea3cac6..ff36875d 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java @@ -33,6 +33,7 @@ import com.google.android.gms.maps.model.PolylineOptions;  import android.app.Activity;  import android.graphics.Color; +import android.graphics.*;  import android.os.Bundle;  import android.support.v4.app.Fragment;  //import android.support.v4.app.FragmentTransaction; @@ -43,8 +44,6 @@ import android.widget.TextView;  import android.location.Location;  public class TabMap extends AltosDroidTab { -	AltosDroid mAltosDroid; -  	private SupportMapFragment mMapFragment;  	private GoogleMap mMap;  	private boolean mapLoaded = false; @@ -63,11 +62,40 @@ public class TabMap extends AltosDroidTab {  	private double mapAccuracy = -1; -	@Override -	public void onAttach(Activity activity) { -		super.onAttach(activity); -		mAltosDroid = (AltosDroid) activity; -		mAltosDroid.registerTab(this); +	private Bitmap rocket_bitmap(String text) { + +		/* From: http://mapicons.nicolasmollet.com/markers/industry/military/missile-2/ +		 */ +		Bitmap orig_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rocket); +		Bitmap bitmap = orig_bitmap.copy(Bitmap.Config.ARGB_8888, true); + +		Canvas canvas = new Canvas(bitmap); +		Paint paint = new Paint(); +		paint.setTextSize(40); +		paint.setColor(0xff000000); + +		Rect	bounds = new Rect(); +		paint.getTextBounds(text, 0, text.length(), bounds); + +		int	width = bounds.right - bounds.left; +		int	height = bounds.bottom - bounds.top; + +		float x = bitmap.getWidth() / 2.0f - width / 2.0f; +		float y = bitmap.getHeight() / 2.0f - height / 2.0f; + +		AltosDebug.debug("map label x %f y %f\n", x, y); + +		canvas.drawText(text, 0, text.length(), x, y, paint); +		return bitmap; +	} + +	private Marker rocket_marker(int serial, double lat, double lon) { +		Bitmap	bitmap = rocket_bitmap(String.format("%d", serial)); + +		return mMap.addMarker(new MarkerOptions() +				      .icon(BitmapDescriptorFactory.fromBitmap(bitmap)) +				      .position(new LatLng(lat, lon)) +				      .visible(false));  	}  	@Override @@ -102,33 +130,17 @@ public class TabMap extends AltosDroidTab {  		getChildFragmentManager().beginTransaction().add(R.id.map, mMapFragment).commit();  	} -	@Override -	public void onDestroyView() { -		super.onDestroyView(); - -		mAltosDroid.unregisterTab(this); -		mAltosDroid = 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) { -			set_map_type(mAltosDroid.map_type); +			set_map_type(altos_droid.map_type);  			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) -					); +			Bitmap label_bitmap = rocket_bitmap("hello"); + +			mRocketMarker = rocket_marker(1800,0,0);  			mPadMarker = mMap.addMarker(  					new MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.pad)) @@ -156,7 +168,7 @@ public class TabMap extends AltosDroidTab {  	public String tab_name() { return "map"; } -	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); @@ -166,6 +178,8 @@ public class TabMap extends AltosDroidTab {  			if (mapLoaded) {  				if (state.gps != null) {  					mRocketMarker.setPosition(new LatLng(state.gps.lat, state.gps.lon)); +					mRocketMarker.setTitle("hello world"); +					mRocketMarker.setSnippet("hello");  					mRocketMarker.setVisible(true);  					mPolyline.setPoints(Arrays.asList(new LatLng(state.pad_lat, state.pad_lon), new LatLng(state.gps.lat, state.gps.lon))); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabMapOffline.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabMapOffline.java index 56e296d9..4b728c23 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabMapOffline.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabMapOffline.java @@ -54,8 +54,6 @@ class Rocket {  public class TabMapOffline extends AltosDroidTab implements AltosMapInterface { -	AltosDroid mAltosDroid; -  	AltosMap map;  	AltosLatLon	here; @@ -325,11 +323,9 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {  	@Override  	public void onAttach(Activity activity) {  		super.onAttach(activity); -		mAltosDroid = (AltosDroid) activity; -		mAltosDroid.registerTab(this);  		map = new AltosMap(this); -		map.set_maptype(mAltosDroid.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 */ @@ -348,12 +344,6 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {  	}  	@Override -	public void onDetach() { -		super.onDetach(); -		mAltosDroid = null; -	} - -	@Override  	public void onCreate(Bundle savedInstanceState) {  		super.onCreate(savedInstanceState);  	} @@ -382,7 +372,6 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {  	public void onDestroyView() {  		super.onDestroyView(); -		mAltosDroid.unregisterTab(this);  	}  	private void center(double lat, double lon, double accuracy) { @@ -395,7 +384,7 @@ public class TabMapOffline extends AltosDroidTab implements AltosMapInterface {  	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); @@ -411,20 +400,30 @@ 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; +		if (telem_state != null) { +			Integer[] old_serial = rockets.keySet().toArray(new Integer[0]); +			Integer[] new_serial = telem_state.states.keySet().toArray(new Integer[0]); -			Rocket	rocket = null; +			/* remove deleted keys */ +			for (int serial : old_serial) { +				if (!telem_state.states.containsKey(serial)) +					rockets.remove(serial); +			} + +			/* set remaining keys */ -			if (state.gps != null && state.gps.locked) { -				if (!rockets.containsKey(serial)) { +			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); -				} else -					rocket = rockets.get(serial); -				rocket.set_position(new AltosLatLon(state.gps.lat, state.gps.lon)); +				} +				rocket.set_position(new AltosLatLon(t_state.gps.lat, t_state.gps.lon));  			}  		} diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java index f7eb43db..7a256963 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java @@ -30,8 +30,6 @@ import android.widget.TextView;  import android.location.Location;  public class TabPad extends AltosDroidTab { -	AltosDroid mAltosDroid; -  	private TextView mBatteryVoltageView;  	private TextView mBatteryVoltageLabel;  	private GoNoGoLights mBatteryLights; @@ -52,13 +50,6 @@ public class TabPad extends AltosDroidTab {  	private TextView mPadAltitudeView;  	@Override -	public void onAttach(Activity activity) { -		super.onAttach(activity); -		mAltosDroid = (AltosDroid) activity; -		mAltosDroid.registerTab(this); -	} - -	@Override  	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  		View v = inflater.inflate(R.layout.tab_pad, container, false);  		mBatteryVoltageView = (TextView) v.findViewById(R.id.battery_voltage_value); @@ -100,16 +91,9 @@ public class TabPad extends AltosDroidTab {          return v;  	} -	@Override -	public void onDestroy() { -		super.onDestroy(); -		mAltosDroid.unregisterTab(this); -		mAltosDroid = null; -	} -  	public String tab_name() { return "pad"; } -	public void show(AltosState state, AltosGreatCircle from_receiver, Location receiver) { +	public void show(TelemetryState telem_state, AltosState state, AltosGreatCircle from_receiver, Location receiver) {  		if (state != null) {  			mBatteryVoltageView.setText(AltosDroid.number("%4.2f V", state.battery_voltage));  			mBatteryLights.set(state.battery_voltage >= AltosLib.ao_battery_good, state.battery_voltage == AltosLib.MISSING); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryLogger.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryLogger.java index 7c3c2268..28bab401 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryLogger.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryLogger.java @@ -34,7 +34,7 @@ public class TelemetryLogger {  			logger = null;  		}  	} -	 +  	void handleExternalStorageState() {  		String state = Environment.getExternalStorageState();  		if (Environment.MEDIA_MOUNTED.equals(state)) { diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java index 7b29fe44..4d4f0ed1 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java @@ -21,6 +21,7 @@ package org.altusmetrum.AltosDroid;  import java.text.*;  import java.io.*; +import java.util.*;  import java.util.concurrent.*;  import android.os.Handler; @@ -34,25 +35,18 @@ public class TelemetryReader extends Thread {  	Handler     handler;  	AltosLink   link; -	AltosState  state = null;  	LinkedBlockingQueue<AltosLine> telemQueue; -	public AltosState read() throws ParseException, AltosCRCException, InterruptedException, IOException { +	public AltosTelemetry read() throws ParseException, AltosCRCException, InterruptedException, IOException {  		AltosLine l = telemQueue.take();  		if (l.line == null)  			throw new IOException("IO error");  		AltosTelemetry telem = AltosTelemetryLegacy.parse(l.line); -		if (state == null) -			state = new AltosState(); -		else -			state = state.clone(); -		telem.update_state(state); -		return state; +		return telem;  	}  	public void close() { -		state = null;  		link.remove_monitor(telemQueue);  		link = null;  		telemQueue.clear(); @@ -60,14 +54,12 @@ public class TelemetryReader extends Thread {  	}  	public void run() { -		AltosState  state = null; -  		try {  			AltosDebug.debug("starting loop");  			while (telemQueue != null) {  				try { -					state = read(); -					handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget(); +					AltosTelemetry	telem = read(); +					handler.obtainMessage(TelemetryService.MSG_TELEMETRY, telem).sendToTarget();  				} catch (ParseException pp) {  					AltosDebug.error("Parse error: %d \"%s\"", pp.getErrorOffset(), pp.getMessage());  				} catch (AltosCRCException ce) { @@ -84,12 +76,11 @@ public class TelemetryReader extends Thread {  		}  	} -	public TelemetryReader (AltosLink in_link, Handler in_handler, AltosState in_state) { +	public TelemetryReader (AltosLink in_link, Handler in_handler) {  		AltosDebug.debug("connected TelemetryReader create started");  		link    = in_link;  		handler = in_handler; -		state = in_state;  		telemQueue = new LinkedBlockingQueue<AltosLine>();  		link.add_monitor(telemQueue);  		link.set_telemetry(AltosLib.ao_telemetry_standard); diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java index eae360db..80694ea7 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java @@ -18,10 +18,8 @@  package org.altusmetrum.AltosDroid;  import java.lang.ref.WeakReference; -import java.util.ArrayList;  import java.util.concurrent.TimeoutException; -import java.util.Timer; -import java.util.TimerTask; +import java.util.*;  import android.app.Notification;  //import android.app.NotificationManager; @@ -62,6 +60,7 @@ public class TelemetryService extends Service implements LocationListener {  	static final int MSG_CRC_ERROR	       = 10;  	static final int MSG_SETBAUD	       = 11;  	static final int MSG_DISCONNECT	       = 12; +	static final int MSG_DELETE_SERIAL     = 13;  	// Unique Identification Number for the Notification.  	// We use it on Notification start, and to cancel it. @@ -120,6 +119,10 @@ public class TelemetryService extends Service implements LocationListener {  				s.address = null;  				s.disconnect(true);  				break; +			case MSG_DELETE_SERIAL: +				AltosDebug.debug("Delete Serial command received"); +				s.delete_serial((Integer) msg.obj); +				break;  			case MSG_SETFREQUENCY:  				AltosDebug.debug("MSG_SETFREQUENCY");  				s.telemetry_state.frequency = (Double) msg.obj; @@ -197,13 +200,8 @@ public class TelemetryService extends Service implements LocationListener {  				 * Messages from TelemetryReader  				 */  			case MSG_TELEMETRY: -				s.telemetry_state.state = (AltosState) msg.obj; -				if (s.telemetry_state.state != null) { -					AltosDebug.debug("Save state"); -					AltosPreferences.set_state(0, s.telemetry_state.state, null); -				}  				AltosDebug.debug("MSG_TELEMETRY"); -				s.send_to_clients(); +				s.telemetry((AltosTelemetry) msg.obj);  				break;  			case MSG_CRC_ERROR:  				// forward crc error messages @@ -217,13 +215,31 @@ public class TelemetryService extends Service implements LocationListener {  		}  	} +	/* Handle telemetry packet +	 */ +	private void telemetry(AltosTelemetry telem) { +		AltosState	state; + +		if (telemetry_state.states.containsKey(telem.serial)) +			state = telemetry_state.states.get(telem.serial).clone(); +		else +			state = new AltosState(); +		telem.update_state(state); +		telemetry_state.states.put(telem.serial, state); +		if (state != null) { +			AltosDebug.debug("Save state %d", telem.serial); +			AltosPreferences.set_state(telem.serial, state, null); +		} +		send_to_clients(); +	} +  	/* Construct the message to deliver to clients  	 */  	private Message message() {  		if (telemetry_state == null)  			AltosDebug.debug("telemetry_state null!"); -		if (telemetry_state.state == null) -			AltosDebug.debug("telemetry_state.state null!"); +		if (telemetry_state.states == null) +			AltosDebug.debug("telemetry_state.states null!");  		return Message.obtain(null, AltosDroid.MSG_STATE, telemetry_state);  	} @@ -332,6 +348,12 @@ public class TelemetryService extends Service implements LocationListener {  		}  	} +	private void delete_serial(int serial) { +		telemetry_state.states.remove((Integer) serial); +		AltosPreferences.remove_state(serial); +		send_to_clients(); +	} +  	private void start_altos_bluetooth(DeviceAddress address, boolean pause) {  		// Get the BLuetoothDevice object  		BluetoothDevice device = bluetooth_adapter.getRemoteDevice(address.address); @@ -372,7 +394,7 @@ public class TelemetryService extends Service implements LocationListener {  		telemetry_state.connect = TelemetryState.CONNECT_CONNECTED;  		telemetry_state.address = address; -		telemetry_reader = new TelemetryReader(altos_link, handler, telemetry_state.state); +		telemetry_reader = new TelemetryReader(altos_link, handler);  		telemetry_reader.start();  		AltosDebug.debug("connected TelemetryReader started"); @@ -406,11 +428,32 @@ public class TelemetryService extends Service implements LocationListener {  		telemetry_state.connect = TelemetryState.CONNECT_DISCONNECTED;  		telemetry_state.address = null; -		AltosSavedState saved_state = AltosPreferences.state(0); +		/* Pull the saved state information out of the preferences database +		 */ +		ArrayList<Integer> serials = AltosPreferences.list_states(); -		if (saved_state != null) { -			AltosDebug.debug("recovered old state flight %d\n", saved_state.state.flight); -			telemetry_state.state = saved_state.state; +		telemetry_state.latest_serial = AltosPreferences.latest_state(); + +		for (int serial : serials) { +			AltosSavedState saved_state = AltosPreferences.state(serial); +			if (saved_state != null) { +				if (serial == 0) { +					serial = saved_state.state.serial; +					AltosPreferences.set_state(serial, saved_state.state, saved_state.listener_state); +					AltosPreferences.remove_state(0); +				} +				if (telemetry_state.latest_serial == 0) +					telemetry_state.latest_serial = serial; + +				AltosDebug.debug("recovered old state serial %d flight %d\n", +						 serial, +						 saved_state.state.flight); +				if (saved_state.state.gps != null) +					AltosDebug.debug("\tposition %f,%f\n", +							 saved_state.state.gps.lat, +							 saved_state.state.gps.lon); +				telemetry_state.states.put(serial, saved_state.state); +			}  		}  		// Listen for GPS and Network position updates diff --git a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryState.java b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryState.java index fb7e1893..d023128f 100644 --- a/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryState.java +++ b/altosdroid/src/org/altusmetrum/AltosDroid/TelemetryState.java @@ -17,6 +17,7 @@  package org.altusmetrum.AltosDroid; +import java.util.*;  import org.altusmetrum.altoslib_7.*;  import android.location.Location; @@ -29,16 +30,19 @@ public class TelemetryState {  	int		connect;  	DeviceAddress	address;  	AltosConfigData	config; -	AltosState	state;  	Location	location;  	int		crc_errors;  	double		frequency;  	int		telemetry_rate; +	HashMap<Integer,AltosState>	states; + +	int		latest_serial; +  	public TelemetryState() {  		connect = CONNECT_NONE;  		config = null; -		state = null; +		states = new HashMap<Integer,AltosState>();  		location = null;  		crc_errors = 0;  		frequency = AltosPreferences.frequency(0); | 
