Merge "Address multiple RemoteControlDisplay competing for registration"
This commit is contained in:
committed by
Android (Google) Code Review
commit
28c5b96d84
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user