Merge "Address multiple RemoteControlDisplay competing for registration"

This commit is contained in:
Jean-Michel Trivi
2011-08-26 18:17:40 -07:00
committed by Android (Google) Code Review

View File

@@ -81,6 +81,10 @@ public class AudioService extends IAudioService.Stub {
private static final String TAG = "AudioService"; private static final String TAG = "AudioService";
/** Debug remote control client/display feature */
// TODO set to false before release
protected static final boolean DEBUG_RC = true;
/** How long to delay before persisting a change in volume/ringer mode. */ /** How long to delay before persisting a change in volume/ringer mode. */
private static final int PERSIST_DELAY = 3000; private static final int PERSIST_DELAY = 3000;
@@ -3072,7 +3076,7 @@ public class AudioService extends IAudioService.Stub {
/** /**
* Update the remote control displays with the new "focused" client generation * Update the remote control displays with the new "focused" client generation
*/ */
private void setNewRcClientOnDisplays_syncAfRcsCurrc(int newClientGeneration, private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
ComponentName newClientEventReceiver, boolean clearing) { ComponentName newClientEventReceiver, boolean clearing) {
// NOTE: Only one IRemoteControlDisplay supported in this implementation // NOTE: Only one IRemoteControlDisplay supported in this implementation
if (mRcDisplay != null) { if (mRcDisplay != null) {
@@ -3091,7 +3095,7 @@ public class AudioService extends IAudioService.Stub {
/** /**
* Update the remote control clients with the new "focused" client generation * Update the remote control clients with the new "focused" client generation
*/ */
private void setNewRcClientGenerationOnClients_syncAfRcsCurrc(int newClientGeneration) { private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) { while(stackIterator.hasNext()) {
RemoteControlStackEntry se = stackIterator.next(); RemoteControlStackEntry se = stackIterator.next();
@@ -3115,27 +3119,26 @@ public class AudioService extends IAudioService.Stub {
* @param clearing true if the new client generation value maps to a remote control update * @param clearing true if the new client generation value maps to a remote control update
* where the display should be cleared. * where the display should be cleared.
*/ */
private void setNewRcClient_syncAfRcsCurrc(int newClientGeneration, private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
ComponentName newClientEventReceiver, boolean clearing) { ComponentName newClientEventReceiver, boolean clearing) {
// send the new valid client generation ID to all displays // send the new valid client generation ID to all displays
setNewRcClientOnDisplays_syncAfRcsCurrc(newClientGeneration, newClientEventReceiver, setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newClientEventReceiver,
clearing); clearing);
// send the new valid client generation ID to all clients // send the new valid client generation ID to all clients
setNewRcClientGenerationOnClients_syncAfRcsCurrc(newClientGeneration); setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
} }
/** /**
* Called when processing MSG_RCDISPLAY_CLEAR event * Called when processing MSG_RCDISPLAY_CLEAR event
*/ */
private void onRcDisplayClear() { private void onRcDisplayClear() {
// TODO remove log before release if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
Log.i(TAG, "Clear remote control display");
synchronized(mRCStack) { synchronized(mRCStack) {
synchronized(mCurrentRcLock) { synchronized(mCurrentRcLock) {
mCurrentRcClientGen++; mCurrentRcClientGen++;
// synchronously update the displays and clients with the new client generation // synchronously update the displays and clients with the new client generation
setNewRcClient_syncAfRcsCurrc(mCurrentRcClientGen, setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
null /*event receiver*/, true /*clearing*/); null /*event receiver*/, true /*clearing*/);
} }
} }
@@ -3148,13 +3151,12 @@ public class AudioService extends IAudioService.Stub {
synchronized(mRCStack) { synchronized(mRCStack) {
synchronized(mCurrentRcLock) { synchronized(mCurrentRcLock) {
if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
// TODO remove log before release if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
Log.i(TAG, "Display/update remote control ");
mCurrentRcClientGen++; mCurrentRcClientGen++;
// synchronously update the displays and clients with // synchronously update the displays and clients with
// the new client generation // the new client generation
setNewRcClient_syncAfRcsCurrc(mCurrentRcClientGen, setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
rcse.mReceiverComponent /*event receiver*/, rcse.mReceiverComponent /*event receiver*/,
false /*clearing*/); false /*clearing*/);
@@ -3374,26 +3376,37 @@ public class AudioService extends IAudioService.Stub {
* of displays if necessary. * of displays if necessary.
*/ */
private class RcDisplayDeathHandler implements IBinder.DeathRecipient { private class RcDisplayDeathHandler implements IBinder.DeathRecipient {
private IBinder mCb; // To be notified of client's death
public RcDisplayDeathHandler(IBinder b) {
if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b);
mCb = b;
}
public void binderDied() { public void binderDied() {
synchronized(mRCStack) { synchronized(mRCStack) {
Log.w(TAG, " RemoteControl: display died"); Log.w(TAG, "RemoteControl: display died");
mRcDisplay = null; mRcDisplay = null;
} }
} }
public void unlinkToRcDisplayDeath() {
if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb);
try {
mCb.unlinkToDeath(this, 0);
} catch (java.util.NoSuchElementException e) {
// not much we can do here, the display was being unregistered anyway
Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()");
e.printStackTrace();
}
}
} }
private void rcDisplay_stopDeathMonitor_syncRcStack() { private void rcDisplay_stopDeathMonitor_syncRcStack() {
if (mRcDisplay != null) { if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null)
// we had a display before, stop monitoring its death // we had a display before, stop monitoring its death
IBinder b = mRcDisplay.asBinder(); mRcDisplayDeathHandler.unlinkToRcDisplayDeath();
try {
b.unlinkToDeath(mRcDisplayDeathHandler, 0);
} catch (java.util.NoSuchElementException e) {
// being conservative here
Log.e(TAG, "Error while trying to unlink display death handler " + e);
e.printStackTrace();
}
} }
} }
@@ -3401,7 +3414,7 @@ public class AudioService extends IAudioService.Stub {
if (mRcDisplay != null) { if (mRcDisplay != null) {
// new non-null display, monitor its death // new non-null display, monitor its death
IBinder b = mRcDisplay.asBinder(); IBinder b = mRcDisplay.asBinder();
mRcDisplayDeathHandler = new RcDisplayDeathHandler(); mRcDisplayDeathHandler = new RcDisplayDeathHandler(b);
try { try {
b.linkToDeath(mRcDisplayDeathHandler, 0); b.linkToDeath(mRcDisplayDeathHandler, 0);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -3412,9 +3425,15 @@ public class AudioService extends IAudioService.Stub {
} }
} }
/**
* Register an IRemoteControlDisplay and notify all IRemoteControlClient of the new display.
* Since only one IRemoteControlDisplay is supported, this will unregister the previous display.
* @param rcd the IRemoteControlDisplay to register. No effect if null.
*/
public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) { public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
synchronized(mRCStack) { synchronized(mRCStack) {
if (mRcDisplay == rcd) { if ((mRcDisplay == rcd) || (rcd == null)) {
return; return;
} }
// if we had a display before, stop monitoring its death // if we had a display before, stop monitoring its death
@@ -3424,6 +3443,8 @@ public class AudioService extends IAudioService.Stub {
rcDisplay_startDeathMonitor_syncRcStack(); rcDisplay_startDeathMonitor_syncRcStack();
// let all the remote control clients there is a new display // let all the remote control clients there is a new display
// no need to unplug the previous because we only support one display
// and the clients don't track the death of the display
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) { while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = stackIterator.next(); RemoteControlStackEntry rcse = stackIterator.next();
@@ -3439,8 +3460,20 @@ public class AudioService extends IAudioService.Stub {
} }
} }
/**
* Unregister an IRemoteControlDisplay.
* Since only one IRemoteControlDisplay is supported, this has no effect if the one to
* unregister is not the current one.
* @param rcd the IRemoteControlDisplay to unregister. No effect if null.
*/
public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) { public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
synchronized(mRCStack) { synchronized(mRCStack) {
// only one display here, so you can only unregister the current display
if ((rcd == null) || (rcd != mRcDisplay)) {
if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD");
return;
}
// if we had a display before, stop monitoring its death // if we had a display before, stop monitoring its death
rcDisplay_stopDeathMonitor_syncRcStack(); rcDisplay_stopDeathMonitor_syncRcStack();
mRcDisplay = null; mRcDisplay = null;