diff options
author | 2012-12-28 11:19:49 -0800 | |
---|---|---|
committer | 2013-01-02 12:31:56 -0800 | |
commit | a578c48e6c8677bcb54340aadb9470f8a275e56c (patch) | |
tree | 8d7aaff790dc7bb08b36e13619dd1af647f43de4 | |
parent | 84aa61e2a838fdeb7484ffaf95945a205bccb453 (diff) |
Use playback state to update remote control stack
The remote control stack in AudioService is responsible for handling
which application receives media button events. When an application
"registers" its media button receiver, it gets placed at the top
of the remote control stack. If the app also has audio focus (is
at top of focus stack), this will also cause the information of
the attached remote control client (RCC) to be displayed on the
lockscreen.
If an app doesn't re-register its button receiver when it wants
to receive the button events, it might have lost its place at the
top of the remote control stack, and would not show up in the
lockscreen anymore.
This change consists in using the playstate reported by the RCC
to change the remote control stack. If an RCC reports a "playing"
state (e.g. playing, fast forwarding), it is safe to assume the
application is actively being used, and should be the one that
receives the transport control buttons. This CL uses the reported
playstate to conditionally move the corresponding stack entry
to the top of the stack.
Bug 7311023
Change-Id: I1505f01664c16e108b22d33e3f47f0056343676e
-rw-r--r-- | media/java/android/media/AudioService.java | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 1c8c7cc382b8..9aac0e6b8cd5 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -157,6 +157,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 26; private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27; private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 28; + private static final int MSG_PROMOTE_RCC = 29; // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be // persisted @@ -3527,6 +3528,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished { case MSG_PERSIST_SAFE_VOLUME_STATE: onPersistSafeVolumeState(msg.arg1); break; + + case MSG_PROMOTE_RCC: + onPromoteRcc(msg.arg1); + break; } } } @@ -5246,6 +5251,50 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } /** + * Helper function: + * Post a message to asynchronously move the media button event receiver associated with the + * given remote control client ID to the top of the remote control stack + * @param rccId + */ + private void postPromoteRcc(int rccId) { + sendMsg(mAudioHandler, MSG_PROMOTE_RCC, SENDMSG_REPLACE, + rccId /*arg1*/, 0, null, 0/*delay*/); + } + + private void onPromoteRcc(int rccId) { + if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); } + synchronized(mAudioFocusLock) { + synchronized(mRCStack) { + // ignore if given RCC ID is already at top of remote control stack + if (!mRCStack.isEmpty() && (mRCStack.peek().mRccId == rccId)) { + return; + } + int indexToPromote = -1; + try { + for (int index = mRCStack.size()-1; index >= 0; index--) { + final RemoteControlStackEntry rcse = mRCStack.elementAt(index); + if (rcse.mRccId == rccId) { + indexToPromote = index; + break; + } + } + if (indexToPromote >= 0) { + if (DEBUG_RC) { Log.d(TAG, " moving RCC from index " + indexToPromote + + " to " + (mRCStack.size()-1)); } + final RemoteControlStackEntry rcse = mRCStack.remove(indexToPromote); + mRCStack.push(rcse); + // the RC stack changed, reevaluate the display + checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); + } + } catch (ArrayIndexOutOfBoundsException e) { + // not expected to happen, indicates improper concurrent modification + Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e); + } + }//synchronized(mRCStack) + }//synchronized(mAudioFocusLock) + } + + /** * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) * precondition: mediaIntent != null, target != null */ @@ -5389,6 +5438,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { */ public void unregisterRemoteControlClient(PendingIntent mediaIntent, IRemoteControlClient rcClient) { + if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient); synchronized(mAudioFocusLock) { synchronized(mRCStack) { boolean topRccChange = false; @@ -5628,6 +5678,12 @@ public class AudioService extends IAudioService.Stub implements OnFinished { postReevaluateRemote(); } } + // an RCC moving to a "playing" state should become the media button + // event receiver so it can be controlled, without requiring the + // app to re-register its receiver + if (isPlaystateActive(value)) { + postPromoteRcc(rccId); + } break; default: Log.e(TAG, "unhandled key " + key + " for RCC " + rccId); |