mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-12-01 09:24:10 +01:00
AndroidGCS: More refactoring of ObjectManagerActivity. Now the updates are
disconnected on pause and reestabilished on resume. This only happens within an onConnected/onDisconnected life cycle.
This commit is contained in:
parent
176922f41c
commit
29d5365f0a
@ -32,11 +32,11 @@ package org.openpilot.androidgcs;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
import org.openpilot.androidgcs.fragments.ObjectManagerFragment;
|
import org.openpilot.androidgcs.fragments.ObjectManagerFragment;
|
||||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService;
|
import org.openpilot.androidgcs.telemetry.OPTelemetryService;
|
||||||
import org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder;
|
import org.openpilot.androidgcs.telemetry.OPTelemetryService.LocalBinder;
|
||||||
@ -79,7 +79,8 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
BroadcastReceiver connectedReceiver;
|
BroadcastReceiver connectedReceiver;
|
||||||
//! Indicate if this activity has already connected it's telemetry callbacks
|
//! Indicate if this activity has already connected it's telemetry callbacks
|
||||||
private boolean telemetryStatsConnected = false;
|
private boolean telemetryStatsConnected = false;
|
||||||
|
//! Maintain a list of all the UAVObject listeners for this activity
|
||||||
|
private HashMap<Observer, UAVObject> listeners;
|
||||||
/** Called when the activity is first created. */
|
/** Called when the activity is first created. */
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@ -88,84 +89,12 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called whenever any objects subscribed to via registerObjects
|
* Called whenever any objects subscribed to via registerObjects
|
||||||
|
* whenever this Activity is not paused
|
||||||
*/
|
*/
|
||||||
protected void objectUpdated(UAVObject obj) {
|
protected void objectUpdated(UAVObject obj) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A message handler and a custom Observer to use it which calls
|
|
||||||
* objectUpdated with the right object type
|
|
||||||
*/
|
|
||||||
final Handler uavobjHandler = new Handler();
|
|
||||||
private class ActivityUpdatedObserver implements Observer {
|
|
||||||
UAVObject obj;
|
|
||||||
ActivityUpdatedObserver(UAVObject obj) { this.obj = obj; };
|
|
||||||
@Override
|
|
||||||
public void update(Observable observable, Object data) {
|
|
||||||
uavobjHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() { objectUpdated(obj); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private class FragmentUpdatedObserver implements Observer {
|
|
||||||
UAVObject obj;
|
|
||||||
ObjectManagerFragment frag;
|
|
||||||
FragmentUpdatedObserver(UAVObject obj, ObjectManagerFragment frag) {
|
|
||||||
this.obj = obj;
|
|
||||||
this.frag = frag;
|
|
||||||
};
|
|
||||||
@Override
|
|
||||||
public void update(Observable observable, Object data) {
|
|
||||||
uavobjHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() { frag.objectUpdated(obj); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register an activity to receive updates from this object
|
|
||||||
*
|
|
||||||
* the objectUpdated() method will be called in the original UI thread
|
|
||||||
*/
|
|
||||||
HashMap<Observer, UAVObject> listeners = new HashMap<Observer,UAVObject>();
|
|
||||||
protected void registerObjectUpdates(UAVObject object) {
|
|
||||||
Observer o = new ActivityUpdatedObserver(object);
|
|
||||||
object.addUpdatedObserver(o);
|
|
||||||
listeners.put(o, object);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Unregister all the objects connected to this activity
|
|
||||||
*/
|
|
||||||
protected void unregisterObjectUpdates()
|
|
||||||
{
|
|
||||||
Set<Observer> s = listeners.keySet();
|
|
||||||
Iterator<Observer> i = s.iterator();
|
|
||||||
while (i.hasNext()) {
|
|
||||||
Observer o = i.next();
|
|
||||||
UAVObject obj = listeners.get(o);
|
|
||||||
obj.removeUpdatedObserver(o);
|
|
||||||
}
|
|
||||||
listeners.clear();
|
|
||||||
}
|
|
||||||
public void registerObjectUpdates(UAVObject object,
|
|
||||||
ObjectManagerFragment frag) {
|
|
||||||
Observer o = new FragmentUpdatedObserver(object, frag);
|
|
||||||
object.addUpdatedObserver(o);
|
|
||||||
listeners.put(o, object);
|
|
||||||
}
|
|
||||||
protected void registerObjectUpdates(List<List<UAVObject>> objects) {
|
|
||||||
ListIterator<List<UAVObject>> li = objects.listIterator();
|
|
||||||
while(li.hasNext()) {
|
|
||||||
ListIterator<UAVObject> li2 = li.next().listIterator();
|
|
||||||
while(li2.hasNext())
|
|
||||||
registerObjectUpdates(li2.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateStats() {
|
private void updateStats() {
|
||||||
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
TextView rxRate = (TextView) findViewById(R.id.telemetry_stats_rx_rate);
|
TextView rxRate = (TextView) findViewById(R.id.telemetry_stats_rx_rate);
|
||||||
@ -199,14 +128,21 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
if ( telemetryStatsConnected )
|
if ( telemetryStatsConnected )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Create a map for all the object updates register for this activity. If anyone
|
||||||
|
// tries to register an object update before this a null exception will occur
|
||||||
|
listeners = new HashMap<Observer,UAVObject>();
|
||||||
|
|
||||||
// We are not using the objectUpdated mechanism in place so that all the children
|
// We are not using the objectUpdated mechanism in place so that all the children
|
||||||
// don't have to sort through the messages.
|
// don't have to sort through the messages.
|
||||||
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
|
||||||
if (stats == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
stats.addUpdatedObserver(telemetryObserver);
|
if (!telemetryStatsConnected) {
|
||||||
telemetryStatsConnected = true;
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
|
if (stats == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stats.addUpdatedObserver(telemetryObserver);
|
||||||
|
telemetryStatsConnected = true;
|
||||||
|
}
|
||||||
updateStats();
|
updateStats();
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "Notifying listeners about connection. There are " + connectionListeners.countObservers());
|
if (DEBUG) Log.d(TAG, "Notifying listeners about connection. There are " + connectionListeners.countObservers());
|
||||||
@ -228,44 +164,62 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
// Providing a null update triggers a disconnect on fragments
|
// Providing a null update triggers a disconnect on fragments
|
||||||
connectionListeners.disconnected();
|
connectionListeners.disconnected();
|
||||||
|
|
||||||
|
if (objMngr == null) {
|
||||||
|
Log.d(TAG, "onOPDisconnected(): Object manager already went away");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (telemetryStatsConnected) {
|
||||||
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
|
if (stats != null) {
|
||||||
|
stats.removeUpdatedObserver(telemetryObserver);
|
||||||
|
}
|
||||||
|
telemetryStatsConnected = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Disconnect from any UAVO updates
|
// Disconnect from any UAVO updates
|
||||||
unregisterObjectUpdates();
|
if (DEBUG) Log.d(TAG, "onOpDisconnected(): Pausing the listeners and deleting the list");
|
||||||
|
pauseObjectUpdates();
|
||||||
|
listeners = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (mConnected && !telemetryStatsConnected) {
|
||||||
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
|
if (stats == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stats.addUpdatedObserver(telemetryObserver);
|
||||||
|
telemetryStatsConnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
resumeObjectUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
protected void onPause() {
|
||||||
if (!mBound || binder == null) {
|
super.onPause();
|
||||||
Log.e(TAG, "Unable to connect to service");
|
|
||||||
return super.onOptionsItemSelected(item);
|
if (telemetryStatsConnected) {
|
||||||
}
|
UAVObject stats = objMngr.getObject("GCSTelemetryStats");
|
||||||
switch(item.getItemId()) {
|
Assert.assertNotNull(stats); // Should not be null if we connected
|
||||||
case R.id.menu_connect:
|
|
||||||
binder.openConnection();
|
stats.removeUpdatedObserver(telemetryObserver);
|
||||||
return true;
|
telemetryStatsConnected = false;
|
||||||
case R.id.menu_disconnect:
|
|
||||||
binder.stopConnection();
|
|
||||||
return true;
|
|
||||||
case R.id.menu_settings:
|
|
||||||
startActivity(new Intent(this, Preferences.class));
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
pauseObjectUpdates();
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
MenuInflater inflater = getMenuInflater();
|
|
||||||
inflater.inflate(R.menu.status_menu, menu);
|
|
||||||
inflater.inflate(R.menu.options_menu, menu);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
if (DEBUG) Log.d(TAG, "onStart()");
|
if (DEBUG) Log.d(TAG, "onStart()");
|
||||||
|
|
||||||
// Register a receiver to get connected/disconnected signals from the telemetry
|
// Register a receiver to get connected/disconnected signals from the telemetry
|
||||||
// service
|
// service
|
||||||
connectedReceiver = new BroadcastReceiver() {
|
connectedReceiver = new BroadcastReceiver() {
|
||||||
@ -284,9 +238,9 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
onOPConnected();
|
onOPConnected();
|
||||||
Log.d(TAG, "Connected()");
|
Log.d(TAG, "Connected()");
|
||||||
} else if (intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_DISCONNECTED) == 0) {
|
} else if (intent.getAction().compareTo(OPTelemetryService.INTENT_ACTION_DISCONNECTED) == 0) {
|
||||||
|
onOPDisconnected();
|
||||||
objMngr = null;
|
objMngr = null;
|
||||||
mConnected = false;
|
mConnected = false;
|
||||||
onOPDisconnected();
|
|
||||||
Log.d(TAG, "Disonnected()");
|
Log.d(TAG, "Disonnected()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,13 +274,131 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
connectedReceiver = null;
|
connectedReceiver = null;
|
||||||
|
|
||||||
// Disconnect from any UAVO updates
|
// Disconnect from any UAVO updates
|
||||||
unregisterObjectUpdates();
|
if (DEBUG) Log.d(TAG, "onStop(): Pausing the listeners and deleting the list");
|
||||||
|
pauseObjectUpdates();
|
||||||
|
listeners = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBind() {
|
/*********** This provides the object update messaging service ************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message handler and a custom Observer to use it which calls
|
||||||
|
* objectUpdated with the right object type
|
||||||
|
*/
|
||||||
|
final Handler uavobjHandler = new Handler();
|
||||||
|
private class ActivityUpdatedObserver implements Observer {
|
||||||
|
UAVObject obj;
|
||||||
|
ActivityUpdatedObserver(UAVObject obj) { this.obj = obj; };
|
||||||
|
@Override
|
||||||
|
public void update(Observable observable, Object data) {
|
||||||
|
uavobjHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() { objectUpdated(obj); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private class FragmentUpdatedObserver implements Observer {
|
||||||
|
UAVObject obj;
|
||||||
|
ObjectManagerFragment frag;
|
||||||
|
FragmentUpdatedObserver(UAVObject obj, ObjectManagerFragment frag) {
|
||||||
|
this.obj = obj;
|
||||||
|
this.frag = frag;
|
||||||
|
};
|
||||||
|
@Override
|
||||||
|
public void update(Observable observable, Object data) {
|
||||||
|
uavobjHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() { frag.objectUpdated(obj); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister all the objects connected to this activity
|
||||||
|
*/
|
||||||
|
private boolean paused = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an activity is paused, disconnect from all
|
||||||
|
* updates to ensure we don't draw to an invalid view
|
||||||
|
*/
|
||||||
|
protected void pauseObjectUpdates()
|
||||||
|
{
|
||||||
|
// When listeners is null then a pause occurred after
|
||||||
|
// disconnecting from the service
|
||||||
|
if (listeners == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Set<Observer> s = listeners.keySet();
|
||||||
|
Iterator<Observer> i = s.iterator();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
Observer o = i.next();
|
||||||
|
UAVObject obj = listeners.get(o);
|
||||||
|
obj.removeUpdatedObserver(o);
|
||||||
|
}
|
||||||
|
paused = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an activity is resumed, reconnect all now the view
|
||||||
|
* is valid again
|
||||||
|
*/
|
||||||
|
protected void resumeObjectUpdates()
|
||||||
|
{
|
||||||
|
// When listeners is null this is the resume at the beginning
|
||||||
|
// before connecting to the telemetry service
|
||||||
|
if(listeners == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Set<Observer> s = listeners.keySet();
|
||||||
|
Iterator<Observer> i = s.iterator();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
Observer o = i.next();
|
||||||
|
UAVObject obj = listeners.get(o);
|
||||||
|
obj.addUpdatedObserver(o);
|
||||||
|
}
|
||||||
|
paused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register to listen to a single object from a fragment
|
||||||
|
* @param object The object to listen to updates from
|
||||||
|
* @param frag The fragment who should be notified
|
||||||
|
* the objectUpdated() method will be called in the original UI thread
|
||||||
|
*/
|
||||||
|
public void registerObjectUpdates(UAVObject object,
|
||||||
|
ObjectManagerFragment frag) {
|
||||||
|
Observer o = new FragmentUpdatedObserver(object, frag);
|
||||||
|
listeners.put(o, object);
|
||||||
|
if (!paused)
|
||||||
|
object.addUpdatedObserver(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an activity to receive updates from this object
|
||||||
|
* @param object The object the activity should listen to updates from
|
||||||
|
* the objectUpdated() method will be called in the original UI thread
|
||||||
|
*/
|
||||||
|
protected void registerObjectUpdates(UAVObject object) {
|
||||||
|
Observer o = new ActivityUpdatedObserver(object);
|
||||||
|
listeners.put(o, object);
|
||||||
|
if (!paused)
|
||||||
|
object.addUpdatedObserver(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to register array of objects
|
||||||
|
*/
|
||||||
|
protected void registerObjectUpdates(List<List<UAVObject>> objects) {
|
||||||
|
for (int i = 0; i < objects.size(); i++) {
|
||||||
|
List<UAVObject> inner = objects.get(i);
|
||||||
|
for (int j = 0; j < inner.size(); j++)
|
||||||
|
registerObjectUpdates(inner.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********** Deals with fragments listening for connections ***************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callbacks so ObjectManagerFragments get the onOPConnected and onOPDisconnected signals
|
* Callbacks so ObjectManagerFragments get the onOPConnected and onOPDisconnected signals
|
||||||
@ -363,7 +435,6 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
public void addOnConnectionListenerFragment(ObjectManagerFragment frag) {
|
public void addOnConnectionListenerFragment(ObjectManagerFragment frag) {
|
||||||
connectionListeners.addObserver(new OnConnectionListener(frag));
|
connectionListeners.addObserver(new OnConnectionListener(frag));
|
||||||
if (DEBUG) Log.d(TAG, "Connecting " + frag + " there are now " + connectionListeners.countObservers());
|
if (DEBUG) Log.d(TAG, "Connecting " + frag + " there are now " + connectionListeners.countObservers());
|
||||||
@ -372,6 +443,8 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********** Deals with (dis)connection to telemetry service ***************/
|
||||||
|
|
||||||
/** Defines callbacks for service binding, passed to bindService() */
|
/** Defines callbacks for service binding, passed to bindService() */
|
||||||
private final ServiceConnection mConnection = new ServiceConnection() {
|
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||||
@Override
|
@Override
|
||||||
@ -394,13 +467,45 @@ public abstract class ObjectManagerActivity extends Activity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(ComponentName name) {
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
onOPDisconnected();
|
||||||
mBound = false;
|
mBound = false;
|
||||||
binder = null;
|
binder = null;
|
||||||
mConnected = false;
|
mConnected = false;
|
||||||
objMngr = null;
|
objMngr = null;
|
||||||
objMngr = null;
|
objMngr = null;
|
||||||
mConnected = false;
|
mConnected = false;
|
||||||
onOPDisconnected();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/************* Deals with menus *****************/
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if (!mBound || binder == null) {
|
||||||
|
Log.e(TAG, "Unable to connect to service");
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
switch(item.getItemId()) {
|
||||||
|
case R.id.menu_connect:
|
||||||
|
binder.openConnection();
|
||||||
|
return true;
|
||||||
|
case R.id.menu_disconnect:
|
||||||
|
binder.stopConnection();
|
||||||
|
return true;
|
||||||
|
case R.id.menu_settings:
|
||||||
|
startActivity(new Intent(this, Preferences.class));
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
inflater.inflate(R.menu.status_menu, menu);
|
||||||
|
inflater.inflate(R.menu.options_menu, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user