summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/AudioManager.java7
-rwxr-xr-xmedia/java/android/media/IAudioService.aidl2
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java7
-rw-r--r--services/core/java/com/android/server/audio/MediaFocusControl.java43
4 files changed, 46 insertions, 13 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d721291ad78f..0722417c0d18 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4003,8 +4003,7 @@ public class AudioManager {
* @hide
* flag set on test API calls,
* 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;
/** @hide */
public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
@@ -4187,7 +4186,9 @@ public class AudioManager {
afr.getFocusGain(),
mICallBack,
mAudioFocusDispatcher,
- clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk);
+ clientFakeId, "com.android.test.fakeclient",
+ afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
+ clientFakeUid, clientTargetSdk);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index afcbc5769cf0..147e73599cad 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -384,7 +384,7 @@ interface IAudioService {
int requestAudioFocusForTest(in AudioAttributes aa, int durationHint, IBinder cb,
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,
in AudioAttributes aa, in String callingPackageName);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index aa33644357be..6238198e9488 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -8252,6 +8252,9 @@ public class AudioService extends IAudioService.Stub
public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
IAudioFocusDispatcher fd, String clientId, String callingPackageName,
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();
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "focus")
.setUid(uid)
@@ -8310,7 +8313,7 @@ public class AudioService extends IAudioService.Stub
/** see {@link AudioManager#requestAudioFocusForTest(AudioFocusRequest, String, int, int)} */
public int requestAudioFocusForTest(AudioAttributes aa, int durationHint, IBinder cb,
IAudioFocusDispatcher fd, String clientId, String callingPackageName,
- int fakeUid, int sdk) {
+ int flags, int fakeUid, int sdk) {
if (!enforceQueryAudioStateForTest("focus request")) {
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
@@ -8320,7 +8323,7 @@ public class AudioService extends IAudioService.Stub
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
- clientId, callingPackageName, null, AudioManager.AUDIOFOCUS_FLAG_TEST,
+ clientId, callingPackageName, null, flags,
sdk, false /*forceDuck*/, fakeUid);
}
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index bf49ac85d1dc..66f62355c7f0 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -461,13 +461,19 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
* at the top of the focus stack
* Push the focus requester onto the audio focus stack at the first position immediately
* 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
* {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
*/
@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();
- for (int index = mFocusStack.size()-1; index >= 0; index--) {
+ for (int index = mFocusStack.size() - 1; index >= 0; index--) {
if (isLockedFocusOwner(mFocusStack.elementAt(index))) {
lastLockedFocusOwnerIndex = index;
}
@@ -480,10 +486,33 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
propagateFocusLossFromGain_syncAf(nfr.getGainRequest(), nfr, false /*forceDuck*/);
mFocusStack.push(nfr);
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
- } else {
- mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
- return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
}
+
+ if (DEBUG) {
+ Log.v(TAG, "> lastLockedFocusOwnerIndex=" + lastLockedFocusOwnerIndex);
+ }
+ mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
+
+ // 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
* {@link android.media.AudioFocusRequest.Builder#setFocusGain(int)} was set to true for
* 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
* @return
*/
@@ -1029,7 +1058,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
if (focusGrantDelayed) {
// focusGrantDelayed being true implies we can't reassign focus right now
// which implies the focus stack is not empty.
- final int requestResult = pushBelowLockedFocusOwners(nfr);
+ final int requestResult = pushBelowLockedFocusOwnersAndPropagate(nfr);
if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult);
}