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

Commit bec223b3 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

Audio focus: fix delayed focus request during locked focus behavior

Fix issue where if audio focus was requested with GAIN, and
accepted delayed focus, while focus was locked, then previous
focus owners didn't receive LOSS, and thus would be removed
from the stack.
 The fix consists in propagating the focus loss through the
stack under the focus locker, and remove any focus loser
if the loss was definitive.
 In order to simulate the bug conditions, the test API for
simulating focus requests and abandons, was modified to support
locking the focus like in a phone call.

Bug: 206856107
Test: atest AudioFocusTest#testAudioFocusDelayedByCall
Test: atest AudioFocusTest#testAudioFocusTransientDelayedByCall
Change-Id: I211cd46b66c882499bfa43718bc0cb37b2f79817
parent b4d9a3df
Loading
Loading
Loading
Loading
+4 −3
Original line number Original line Diff line number Diff line
@@ -4003,8 +4003,7 @@ public class AudioManager {
     * @hide
     * @hide
     * flag set on test API calls,
     * flag set on test API calls,
     * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
     * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
     * note that it isn't used in conjunction with other flags, it is passed as the single
     */
     * value for flags */
    public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
    public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
    /** @hide */
    /** @hide */
    public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
    public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
@@ -4187,7 +4186,9 @@ public class AudioManager {
                    afr.getFocusGain(),
                    afr.getFocusGain(),
                    mICallBack,
                    mICallBack,
                    mAudioFocusDispatcher,
                    mAudioFocusDispatcher,
                    clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk);
                    clientFakeId, "com.android.test.fakeclient",
                    afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
                    clientFakeUid, clientTargetSdk);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
            throw e.rethrowFromSystemServer();
        }
        }
+1 −1
Original line number Original line Diff line number Diff line
@@ -384,7 +384,7 @@ interface IAudioService {


    int requestAudioFocusForTest(in AudioAttributes aa, int durationHint, IBinder cb,
    int requestAudioFocusForTest(in AudioAttributes aa, int durationHint, IBinder cb,
            in IAudioFocusDispatcher fd, in String clientId, in String callingPackageName,
            in IAudioFocusDispatcher fd, in String clientId, in String callingPackageName,
            int uid, int sdk);
            int flags, int uid, int sdk);


    int abandonAudioFocusForTest(in IAudioFocusDispatcher fd, in String clientId,
    int abandonAudioFocusForTest(in IAudioFocusDispatcher fd, in String clientId,
            in AudioAttributes aa, in String callingPackageName);
            in AudioAttributes aa, in String callingPackageName);
+5 −2
Original line number Original line Diff line number Diff line
@@ -8252,6 +8252,9 @@ public class AudioService extends IAudioService.Stub
    public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
    public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
            IAudioFocusDispatcher fd, String clientId, String callingPackageName,
            IAudioFocusDispatcher fd, String clientId, String callingPackageName,
            String attributionTag, int flags, IAudioPolicyCallback pcb, int sdk) {
            String attributionTag, int flags, IAudioPolicyCallback pcb, int sdk) {
        if ((flags & AudioManager.AUDIOFOCUS_FLAG_TEST) != 0) {
            throw new IllegalArgumentException("Invalid test flag");
        }
        final int uid = Binder.getCallingUid();
        final int uid = Binder.getCallingUid();
        MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "focus")
        MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "focus")
                .setUid(uid)
                .setUid(uid)
@@ -8310,7 +8313,7 @@ public class AudioService extends IAudioService.Stub
    /** see {@link AudioManager#requestAudioFocusForTest(AudioFocusRequest, String, int, int)} */
    /** see {@link AudioManager#requestAudioFocusForTest(AudioFocusRequest, String, int, int)} */
    public int requestAudioFocusForTest(AudioAttributes aa, int durationHint, IBinder cb,
    public int requestAudioFocusForTest(AudioAttributes aa, int durationHint, IBinder cb,
            IAudioFocusDispatcher fd, String clientId, String callingPackageName,
            IAudioFocusDispatcher fd, String clientId, String callingPackageName,
            int fakeUid, int sdk) {
            int flags, int fakeUid, int sdk) {
        if (!enforceQueryAudioStateForTest("focus request")) {
        if (!enforceQueryAudioStateForTest("focus request")) {
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }
        }
@@ -8320,7 +8323,7 @@ public class AudioService extends IAudioService.Stub
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }
        }
        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
                clientId, callingPackageName, null, AudioManager.AUDIOFOCUS_FLAG_TEST,
                clientId, callingPackageName, null, flags,
                sdk, false /*forceDuck*/, fakeUid);
                sdk, false /*forceDuck*/, fakeUid);
    }
    }


+36 −7
Original line number Original line Diff line number Diff line
@@ -461,11 +461,17 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
     *                 at the top of the focus stack
     *                 at the top of the focus stack
     * Push the focus requester onto the audio focus stack at the first position immediately
     * Push the focus requester onto the audio focus stack at the first position immediately
     * following the locked focus owners.
     * following the locked focus owners.
     * Propagate through the stack the changes that the new (future) focus owner causes.
     * @param nfr the future focus owner that will gain focus when the locked focus owners are
     *            removed from the stack
     * @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
     * @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
     *     {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
     *     {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
     */
     */
    @GuardedBy("mAudioFocusLock")
    @GuardedBy("mAudioFocusLock")
    private int pushBelowLockedFocusOwners(FocusRequester nfr) {
    private int pushBelowLockedFocusOwnersAndPropagate(FocusRequester nfr) {
        if (DEBUG) {
            Log.v(TAG, "pushBelowLockedFocusOwnersAndPropagate client=" + nfr.getClientId());
        }
        int lastLockedFocusOwnerIndex = mFocusStack.size();
        int lastLockedFocusOwnerIndex = mFocusStack.size();
        for (int index = mFocusStack.size() - 1; index >= 0; index--) {
        for (int index = mFocusStack.size() - 1; index >= 0; index--) {
            if (isLockedFocusOwner(mFocusStack.elementAt(index))) {
            if (isLockedFocusOwner(mFocusStack.elementAt(index))) {
@@ -480,10 +486,33 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
            propagateFocusLossFromGain_syncAf(nfr.getGainRequest(), nfr, false /*forceDuck*/);
            propagateFocusLossFromGain_syncAf(nfr.getGainRequest(), nfr, false /*forceDuck*/);
            mFocusStack.push(nfr);
            mFocusStack.push(nfr);
            return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
            return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
        } else {
        }

        if (DEBUG) {
            Log.v(TAG, "> lastLockedFocusOwnerIndex=" + lastLockedFocusOwnerIndex);
        }
        mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
        mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
            return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;

        // propagate potential focus loss (and removal from stack) after the newly
        // inserted FocusRequester (at index lastLockedFocusOwnerIndex-1)
        final List<String> clientsToRemove = new LinkedList<String>();
        for (int index = lastLockedFocusOwnerIndex - 1; index >= 0; index--) {
            final boolean isDefinitiveLoss =
                    mFocusStack.elementAt(index).handleFocusLossFromGain(
                            nfr.getGainRequest(), nfr, false /*forceDuck*/);
            if (isDefinitiveLoss) {
                clientsToRemove.add(mFocusStack.elementAt(index).getClientId());
            }
        }
        for (String clientToRemove : clientsToRemove) {
            if (DEBUG) {
                Log.v(TAG, "> removing focus client " + clientToRemove);
            }
            }
            removeFocusStackEntry(clientToRemove, false /*signal*/,
                    true /*notifyFocusFollowers*/);
        }

        return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
    }
    }


    /**
    /**
@@ -868,7 +897,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
     * @param forceDuck only true if
     * @param forceDuck only true if
     *     {@link android.media.AudioFocusRequest.Builder#setFocusGain(int)} was set to true for
     *     {@link android.media.AudioFocusRequest.Builder#setFocusGain(int)} was set to true for
     *                  accessibility.
     *                  accessibility.
     * @param testUid ignored if flags is not AudioManager.AUDIOFOCUS_FLAG_TEST (strictly equals to)
     * @param testUid ignored if flags doesn't contain AudioManager.AUDIOFOCUS_FLAG_TEST
     *                otherwise the UID being injected for testing
     *                otherwise the UID being injected for testing
     * @return
     * @return
     */
     */
@@ -1029,7 +1058,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
            if (focusGrantDelayed) {
            if (focusGrantDelayed) {
                // focusGrantDelayed being true implies we can't reassign focus right now
                // focusGrantDelayed being true implies we can't reassign focus right now
                // which implies the focus stack is not empty.
                // which implies the focus stack is not empty.
                final int requestResult = pushBelowLockedFocusOwners(nfr);
                final int requestResult = pushBelowLockedFocusOwnersAndPropagate(nfr);
                if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
                if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
                    notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult);
                    notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult);
                }
                }