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

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

Audio focus: fix focus loss notification for older SDKs

The feature of ducking enforced by the framework is gated by the
  SDK version of the focus owner. The check was performed by
  asking the SDK target level of the players to duck.
  But if there were no players in the STARTED state at
  the time, the check didn't report that the ducking
  shouldn't be performed by the framework, and thus the
  focus loss wasn't reported to the application.
The fix consists in moving the SDK check at the focus owner
  level, so the check can happen regardless of whether there
  are active players or not.
Add more informative logs where piids are logged (uid+pid).
In the FocusRequester class, initialize mFocusLossWasNotified
  to true for the focus gain path, and don't set it to false
  after gaining focus, it is properly updated instead in
  the focus loss code path.

Test: launch Audible, play then pause, play a notification, verify in the logs Audible is notified of the focus loss
Bug: 37987086

Change-Id: I7c44d824b2563e71cf288ae1f256d001662a6a59
parent 00487cf9
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ public class FocusRequester {
        mFocusGainRequest = focusRequest;
        mGrantFlags = grantFlags;
        mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
        mFocusLossWasNotified = true;
        mFocusController = ctlr;
        mSdkTarget = sdk;
    }
@@ -111,6 +112,7 @@ public class FocusRequester {
        mCallingUid = afi.getClientUid();
        mFocusGainRequest = afi.getGainRequest();
        mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
        mFocusLossWasNotified = true;
        mGrantFlags = afi.getFlags();
        mSdkTarget = afi.getSdkTarget();

@@ -324,7 +326,6 @@ public class FocusRequester {
                }
            }
            mFocusController.unduckPlayers(this);
            mFocusLossWasNotified = false;
        } catch (android.os.RemoteException e) {
            Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
        }
@@ -378,6 +379,12 @@ public class FocusRequester {
                            // the focus loser declared it would pause instead of duck, let it
                            // handle it (the framework doesn't pause for apps)
                            handled = false;
                            Log.v(TAG, "not ducking uid " + this.mCallingUid + " - flags");
                        } else if (MediaFocusControl.ENFORCE_DUCKING_FOR_NEW &&
                                this.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL) {
                            // legacy behavior, apps used to be notified when they should be ducking
                            handled = false;
                            Log.v(TAG, "not ducking uid " + this.mCallingUid + " - old SDK");
                        } else {
                            handled = mFocusController.duckPlayers(fr, this);
                        }
+15 −17
Original line number Diff line number Diff line
@@ -286,23 +286,20 @@ public final class PlaybackActivityMonitor
                        && loser.hasSameUid(apc.getClientUid())
                        && apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED)
                {
                    if (MediaFocusControl.ENFORCE_DUCKING
                            && MediaFocusControl.ENFORCE_DUCKING_FOR_NEW
                            && loser.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL) {
                        // legacy behavior, apps used to be notified when they should be ducking
                        if (DEBUG) {Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
                                + ": old SDK"); }
                        return false;
                    } else if (apc.getAudioAttributes().getContentType() ==
                    if (apc.getAudioAttributes().getContentType() ==
                            AudioAttributes.CONTENT_TYPE_SPEECH) {
                        // the player is speaking, ducking will make the speech unintelligible
                        // so let the app handle it instead
                        if (DEBUG) { Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
                                + ": SPEECH"); }
                        Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
                                + " uid:" + apc.getClientUid() + " pid:" + apc.getClientPid()
                                + " - SPEECH");
                        return false;
                    } else if (apc.getPlayerType()
                            == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
                        // TODO support ducking of SoundPool players
                        Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
                                + " uid:" + apc.getClientUid() + " pid:" + apc.getClientPid()
                                + " - SoundPool");
                        return false;
                    }
                    apcsToDuck.add(apc);
@@ -351,7 +348,7 @@ public final class PlaybackActivityMonitor
                }
                if (mute) {
                    try {
                        Log.v(TAG, "call: muting player" + piid);
                        Log.v(TAG, "call: muting player" + piid + " uid:" + apc.getClientUid());
                        apc.getPlayerProxy().setVolume(0.0f);
                        mMutedPlayers.add(new Integer(piid));
                    } catch (Exception e) {
@@ -375,10 +372,11 @@ public final class PlaybackActivityMonitor
                final AudioPlaybackConfiguration apc = mPlayers.get(piid);
                if (apc != null) {
                    try {
                        Log.v(TAG, "call: unmuting player" + piid);
                        Log.v(TAG, "call: unmuting player" + piid + " uid:" + apc.getClientUid());
                        apc.getPlayerProxy().setVolume(1.0f);
                    } catch (Exception e) {
                        Log.e(TAG, "call: error unmuting player " + piid, e);
                        Log.e(TAG, "call: error unmuting player " + piid + " uid:"
                                + apc.getClientUid(), e);
                    }
                }
            }
@@ -559,13 +557,13 @@ public final class PlaybackActivityMonitor
                    return;
                }
                try {
                    Log.v(TAG, "ducking player " + apc.getPlayerInterfaceId());
                    Log.v(TAG, "ducking player " + apc.getPlayerInterfaceId() + " uid:" + mUid);
                    apc.getPlayerProxy().applyVolumeShaper(
                            DUCK_VSHAPE,
                            PLAY_CREATE_IF_NEEDED);
                    mDuckedPlayers.add(piid);
                } catch (Exception e) {
                    Log.e(TAG, "Error ducking player " + piid, e);
                    Log.e(TAG, "Error ducking player " + piid + " uid:" + mUid, e);
                }
            }

@@ -574,12 +572,12 @@ public final class PlaybackActivityMonitor
                    final AudioPlaybackConfiguration apc = players.get(piid);
                    if (apc != null) {
                        try {
                            Log.v(TAG, "unducking player " + piid);
                            Log.v(TAG, "unducking player " + piid + " uid:" + mUid);
                            apc.getPlayerProxy().applyVolumeShaper(
                                    DUCK_ID,
                                    VolumeShaper.Operation.REVERSE);
                        } catch (Exception e) {
                            Log.e(TAG, "Error unducking player " + piid, e);
                            Log.e(TAG, "Error unducking player " + piid + " uid:" + mUid, e);
                        }
                    } else {
                        // this piid was in the list of ducked players, but wasn't found