Merge "Support multiple IRemoteControlDisplay" into jb-mr2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
7c8aeadd9a
@@ -2171,15 +2171,36 @@ public class AudioManager {
|
||||
/**
|
||||
* @hide
|
||||
* Registers a remote control display that will be sent information by remote control clients.
|
||||
* @param rcd
|
||||
* Use this method if your IRemoteControlDisplay is not going to display artwork, otherwise
|
||||
* use {@link #registerRemoteControlDisplay(IRemoteControlDisplay, int, int)} to pass the
|
||||
* artwork size directly, or
|
||||
* {@link #remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay, int, int)} later if artwork
|
||||
* is not yet needed.
|
||||
* @param rcd the IRemoteControlDisplay
|
||||
*/
|
||||
public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
|
||||
// passing a negative value for art work width and height as they are unknown at this stage
|
||||
registerRemoteControlDisplay(rcd, /*w*/-1, /*h*/ -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Registers a remote control display that will be sent information by remote control clients.
|
||||
* @param rcd
|
||||
* @param w the maximum width of the expected bitmap. Negative values indicate it is
|
||||
* useless to send artwork.
|
||||
* @param h the maximum height of the expected bitmap. Negative values indicate it is
|
||||
* useless to send artwork.
|
||||
*/
|
||||
public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
|
||||
if (rcd == null) {
|
||||
return;
|
||||
}
|
||||
IAudioService service = getService();
|
||||
try {
|
||||
service.registerRemoteControlDisplay(rcd);
|
||||
// passing a negative value for art work width and height as they are unknown at
|
||||
// this stage
|
||||
service.registerRemoteControlDisplay(rcd, w, h);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
|
||||
}
|
||||
@@ -2223,63 +2244,6 @@ public class AudioManager {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME remove because we are not using intents anymore between AudioService and RcDisplay
|
||||
/**
|
||||
* @hide
|
||||
* Broadcast intent action indicating that the displays on the remote controls
|
||||
* should be updated because a new remote control client is now active. If there is no
|
||||
* {@link #EXTRA_REMOTE_CONTROL_CLIENT}, the remote control display should be cleared
|
||||
* because there is no valid client to supply it with information.
|
||||
*
|
||||
* @see #EXTRA_REMOTE_CONTROL_CLIENT
|
||||
*/
|
||||
public static final String REMOTE_CONTROL_CLIENT_CHANGED =
|
||||
"android.media.REMOTE_CONTROL_CLIENT_CHANGED";
|
||||
|
||||
// FIXME remove because we are not using intents anymore between AudioService and RcDisplay
|
||||
/**
|
||||
* @hide
|
||||
* The IRemoteControlClientDispatcher monotonically increasing generation counter.
|
||||
*
|
||||
* @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
|
||||
*/
|
||||
public static final String EXTRA_REMOTE_CONTROL_CLIENT_GENERATION =
|
||||
"android.media.EXTRA_REMOTE_CONTROL_CLIENT_GENERATION";
|
||||
|
||||
// FIXME remove because we are not using intents anymore between AudioService and RcDisplay
|
||||
/**
|
||||
* @hide
|
||||
* The name of the RemoteControlClient.
|
||||
* This String is passed as the client name when calling methods from the
|
||||
* IRemoteControlClientDispatcher interface.
|
||||
*
|
||||
* @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
|
||||
*/
|
||||
public static final String EXTRA_REMOTE_CONTROL_CLIENT_NAME =
|
||||
"android.media.EXTRA_REMOTE_CONTROL_CLIENT_NAME";
|
||||
|
||||
// FIXME remove because we are not using intents anymore between AudioService and RcDisplay
|
||||
/**
|
||||
* @hide
|
||||
* The media button event receiver associated with the RemoteControlClient.
|
||||
* The {@link android.content.ComponentName} value of the event receiver can be retrieved with
|
||||
* {@link android.content.ComponentName#unflattenFromString(String)}
|
||||
*
|
||||
* @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
|
||||
*/
|
||||
public static final String EXTRA_REMOTE_CONTROL_EVENT_RECEIVER =
|
||||
"android.media.EXTRA_REMOTE_CONTROL_EVENT_RECEIVER";
|
||||
|
||||
// FIXME remove because we are not using intents anymore between AudioService and RcDisplay
|
||||
/**
|
||||
* @hide
|
||||
* The flags describing what information has changed in the current remote control client.
|
||||
*
|
||||
* @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
|
||||
*/
|
||||
public static final String EXTRA_REMOTE_CONTROL_CLIENT_INFO_CHANGED =
|
||||
"android.media.EXTRA_REMOTE_CONTROL_CLIENT_INFO_CHANGED";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Reload audio settings. This method is called by Settings backup
|
||||
|
||||
@@ -4905,7 +4905,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
" -- vol: " + rcse.mPlaybackVolume +
|
||||
" -- volMax: " + rcse.mPlaybackVolumeMax +
|
||||
" -- volObs: " + rcse.mRemoteVolumeObs);
|
||||
|
||||
}
|
||||
}
|
||||
synchronized (mMainRemote) {
|
||||
@@ -4921,6 +4920,23 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function:
|
||||
* Display in the log the current entries in the list of remote control displays
|
||||
*/
|
||||
private void dumpRCDList(PrintWriter pw) {
|
||||
pw.println("\nRemote Control Display list entries:");
|
||||
synchronized(mRCStack) {
|
||||
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
|
||||
pw.println(" IRCD: " + di.mRcDisplay +
|
||||
" -- w:" + di.mArtworkExpectedWidth +
|
||||
" -- h:" + di.mArtworkExpectedHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function:
|
||||
* Remove any entry in the remote control stack that has the same package name as packageName
|
||||
@@ -5059,16 +5075,20 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
*/
|
||||
private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
|
||||
PendingIntent newMediaIntent, boolean clearing) {
|
||||
// NOTE: Only one IRemoteControlDisplay supported in this implementation
|
||||
if (mRcDisplay != null) {
|
||||
try {
|
||||
mRcDisplay.setCurrentClientId(
|
||||
newClientGeneration, newMediaIntent, clearing);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e);
|
||||
// if we had a display before, stop monitoring its death
|
||||
rcDisplay_stopDeathMonitor_syncRcStack();
|
||||
mRcDisplay = null;
|
||||
synchronized(mRCStack) {
|
||||
if (mRcDisplays.size() > 0) {
|
||||
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForServer di = displayIterator.next();
|
||||
try {
|
||||
di.mRcDisplay.setCurrentClientId(
|
||||
newClientGeneration, newMediaIntent, clearing);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
|
||||
di.release();
|
||||
displayIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5086,7 +5106,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
try {
|
||||
se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e);
|
||||
Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
|
||||
stackIterator.remove();
|
||||
se.unlinkToRcClientDeath();
|
||||
}
|
||||
@@ -5144,8 +5164,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
|
||||
// tell the current client that it needs to send info
|
||||
try {
|
||||
mCurrentRcClient.onInformationRequested(mCurrentRcClientGen,
|
||||
flags, mArtworkExpectedWidth, mArtworkExpectedHeight);
|
||||
mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Current valid remote client is dead: "+e);
|
||||
mCurrentRcClient = null;
|
||||
@@ -5409,13 +5428,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
rccId = rcse.mRccId;
|
||||
|
||||
// there is a new (non-null) client:
|
||||
// 1/ give the new client the current display (if any)
|
||||
if (mRcDisplay != null) {
|
||||
try {
|
||||
rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
|
||||
}
|
||||
// 1/ give the new client the displays (if any)
|
||||
if (mRcDisplays.size() > 0) {
|
||||
plugRemoteControlDisplaysIntoClient_syncRcStack(rcse.mRcClient);
|
||||
}
|
||||
// 2/ monitor the new client's death
|
||||
IBinder b = rcse.mRcClient.asBinder();
|
||||
@@ -5485,102 +5500,141 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The remote control displays.
|
||||
* Access synchronized on mRCStack
|
||||
* NOTE: Only one IRemoteControlDisplay supported in this implementation
|
||||
*/
|
||||
private IRemoteControlDisplay mRcDisplay;
|
||||
private RcDisplayDeathHandler mRcDisplayDeathHandler;
|
||||
private int mArtworkExpectedWidth = -1;
|
||||
private int mArtworkExpectedHeight = -1;
|
||||
/**
|
||||
* Inner class to monitor remote control display deaths, and unregister them from the list
|
||||
* of displays if necessary.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* A class to encapsulate all the information about a remote control display.
|
||||
* After instanciation, init() must always be called before the object is added in the list
|
||||
* of displays.
|
||||
* Before being removed from the list of displays, release() must always be called (otherwise
|
||||
* it will leak death handlers).
|
||||
*/
|
||||
private class DisplayInfoForServer implements IBinder.DeathRecipient {
|
||||
/** may never be null */
|
||||
private IRemoteControlDisplay mRcDisplay;
|
||||
private IBinder mRcDisplayBinder;
|
||||
private int mArtworkExpectedWidth = -1;
|
||||
private int mArtworkExpectedHeight = -1;
|
||||
|
||||
public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
|
||||
if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
|
||||
mRcDisplay = rcd;
|
||||
mRcDisplayBinder = rcd.asBinder();
|
||||
mArtworkExpectedWidth = w;
|
||||
mArtworkExpectedHeight = h;
|
||||
}
|
||||
|
||||
public boolean init() {
|
||||
try {
|
||||
mRcDisplayBinder.linkToDeath(this, 0);
|
||||
} catch (RemoteException e) {
|
||||
// remote control display is DOA, disqualify it
|
||||
Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
try {
|
||||
mRcDisplayBinder.unlinkToDeath(this, 0);
|
||||
} catch (java.util.NoSuchElementException e) {
|
||||
// not much we can do here, the display should have been unregistered anyway
|
||||
Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void binderDied() {
|
||||
synchronized(mRCStack) {
|
||||
Log.w(TAG, "RemoteControl: display died");
|
||||
mRcDisplay = null;
|
||||
Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
|
||||
// remove the display from the list
|
||||
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
|
||||
if (di.mRcDisplay == mRcDisplay) {
|
||||
if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
|
||||
displayIterator.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null)
|
||||
// we had a display before, stop monitoring its death
|
||||
mRcDisplayDeathHandler.unlinkToRcDisplayDeath();
|
||||
}
|
||||
}
|
||||
|
||||
private void rcDisplay_startDeathMonitor_syncRcStack() {
|
||||
if (mRcDisplay != null) {
|
||||
// new non-null display, monitor its death
|
||||
IBinder b = mRcDisplay.asBinder();
|
||||
mRcDisplayDeathHandler = new RcDisplayDeathHandler(b);
|
||||
/**
|
||||
* The remote control displays.
|
||||
* Access synchronized on mRCStack
|
||||
*/
|
||||
private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
|
||||
|
||||
/**
|
||||
* Plug each registered display into the specified client
|
||||
* @param rcc, guaranteed non null
|
||||
*/
|
||||
private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
|
||||
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
|
||||
try {
|
||||
b.linkToDeath(mRcDisplayDeathHandler, 0);
|
||||
rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
|
||||
di.mArtworkExpectedHeight);
|
||||
} catch (RemoteException e) {
|
||||
// remote control display is DOA, disqualify it
|
||||
Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b);
|
||||
mRcDisplay = null;
|
||||
Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the remote control display interface already registered
|
||||
* @param rcd
|
||||
* @return true if the IRemoteControlDisplay is already in the list of displays
|
||||
*/
|
||||
private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
|
||||
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
|
||||
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an IRemoteControlDisplay.
|
||||
* Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
|
||||
* at the top of the stack to update the new display with its information.
|
||||
* Since only one IRemoteControlDisplay is supported, this will unregister the previous display.
|
||||
* @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
|
||||
* @param rcd the IRemoteControlDisplay to register. No effect if null.
|
||||
* @param w the maximum width of the expected bitmap. Negative or zero values indicate this
|
||||
* display doesn't need to receive artwork.
|
||||
* @param h the maximum height of the expected bitmap. Negative or zero values indicate this
|
||||
* display doesn't need to receive artwork.
|
||||
*/
|
||||
public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
|
||||
public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
|
||||
if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
|
||||
synchronized(mAudioFocusLock) {
|
||||
synchronized(mRCStack) {
|
||||
if ((mRcDisplay == rcd) || (rcd == null)) {
|
||||
if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
|
||||
return;
|
||||
}
|
||||
// if we had a display before, stop monitoring its death
|
||||
rcDisplay_stopDeathMonitor_syncRcStack();
|
||||
mRcDisplay = rcd;
|
||||
// new display, start monitoring its death
|
||||
rcDisplay_startDeathMonitor_syncRcStack();
|
||||
DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
|
||||
if (!di.init()) {
|
||||
if (DEBUG_RC) Log.e(TAG, " error registering RCD");
|
||||
return;
|
||||
}
|
||||
// add RCD to list of displays
|
||||
mRcDisplays.add(di);
|
||||
|
||||
// let all the remote control clients know there is a new display, so the remote
|
||||
// control stack traversal order doesn't matter.
|
||||
// No need to unplug the previous because we only support one display
|
||||
// and the clients don't track the death of the display
|
||||
// let all the remote control clients know there is a new display (so the remote
|
||||
// control stack traversal order doesn't matter).
|
||||
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
|
||||
while(stackIterator.hasNext()) {
|
||||
RemoteControlStackEntry rcse = stackIterator.next();
|
||||
if(rcse.mRcClient != null) {
|
||||
try {
|
||||
rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
|
||||
rcse.mRcClient.plugRemoteControlDisplay(rcd, w, h);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error connecting remote control display to client: " + e);
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "Error connecting RCD to client: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5593,44 +5647,86 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
|
||||
/**
|
||||
* Unregister an IRemoteControlDisplay.
|
||||
* Since only one IRemoteControlDisplay is supported, this has no effect if the one to
|
||||
* unregister is not the current one.
|
||||
* No effect if the IRemoteControlDisplay hasn't been successfully registered.
|
||||
* @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
|
||||
* @param rcd the IRemoteControlDisplay to unregister. No effect if null.
|
||||
*/
|
||||
public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
|
||||
if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
|
||||
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");
|
||||
if (rcd == null) {
|
||||
return;
|
||||
}
|
||||
// if we had a display before, stop monitoring its death
|
||||
rcDisplay_stopDeathMonitor_syncRcStack();
|
||||
mRcDisplay = null;
|
||||
|
||||
// disconnect this remote control display from all the clients, so the remote
|
||||
// control stack traversal order doesn't matter
|
||||
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
|
||||
while(stackIterator.hasNext()) {
|
||||
RemoteControlStackEntry rcse = stackIterator.next();
|
||||
if(rcse.mRcClient != null) {
|
||||
try {
|
||||
rcse.mRcClient.unplugRemoteControlDisplay(rcd);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error disconnecting remote control display to client: " + e);
|
||||
e.printStackTrace();
|
||||
boolean displayWasPluggedIn = false;
|
||||
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext() && !displayWasPluggedIn) {
|
||||
final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
|
||||
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
|
||||
displayWasPluggedIn = true;
|
||||
di.release();
|
||||
displayIterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (displayWasPluggedIn) {
|
||||
// disconnect this remote control display from all the clients, so the remote
|
||||
// control stack traversal order doesn't matter
|
||||
final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
|
||||
while(stackIterator.hasNext()) {
|
||||
final RemoteControlStackEntry rcse = stackIterator.next();
|
||||
if(rcse.mRcClient != null) {
|
||||
try {
|
||||
rcse.mRcClient.unplugRemoteControlDisplay(rcd);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error disconnecting remote control display to client: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the size of the artwork used by an IRemoteControlDisplay.
|
||||
* @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
|
||||
* @param rcd the IRemoteControlDisplay with the new artwork size requirement
|
||||
* @param w the maximum width of the expected bitmap. Negative or zero values indicate this
|
||||
* display doesn't need to receive artwork.
|
||||
* @param h the maximum height of the expected bitmap. Negative or zero values indicate this
|
||||
* display doesn't need to receive artwork.
|
||||
*/
|
||||
public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
|
||||
synchronized(mRCStack) {
|
||||
// NOTE: Only one IRemoteControlDisplay supported in this implementation
|
||||
mArtworkExpectedWidth = w;
|
||||
mArtworkExpectedHeight = h;
|
||||
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
|
||||
boolean artworkSizeUpdate = false;
|
||||
while (displayIterator.hasNext() && !artworkSizeUpdate) {
|
||||
final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
|
||||
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
|
||||
if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
|
||||
di.mArtworkExpectedWidth = w;
|
||||
di.mArtworkExpectedHeight = h;
|
||||
artworkSizeUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (artworkSizeUpdate) {
|
||||
// RCD is currently plugged in and its artwork size has changed, notify all RCCs,
|
||||
// stack traversal order doesn't matter
|
||||
final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
|
||||
while(stackIterator.hasNext()) {
|
||||
final RemoteControlStackEntry rcse = stackIterator.next();
|
||||
if(rcse.mRcClient != null) {
|
||||
try {
|
||||
rcse.mRcClient.setBitmapSizeForDisplay(rcd, w, h);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6233,6 +6329,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
||||
dumpFocusStack(pw);
|
||||
dumpRCStack(pw);
|
||||
dumpRCCStack(pw);
|
||||
dumpRCDList(pw);
|
||||
dumpStreamStates(pw);
|
||||
dumpRingerMode(pw);
|
||||
pw.println("\nAudio routes:");
|
||||
|
||||
@@ -131,8 +131,31 @@ interface IAudioService {
|
||||
oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
|
||||
in IRemoteControlClient rcClient);
|
||||
|
||||
oneway void registerRemoteControlDisplay(in IRemoteControlDisplay rcd);
|
||||
/**
|
||||
* Register an IRemoteControlDisplay.
|
||||
* Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
|
||||
* at the top of the stack to update the new display with its information.
|
||||
* @param rcd the IRemoteControlDisplay to register. No effect if null.
|
||||
* @param w the maximum width of the expected bitmap. Negative or zero values indicate this
|
||||
* display doesn't need to receive artwork.
|
||||
* @param h the maximum height of the expected bitmap. Negative or zero values indicate this
|
||||
* display doesn't need to receive artwork.
|
||||
*/
|
||||
oneway void registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
|
||||
/**
|
||||
* Unregister an IRemoteControlDisplay.
|
||||
* No effect if the IRemoteControlDisplay hasn't been successfully registered.
|
||||
* @param rcd the IRemoteControlDisplay to unregister. No effect if null.
|
||||
*/
|
||||
oneway void unregisterRemoteControlDisplay(in IRemoteControlDisplay rcd);
|
||||
/**
|
||||
* Update the size of the artwork used by an IRemoteControlDisplay.
|
||||
* @param rcd the IRemoteControlDisplay with the new artwork size requirement
|
||||
* @param w the maximum width of the expected bitmap. Negative or zero values indicate this
|
||||
* display doesn't need to receive artwork.
|
||||
* @param h the maximum height of the expected bitmap. Negative or zero values indicate this
|
||||
* display doesn't need to receive artwork.
|
||||
*/
|
||||
oneway void remoteControlDisplayUsesBitmapSize(in IRemoteControlDisplay rcd, int w, int h);
|
||||
|
||||
oneway void setPlaybackInfoForRcc(int rccId, int what, int value);
|
||||
|
||||
@@ -34,18 +34,17 @@ oneway interface IRemoteControlClient
|
||||
* parameters are valid.
|
||||
* @param generationId
|
||||
* @param infoFlags
|
||||
* @param artWidth if > 0, artHeight must be > 0 too.
|
||||
* @param artHeight
|
||||
* FIXME: is infoFlags required? since the RCC pushes info, this might always be called
|
||||
* with RC_INFO_ALL
|
||||
*/
|
||||
void onInformationRequested(int generationId, int infoFlags, int artWidth, int artHeight);
|
||||
void onInformationRequested(int generationId, int infoFlags);
|
||||
|
||||
/**
|
||||
* Sets the generation counter of the current client that is displayed on the remote control.
|
||||
*/
|
||||
void setCurrentClientGenerationId(int clientGeneration);
|
||||
|
||||
void plugRemoteControlDisplay(IRemoteControlDisplay rcd);
|
||||
void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h);
|
||||
void unplugRemoteControlDisplay(IRemoteControlDisplay rcd);
|
||||
void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
|
||||
}
|
||||
@@ -36,6 +36,8 @@ import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.IllegalArgumentException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* RemoteControlClient enables exposing information meant to be consumed by remote controls
|
||||
@@ -498,13 +500,7 @@ public class RemoteControlClient
|
||||
if (key != BITMAP_KEY_ARTWORK) {
|
||||
throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
|
||||
}
|
||||
if ((mArtworkExpectedWidth > 0) && (mArtworkExpectedHeight > 0)) {
|
||||
mEditorArtwork = scaleBitmapIfTooBig(bitmap,
|
||||
mArtworkExpectedWidth, mArtworkExpectedHeight);
|
||||
} else {
|
||||
// no valid resize dimensions, store as is
|
||||
mEditorArtwork = bitmap;
|
||||
}
|
||||
mEditorArtwork = bitmap;
|
||||
mArtworkChanged = true;
|
||||
return this;
|
||||
}
|
||||
@@ -536,10 +532,10 @@ public class RemoteControlClient
|
||||
synchronized(mCacheLock) {
|
||||
// assign the edited data
|
||||
mMetadata = new Bundle(mEditorMetadata);
|
||||
if ((mArtwork != null) && (!mArtwork.equals(mEditorArtwork))) {
|
||||
mArtwork.recycle();
|
||||
if ((mOriginalArtwork != null) && (!mOriginalArtwork.equals(mEditorArtwork))) {
|
||||
mOriginalArtwork.recycle();
|
||||
}
|
||||
mArtwork = mEditorArtwork;
|
||||
mOriginalArtwork = mEditorArtwork;
|
||||
mEditorArtwork = null;
|
||||
if (mMetadataChanged & mArtworkChanged) {
|
||||
// send to remote control display if conditions are met
|
||||
@@ -571,7 +567,7 @@ public class RemoteControlClient
|
||||
editor.mArtworkChanged = true;
|
||||
} else {
|
||||
editor.mEditorMetadata = new Bundle(mMetadata);
|
||||
editor.mEditorArtwork = mArtwork;
|
||||
editor.mEditorArtwork = mOriginalArtwork;
|
||||
editor.mMetadataChanged = false;
|
||||
editor.mArtworkChanged = false;
|
||||
}
|
||||
@@ -766,11 +762,7 @@ public class RemoteControlClient
|
||||
* accessed to be resized, in which case a copy will be made. This would add overhead in
|
||||
* Bundle operations.
|
||||
*/
|
||||
private Bitmap mArtwork;
|
||||
private final int ARTWORK_DEFAULT_SIZE = 256;
|
||||
private final int ARTWORK_INVALID_SIZE = -1;
|
||||
private int mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE;
|
||||
private int mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE;
|
||||
private Bitmap mOriginalArtwork;
|
||||
/**
|
||||
* Cache for the transport control mask.
|
||||
* Access synchronized on mCacheLock
|
||||
@@ -802,10 +794,27 @@ public class RemoteControlClient
|
||||
private final PendingIntent mRcMediaIntent;
|
||||
|
||||
/**
|
||||
* The remote control display to which this client will send information.
|
||||
* NOTE: Only one IRemoteControlDisplay supported in this implementation
|
||||
* A class to encapsulate all the information about a remote control display.
|
||||
* A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay
|
||||
*/
|
||||
private IRemoteControlDisplay mRcDisplay;
|
||||
private class DisplayInfoForClient {
|
||||
/** may never be null */
|
||||
private IRemoteControlDisplay mRcDisplay;
|
||||
private int mArtworkExpectedWidth;
|
||||
private int mArtworkExpectedHeight;
|
||||
|
||||
DisplayInfoForClient(IRemoteControlDisplay rcd, int w, int h) {
|
||||
mRcDisplay = rcd;
|
||||
mArtworkExpectedWidth = w;
|
||||
mArtworkExpectedHeight = h;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of remote control displays to which this client will send information.
|
||||
* Accessed and modified synchronized on mCacheLock
|
||||
*/
|
||||
private ArrayList<DisplayInfoForClient> mRcDisplays = new ArrayList<DisplayInfoForClient>(1);
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -827,17 +836,14 @@ public class RemoteControlClient
|
||||
*/
|
||||
private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
|
||||
|
||||
public void onInformationRequested(int clientGeneration, int infoFlags,
|
||||
int artWidth, int artHeight) {
|
||||
public void onInformationRequested(int clientGeneration, int infoFlags) {
|
||||
// only post messages, we can't block here
|
||||
if (mEventHandler != null) {
|
||||
// signal new client
|
||||
mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
|
||||
mEventHandler.dispatchMessage(
|
||||
mEventHandler.obtainMessage(
|
||||
MSG_NEW_INTERNAL_CLIENT_GEN,
|
||||
artWidth, artHeight,
|
||||
new Integer(clientGeneration)));
|
||||
mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
|
||||
/*arg1*/ clientGeneration, /*arg2, ignored*/ 0));
|
||||
// send the information
|
||||
mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE);
|
||||
mEventHandler.removeMessages(MSG_REQUEST_METADATA);
|
||||
@@ -861,21 +867,29 @@ public class RemoteControlClient
|
||||
}
|
||||
}
|
||||
|
||||
public void plugRemoteControlDisplay(IRemoteControlDisplay rcd) {
|
||||
public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
|
||||
// only post messages, we can't block here
|
||||
if (mEventHandler != null) {
|
||||
if ((mEventHandler != null) && (rcd != null)) {
|
||||
mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
|
||||
MSG_PLUG_DISPLAY, rcd));
|
||||
MSG_PLUG_DISPLAY, w, h, rcd));
|
||||
}
|
||||
}
|
||||
|
||||
public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
|
||||
// only post messages, we can't block here
|
||||
if (mEventHandler != null) {
|
||||
if ((mEventHandler != null) && (rcd != null)) {
|
||||
mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
|
||||
MSG_UNPLUG_DISPLAY, rcd));
|
||||
}
|
||||
}
|
||||
|
||||
public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) {
|
||||
// only post messages, we can't block here
|
||||
if ((mEventHandler != null) && (rcd != null)) {
|
||||
mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
|
||||
MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -915,6 +929,7 @@ public class RemoteControlClient
|
||||
private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6;
|
||||
private final static int MSG_PLUG_DISPLAY = 7;
|
||||
private final static int MSG_UNPLUG_DISPLAY = 8;
|
||||
private final static int MSG_UPDATE_DISPLAY_ARTWORK_SIZE = 9;
|
||||
|
||||
private class EventHandler extends Handler {
|
||||
public EventHandler(RemoteControlClient rcc, Looper looper) {
|
||||
@@ -945,17 +960,20 @@ public class RemoteControlClient
|
||||
}
|
||||
break;
|
||||
case MSG_NEW_INTERNAL_CLIENT_GEN:
|
||||
onNewInternalClientGen((Integer)msg.obj, msg.arg1, msg.arg2);
|
||||
onNewInternalClientGen(msg.arg1);
|
||||
break;
|
||||
case MSG_NEW_CURRENT_CLIENT_GEN:
|
||||
onNewCurrentClientGen(msg.arg1);
|
||||
break;
|
||||
case MSG_PLUG_DISPLAY:
|
||||
onPlugDisplay((IRemoteControlDisplay)msg.obj);
|
||||
onPlugDisplay((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
|
||||
break;
|
||||
case MSG_UNPLUG_DISPLAY:
|
||||
onUnplugDisplay((IRemoteControlDisplay)msg.obj);
|
||||
break;
|
||||
case MSG_UPDATE_DISPLAY_ARTWORK_SIZE:
|
||||
onUpdateDisplayArtworkSize((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
|
||||
}
|
||||
@@ -963,75 +981,106 @@ public class RemoteControlClient
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
// Communication with IRemoteControlDisplay
|
||||
|
||||
private void detachFromDisplay_syncCacheLock() {
|
||||
mRcDisplay = null;
|
||||
mArtworkExpectedWidth = ARTWORK_INVALID_SIZE;
|
||||
mArtworkExpectedHeight = ARTWORK_INVALID_SIZE;
|
||||
}
|
||||
// Communication with the IRemoteControlDisplay (the displays known to the system)
|
||||
|
||||
private void sendPlaybackState_syncCacheLock() {
|
||||
if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
|
||||
try {
|
||||
mRcDisplay.setPlaybackState(mInternalClientGenId, mPlaybackState,
|
||||
mPlaybackStateChangeTimeMs);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error in setPlaybackState(), dead display "+e);
|
||||
detachFromDisplay_syncCacheLock();
|
||||
if (mCurrentClientGenId == mInternalClientGenId) {
|
||||
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
|
||||
try {
|
||||
di.mRcDisplay.setPlaybackState(mInternalClientGenId,
|
||||
mPlaybackState, mPlaybackStateChangeTimeMs);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error in setPlaybackState(), dead display " + di.mRcDisplay, e);
|
||||
displayIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMetadata_syncCacheLock() {
|
||||
if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
|
||||
try {
|
||||
mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error in sendPlaybackState(), dead display "+e);
|
||||
detachFromDisplay_syncCacheLock();
|
||||
if (mCurrentClientGenId == mInternalClientGenId) {
|
||||
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
|
||||
try {
|
||||
di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error in setMetadata(), dead display " + di.mRcDisplay, e);
|
||||
displayIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendTransportControlFlags_syncCacheLock() {
|
||||
if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
|
||||
try {
|
||||
mRcDisplay.setTransportControlFlags(mInternalClientGenId,
|
||||
mTransportControlFlags);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error in sendTransportControlFlags(), dead display "+e);
|
||||
detachFromDisplay_syncCacheLock();
|
||||
if (mCurrentClientGenId == mInternalClientGenId) {
|
||||
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
|
||||
try {
|
||||
di.mRcDisplay.setTransportControlFlags(mInternalClientGenId,
|
||||
mTransportControlFlags);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error in setTransportControlFlags(), dead display " + di.mRcDisplay,
|
||||
e);
|
||||
displayIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendArtwork_syncCacheLock() {
|
||||
if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
|
||||
// even though we have already scaled in setArtwork(), when this client needs to
|
||||
// send the bitmap, there might be newer and smaller expected dimensions, so we have
|
||||
// to check again.
|
||||
mArtwork = scaleBitmapIfTooBig(mArtwork, mArtworkExpectedWidth, mArtworkExpectedHeight);
|
||||
try {
|
||||
mRcDisplay.setArtwork(mInternalClientGenId, mArtwork);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error in sendArtwork(), dead display "+e);
|
||||
detachFromDisplay_syncCacheLock();
|
||||
// FIXME modify to cache all requested sizes?
|
||||
if (mCurrentClientGenId == mInternalClientGenId) {
|
||||
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
if (!sendArtworkToDisplay((DisplayInfoForClient) displayIterator.next())) {
|
||||
displayIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMetadataWithArtwork_syncCacheLock() {
|
||||
if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
|
||||
// even though we have already scaled in setArtwork(), when this client needs to
|
||||
// send the bitmap, there might be newer and smaller expected dimensions, so we have
|
||||
// to check again.
|
||||
mArtwork = scaleBitmapIfTooBig(mArtwork, mArtworkExpectedWidth, mArtworkExpectedHeight);
|
||||
/**
|
||||
* Send artwork to an IRemoteControlDisplay.
|
||||
* @param di encapsulates the IRemoteControlDisplay that will receive the artwork, and its
|
||||
* dimension requirements.
|
||||
* @return false if there was an error communicating with the IRemoteControlDisplay.
|
||||
*/
|
||||
private boolean sendArtworkToDisplay(DisplayInfoForClient di) {
|
||||
if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
|
||||
Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
|
||||
di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
|
||||
try {
|
||||
mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, mArtwork);
|
||||
di.mRcDisplay.setArtwork(mInternalClientGenId, artwork);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error in setAllMetadata(), dead display "+e);
|
||||
detachFromDisplay_syncCacheLock();
|
||||
Log.e(TAG, "Error in sendArtworkToDisplay(), dead display " + di.mRcDisplay, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void sendMetadataWithArtwork_syncCacheLock() {
|
||||
// FIXME modify to cache all requested sizes?
|
||||
if (mCurrentClientGenId == mInternalClientGenId) {
|
||||
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
|
||||
try {
|
||||
if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
|
||||
Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
|
||||
di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
|
||||
di.mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
|
||||
} else {
|
||||
di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error when setting metadata, dead display " + di.mRcDisplay, e);
|
||||
displayIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1067,15 +1116,11 @@ public class RemoteControlClient
|
||||
//===========================================================
|
||||
// Message handlers
|
||||
|
||||
private void onNewInternalClientGen(Integer clientGeneration, int artWidth, int artHeight) {
|
||||
private void onNewInternalClientGen(int clientGeneration) {
|
||||
synchronized (mCacheLock) {
|
||||
// this remote control client is told it is the "focused" one:
|
||||
// it implies that now (mCurrentClientGenId == mInternalClientGenId) is true
|
||||
mInternalClientGenId = clientGeneration.intValue();
|
||||
if (artWidth > 0) {
|
||||
mArtworkExpectedWidth = artWidth;
|
||||
mArtworkExpectedHeight = artHeight;
|
||||
}
|
||||
mInternalClientGenId = clientGeneration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,18 +1130,62 @@ public class RemoteControlClient
|
||||
}
|
||||
}
|
||||
|
||||
private void onPlugDisplay(IRemoteControlDisplay rcd) {
|
||||
/** pre-condition rcd != null */
|
||||
private void onPlugDisplay(IRemoteControlDisplay rcd, int w, int h) {
|
||||
synchronized(mCacheLock) {
|
||||
mRcDisplay = rcd;
|
||||
// do we have this display already?
|
||||
boolean displayKnown = false;
|
||||
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext() && !displayKnown) {
|
||||
final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
|
||||
displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder());
|
||||
if (displayKnown) {
|
||||
// this display was known but the change in artwork size will cause the
|
||||
// artwork to be refreshed
|
||||
if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
|
||||
di.mArtworkExpectedWidth = w;
|
||||
di.mArtworkExpectedHeight = h;
|
||||
if (!sendArtworkToDisplay(di)) {
|
||||
displayIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!displayKnown) {
|
||||
mRcDisplays.add(new DisplayInfoForClient(rcd, w, h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** pre-condition rcd != null */
|
||||
private void onUnplugDisplay(IRemoteControlDisplay rcd) {
|
||||
synchronized(mCacheLock) {
|
||||
if ((mRcDisplay != null) && (mRcDisplay.asBinder().equals(rcd.asBinder()))) {
|
||||
mRcDisplay = null;
|
||||
mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE;
|
||||
mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE;
|
||||
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
|
||||
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
|
||||
displayIterator.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** pre-condition rcd != null */
|
||||
private void onUpdateDisplayArtworkSize(IRemoteControlDisplay rcd, int w, int h) {
|
||||
synchronized(mCacheLock) {
|
||||
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
|
||||
while (displayIterator.hasNext()) {
|
||||
final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
|
||||
if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) &&
|
||||
((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) {
|
||||
di.mArtworkExpectedWidth = w;
|
||||
di.mArtworkExpectedHeight = h;
|
||||
if (!sendArtworkToDisplay(di)) {
|
||||
displayIterator.remove();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user