diff options
| author | 2019-03-19 12:29:27 -0700 | |
|---|---|---|
| committer | 2019-03-21 10:29:59 -0700 | |
| commit | ee7d2456e10812c37f2f1abdbae7036f7c12f60a (patch) | |
| tree | a89147d1c375bd7cb23e4dd98601cbd76f56b7f2 | |
| parent | 70974aa123542576ab403cc33ca8f2a6f0acc93d (diff) | |
AudioPolicy: add test flagging for focus policy tests
(Note there is no @TestApi for @SystemApi, so rely
on javadoc to document that the new method is
for testing purposes only)
Add method to flag a focus policy as a test policy for
devices that run their own focus policy to customize
audio focus management. When a test policy is installed
it will replace the current one, and will restore it
when it is unregistered.
Add nullability annotations in Builder.
Bug: 123717363
Test: make system-api-stubs-docs-update-current-api
Test: gts-tradefed run gts --skip-device-info --skip-system-status-check com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker -m GtsGmscoreHostTestCases -t 'com.google.android.gts.audiopolicy.AudioPolicyHostTest#testFocusPolicy'
Change-Id: I572487bb53f85aade22da8529db9491a542ef0db
| -rw-r--r-- | api/system-current.txt | 11 | ||||
| -rw-r--r-- | media/java/android/media/AudioManager.java | 3 | ||||
| -rw-r--r-- | media/java/android/media/IAudioService.aidl | 1 | ||||
| -rw-r--r-- | media/java/android/media/audiopolicy/AudioPolicy.java | 36 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioService.java | 15 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/MediaFocusControl.java | 25 |
6 files changed, 72 insertions, 19 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 0b8b8e45062b..8880f99dffaa 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3664,13 +3664,14 @@ package android.media.audiopolicy { public static class AudioPolicy.Builder { ctor public AudioPolicy.Builder(android.content.Context); - method public android.media.audiopolicy.AudioPolicy.Builder addMix(@NonNull android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException; - method public android.media.audiopolicy.AudioPolicy build(); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder addMix(@NonNull android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException; + method @NonNull public android.media.audiopolicy.AudioPolicy build(); method public void setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener); method public void setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener); - method public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback); - method public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean); - method public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException; + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsTestFocusPolicy(boolean); + method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException; } public final class AudioProductStrategies implements java.lang.Iterable<android.media.audiopolicy.AudioProductStrategy> android.os.Parcelable { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index f9080a70206e..998849c3d421 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3307,7 +3307,8 @@ public class AudioManager { try { MediaProjection projection = policy.getMediaProjection(); String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), - policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController(), + policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(), + policy.isVolumeController(), projection == null ? null : projection.getProjection()); if (regId == null) { return ERROR; diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index c29f355181f4..a1fde52a89cc 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -195,6 +195,7 @@ interface IAudioService { String registerAudioPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy, + boolean isTestFocusPolicy, boolean isVolumeController, in IMediaProjection projection); oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb); diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 978583e99971..00f601388164 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -75,6 +75,7 @@ public class AudioPolicy { private String mRegistrationId; private AudioPolicyStatusListener mStatusListener; private boolean mIsFocusPolicy; + private boolean mIsTestFocusPolicy; /** * The list of AudioTrack instances created to inject audio into the associated mixes @@ -121,6 +122,10 @@ public class AudioPolicy { /** @hide */ public boolean isFocusPolicy() { return mIsFocusPolicy; } /** @hide */ + public boolean isTestFocusPolicy() { + return mIsTestFocusPolicy; + } + /** @hide */ public boolean isVolumeController() { return mVolCb != null; } /** @hide */ public @Nullable MediaProjection getMediaProjection() { @@ -128,10 +133,11 @@ public class AudioPolicy { } /** - * The parameter is guaranteed non-null through the Builder + * The parameters are guaranteed non-null through the Builder */ private AudioPolicy(AudioPolicyConfig config, Context context, Looper looper, - AudioPolicyFocusListener fl, AudioPolicyStatusListener sl, boolean isFocusPolicy, + AudioPolicyFocusListener fl, AudioPolicyStatusListener sl, + boolean isFocusPolicy, boolean isTestFocusPolicy, AudioPolicyVolumeCallback vc, @Nullable MediaProjection projection) { mConfig = config; mStatus = POLICY_STATUS_UNREGISTERED; @@ -148,6 +154,7 @@ public class AudioPolicy { mFocusListener = fl; mStatusListener = sl; mIsFocusPolicy = isFocusPolicy; + mIsTestFocusPolicy = isTestFocusPolicy; mVolCb = vc; mProjection = projection; } @@ -163,6 +170,7 @@ public class AudioPolicy { private AudioPolicyFocusListener mFocusListener; private AudioPolicyStatusListener mStatusListener; private boolean mIsFocusPolicy = false; + private boolean mIsTestFocusPolicy = false; private AudioPolicyVolumeCallback mVolCb; private MediaProjection mProjection; @@ -181,6 +189,7 @@ public class AudioPolicy { * @return the same Builder instance. * @throws IllegalArgumentException */ + @NonNull public Builder addMix(@NonNull AudioMix mix) throws IllegalArgumentException { if (mix == null) { throw new IllegalArgumentException("Illegal null AudioMix argument"); @@ -195,6 +204,7 @@ public class AudioPolicy { * @return the same Builder instance. * @throws IllegalArgumentException */ + @NonNull public Builder setLooper(@NonNull Looper looper) throws IllegalArgumentException { if (looper == null) { throw new IllegalArgumentException("Illegal null Looper argument"); @@ -220,12 +230,28 @@ public class AudioPolicy { * @param enforce true if the policy will govern audio focus decisions. * @return the same Builder instance. */ + @NonNull public Builder setIsAudioFocusPolicy(boolean isFocusPolicy) { mIsFocusPolicy = isFocusPolicy; return this; } /** + * Test method to declare whether this audio focus policy is for test purposes only. + * Having a test policy registered will disable the current focus policy and replace it + * with this test policy. When unregistered, the previous focus policy will be restored. + * <p>A value of <code>true</code> will be ignored if the AudioPolicy is not also + * focus policy. + * @param isTestFocusPolicy true if the focus policy to register is for testing purposes. + * @return the same Builder instance + */ + @NonNull + public Builder setIsTestFocusPolicy(boolean isTestFocusPolicy) { + mIsTestFocusPolicy = isTestFocusPolicy; + return this; + } + + /** * Sets the audio policy status listener. * @param l a {@link AudioPolicy.AudioPolicyStatusListener} */ @@ -240,6 +266,7 @@ public class AudioPolicy { * @param vc * @return the same Builder instance. */ + @NonNull public Builder setAudioPolicyVolumeCallback(@NonNull AudioPolicyVolumeCallback vc) { if (vc == null) { throw new IllegalArgumentException("Invalid null volume callback"); @@ -256,6 +283,7 @@ public class AudioPolicy { * * @hide */ + @NonNull public Builder setMediaProjection(@NonNull MediaProjection projection) { if (projection == null) { throw new IllegalArgumentException("Invalid null volume callback"); @@ -273,6 +301,7 @@ public class AudioPolicy { * {@link AudioPolicy.AudioPolicyStatusListener} but the policy was configured * as an audio focus policy with {@link #setIsAudioFocusPolicy(boolean)}. */ + @NonNull public AudioPolicy build() { if (mStatusListener != null) { // the AudioPolicy status listener includes updates on each mix activity state @@ -285,7 +314,8 @@ public class AudioPolicy { + "an AudioPolicyFocusListener"); } return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper, - mFocusListener, mStatusListener, mIsFocusPolicy, mVolCb, mProjection); + mFocusListener, mStatusListener, mIsFocusPolicy, mIsTestFocusPolicy, + mVolCb, mProjection); } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a14a638395db..26f82bbf4dea 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6290,8 +6290,8 @@ public class AudioService extends IAudioService.Stub // Audio policy management //========================================================================================== public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb, - boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController, - IMediaProjection projection) { + boolean hasFocusListener, boolean isFocusPolicy, boolean isTestFocusPolicy, + boolean isVolumeController, IMediaProjection projection) { AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback); if (!isPolicyRegisterAllowed(policyConfig, projection)) { @@ -6312,7 +6312,7 @@ public class AudioService extends IAudioService.Stub return null; } AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener, - isFocusPolicy, isVolumeController); + isFocusPolicy, isTestFocusPolicy, isVolumeController); pcb.asBinder().linkToDeath(app, 0/*flags*/); regId = app.getRegistrationId(); mAudioPolicies.put(pcb.asBinder(), app); @@ -6730,9 +6730,11 @@ public class AudioService extends IAudioService.Stub */ int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT; boolean mIsFocusPolicy = false; + boolean mIsTestFocusPolicy = false; AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token, - boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController) { + boolean hasFocusListener, boolean isFocusPolicy, boolean isTestFocusPolicy, + boolean isVolumeController) { super(config); setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++)); mPolicyCallback = token; @@ -6743,7 +6745,8 @@ public class AudioService extends IAudioService.Stub // can only ever be true if there is a focus listener if (isFocusPolicy) { mIsFocusPolicy = true; - mMediaFocusControl.setFocusPolicy(mPolicyCallback); + mIsTestFocusPolicy = isTestFocusPolicy; + mMediaFocusControl.setFocusPolicy(mPolicyCallback, mIsTestFocusPolicy); } } if (mIsVolumeController) { @@ -6771,7 +6774,7 @@ public class AudioService extends IAudioService.Stub void release() { if (mIsFocusPolicy) { - mMediaFocusControl.unsetFocusPolicy(mPolicyCallback); + mMediaFocusControl.unsetFocusPolicy(mPolicyCallback, mIsTestFocusPolicy); } if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) { mMediaFocusControl.setDuckingInExtPolicyAvailable(false); diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index d028e88fa160..1e58b454a15b 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -17,6 +17,7 @@ package com.android.server.audio; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.media.AudioAttributes; @@ -458,7 +459,15 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } - private IAudioPolicyCallback mFocusPolicy = null; + /** The current audio focus policy */ + @GuardedBy("mAudioFocusLock") + @Nullable private IAudioPolicyCallback mFocusPolicy = null; + /** + * The audio focus policy that was registered before a test focus policy was registered + * during a test + */ + @GuardedBy("mAudioFocusLock") + @Nullable private IAudioPolicyCallback mPreviousFocusPolicy = null; // Since we don't have a stack of focus owners when using an external focus policy, we keep // track of all the focus requesters in this map, with their clientId as the key. This is @@ -466,22 +475,30 @@ public class MediaFocusControl implements PlayerFocusEnforcer { private HashMap<String, FocusRequester> mFocusOwnersForFocusPolicy = new HashMap<String, FocusRequester>(); - void setFocusPolicy(IAudioPolicyCallback policy) { + void setFocusPolicy(IAudioPolicyCallback policy, boolean isTestFocusPolicy) { if (policy == null) { return; } synchronized (mAudioFocusLock) { + if (isTestFocusPolicy) { + mPreviousFocusPolicy = mFocusPolicy; + } mFocusPolicy = policy; } } - void unsetFocusPolicy(IAudioPolicyCallback policy) { + void unsetFocusPolicy(IAudioPolicyCallback policy, boolean isTestFocusPolicy) { if (policy == null) { return; } synchronized (mAudioFocusLock) { if (mFocusPolicy == policy) { - mFocusPolicy = null; + if (isTestFocusPolicy) { + // restore the focus policy that was there before the focus policy test started + mFocusPolicy = mPreviousFocusPolicy; + } else { + mFocusPolicy = null; + } } } } |