summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jean-Michel Trivi <jmtrivi@google.com> 2012-12-28 11:19:49 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2013-01-02 12:31:56 -0800
commita578c48e6c8677bcb54340aadb9470f8a275e56c (patch)
tree8d7aaff790dc7bb08b36e13619dd1af647f43de4
parent84aa61e2a838fdeb7484ffaf95945a205bccb453 (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.java56
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);