Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a578c48e authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by Android (Google) Code Review
Browse files

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
parent 84aa61e2
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -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;
            }
        }
    }
@@ -5245,6 +5250,50 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
    }

    /**
     * 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);