From 087b672797b23d6c7451f975ca7f825d64fb1bd9 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Wed, 10 May 2017 13:05:06 -0700 Subject: [PATCH] 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 --- .../android/server/audio/FocusRequester.java | 9 +++++- .../server/audio/PlaybackActivityMonitor.java | 32 +++++++++---------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java index 125095cc0ecfa..c298fe70422de 100644 --- a/services/core/java/com/android/server/audio/FocusRequester.java +++ b/services/core/java/com/android/server/audio/FocusRequester.java @@ -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); } diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index 30538798959e7..dcd58e7601cd1 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -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