diff options
author | Justin Klaassen <justinklaassen@google.com> | 2018-04-03 23:21:57 -0400 |
---|---|---|
committer | Justin Klaassen <justinklaassen@google.com> | 2018-04-03 23:21:57 -0400 |
commit | 4d01eeaffaa720e4458a118baa137a11614f00f7 (patch) | |
tree | 66751893566986236788e3c796a7cc5e90d05f52 /android/media/audiopolicy | |
parent | a192cc2a132cb0ee8588e2df755563ec7008c179 (diff) | |
download | android-28-4d01eeaffaa720e4458a118baa137a11614f00f7.tar.gz |
Import Android SDK Platform P [4697573]
/google/data/ro/projects/android/fetch_artifact \
--bid 4697573 \
--target sdk_phone_armv7-win_sdk \
sdk-repo-linux-sources-4697573.zip
AndroidVersion.ApiLevel has been modified to appear as 28
Change-Id: If80578c3c657366cc9cf75f8db13d46e2dd4e077
Diffstat (limited to 'android/media/audiopolicy')
-rw-r--r-- | android/media/audiopolicy/AudioMix.java | 18 | ||||
-rw-r--r-- | android/media/audiopolicy/AudioMixingRule.java | 31 | ||||
-rw-r--r-- | android/media/audiopolicy/AudioPolicy.java | 152 | ||||
-rw-r--r-- | android/media/audiopolicy/AudioPolicyConfig.java | 53 |
4 files changed, 235 insertions, 19 deletions
diff --git a/android/media/audiopolicy/AudioMix.java b/android/media/audiopolicy/AudioMix.java index adeb8348..fca0cc73 100644 --- a/android/media/audiopolicy/AudioMix.java +++ b/android/media/audiopolicy/AudioMix.java @@ -162,6 +162,24 @@ public class AudioMix { } /** @hide */ + public boolean isAffectingUsage(int usage) { + return mRule.isAffectingUsage(usage); + } + + /** @hide */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final AudioMix that = (AudioMix) o; + return (this.mRouteFlags == that.mRouteFlags) + && (this.mRule == that.mRule) + && (this.mMixType == that.mMixType) + && (this.mFormat == that.mFormat); + } + + /** @hide */ @Override public int hashCode() { return Objects.hash(mRouteFlags, mRule, mMixType, mFormat); diff --git a/android/media/audiopolicy/AudioMixingRule.java b/android/media/audiopolicy/AudioMixingRule.java index 5f127421..749a45e3 100644 --- a/android/media/audiopolicy/AudioMixingRule.java +++ b/android/media/audiopolicy/AudioMixingRule.java @@ -135,11 +135,42 @@ public class AudioMixingRule { } } + boolean isAffectingUsage(int usage) { + for (AudioMixMatchCriterion criterion : mCriteria) { + if ((criterion.mRule & RULE_MATCH_ATTRIBUTE_USAGE) != 0 + && criterion.mAttr != null + && criterion.mAttr.getUsage() == usage) { + return true; + } + } + return false; + } + + private static boolean areCriteriaEquivalent(ArrayList<AudioMixMatchCriterion> cr1, + ArrayList<AudioMixMatchCriterion> cr2) { + if (cr1 == null || cr2 == null) return false; + if (cr1 == cr2) return true; + if (cr1.size() != cr2.size()) return false; + //TODO iterate over rules to check they contain the same criterion + return (cr1.hashCode() == cr2.hashCode()); + } + private final int mTargetMixType; int getTargetMixType() { return mTargetMixType; } private final ArrayList<AudioMixMatchCriterion> mCriteria; ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; } + /** @hide */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final AudioMixingRule that = (AudioMixingRule) o; + return (this.mTargetMixType == that.mTargetMixType) + && (areCriteriaEquivalent(this.mCriteria, that.mCriteria)); + } + @Override public int hashCode() { return Objects.hash(mTargetMixType, mCriteria); diff --git a/android/media/audiopolicy/AudioPolicy.java b/android/media/audiopolicy/AudioPolicy.java index 7e88c277..11107e2d 100644 --- a/android/media/audiopolicy/AudioPolicy.java +++ b/android/media/audiopolicy/AudioPolicy.java @@ -42,6 +42,7 @@ import android.util.Slog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.List; /** * @hide @@ -89,6 +90,8 @@ public class AudioPolicy { private AudioPolicyFocusListener mFocusListener; + private final AudioPolicyVolumeCallback mVolCb; + private Context mContext; private AudioPolicyConfig mConfig; @@ -99,12 +102,15 @@ public class AudioPolicy { public boolean hasFocusListener() { return mFocusListener != null; } /** @hide */ public boolean isFocusPolicy() { return mIsFocusPolicy; } + /** @hide */ + public boolean isVolumeController() { return mVolCb != null; } /** * The parameter is 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, + AudioPolicyVolumeCallback vc) { mConfig = config; mStatus = POLICY_STATUS_UNREGISTERED; mContext = context; @@ -120,6 +126,7 @@ public class AudioPolicy { mFocusListener = fl; mStatusListener = sl; mIsFocusPolicy = isFocusPolicy; + mVolCb = vc; } /** @@ -134,6 +141,7 @@ public class AudioPolicy { private AudioPolicyFocusListener mFocusListener; private AudioPolicyStatusListener mStatusListener; private boolean mIsFocusPolicy = false; + private AudioPolicyVolumeCallback mVolCb; /** * Constructs a new Builder with no audio mixes. @@ -208,6 +216,22 @@ public class AudioPolicy { mStatusListener = l; } + @SystemApi + /** + * Sets the callback to receive all volume key-related events. + * The callback will only be called if the device is configured to handle volume events + * in the PhoneWindowManager (see config_handleVolumeKeysInWindowManager) + * @param vc + * @return the same Builder instance. + */ + public Builder setAudioPolicyVolumeCallback(@NonNull AudioPolicyVolumeCallback vc) { + if (vc == null) { + throw new IllegalArgumentException("Invalid null volume callback"); + } + mVolCb = vc; + return this; + } + /** * Combines all of the attributes that have been set on this {@code Builder} and returns a * new {@link AudioPolicy} object. @@ -229,7 +253,90 @@ public class AudioPolicy { + "an AudioPolicyFocusListener"); } return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper, - mFocusListener, mStatusListener, mIsFocusPolicy); + mFocusListener, mStatusListener, mIsFocusPolicy, mVolCb); + } + } + + /** + * @hide + * Update the current configuration of the set of audio mixes by adding new ones, while + * keeping the policy registered. + * This method can only be called on a registered policy. + * @param mixes the list of {@link AudioMix} to add + * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR} + * otherwise. + */ + @SystemApi + public int attachMixes(@NonNull List<AudioMix> mixes) { + if (mixes == null) { + throw new IllegalArgumentException("Illegal null list of AudioMix"); + } + synchronized (mLock) { + if (mStatus != POLICY_STATUS_REGISTERED) { + throw new IllegalStateException("Cannot alter unregistered AudioPolicy"); + } + final ArrayList<AudioMix> zeMixes = new ArrayList<AudioMix>(mixes.size()); + for (AudioMix mix : mixes) { + if (mix == null) { + throw new IllegalArgumentException("Illegal null AudioMix in attachMixes"); + } else { + zeMixes.add(mix); + } + } + final AudioPolicyConfig cfg = new AudioPolicyConfig(zeMixes); + IAudioService service = getService(); + try { + final int status = service.addMixForPolicy(cfg, this.cb()); + if (status == AudioManager.SUCCESS) { + mConfig.add(zeMixes); + } + return status; + } catch (RemoteException e) { + Log.e(TAG, "Dead object in attachMixes", e); + return AudioManager.ERROR; + } + } + } + + /** + * @hide + * Update the current configuration of the set of audio mixes by removing some, while + * keeping the policy registered. + * This method can only be called on a registered policy. + * @param mixes the list of {@link AudioMix} to remove + * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR} + * otherwise. + */ + @SystemApi + public int detachMixes(@NonNull List<AudioMix> mixes) { + if (mixes == null) { + throw new IllegalArgumentException("Illegal null list of AudioMix"); + } + synchronized (mLock) { + if (mStatus != POLICY_STATUS_REGISTERED) { + throw new IllegalStateException("Cannot alter unregistered AudioPolicy"); + } + final ArrayList<AudioMix> zeMixes = new ArrayList<AudioMix>(mixes.size()); + for (AudioMix mix : mixes) { + if (mix == null) { + throw new IllegalArgumentException("Illegal null AudioMix in detachMixes"); + // TODO also check mix is currently contained in list of mixes + } else { + zeMixes.add(mix); + } + } + final AudioPolicyConfig cfg = new AudioPolicyConfig(zeMixes); + IAudioService service = getService(); + try { + final int status = service.removeMixForPolicy(cfg, this.cb()); + if (status == AudioManager.SUCCESS) { + mConfig.remove(zeMixes); + } + return status; + } catch (RemoteException e) { + Log.e(TAG, "Dead object in detachMixes", e); + return AudioManager.ERROR; + } } } @@ -377,6 +484,7 @@ public class AudioPolicy { new AudioAttributes.Builder() .setInternalCapturePreset(MediaRecorder.AudioSource.REMOTE_SUBMIX) .addTag(addressForTag(mix)) + .addTag(AudioRecord.SUBMIX_FIXED_VOLUME) .build(), mixFormat, AudioRecord.getMinBufferSize(mix.getFormat().getSampleRate(), @@ -440,9 +548,9 @@ public class AudioPolicy { * Only ever called if the {@link AudioPolicy} was built with * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to {@code true}. * @param afi information about the focus request and the requester - * @param requestResult the result that was returned synchronously by the framework to the - * application, {@link #AUDIOFOCUS_REQUEST_FAILED},or - * {@link #AUDIOFOCUS_REQUEST_DELAYED}. + * @param requestResult deprecated after the addition of + * {@link AudioManager#setFocusRequestResult(AudioFocusInfo, int, AudioPolicy)} + * in Android P, always equal to {@link #AUDIOFOCUS_REQUEST_GRANTED}. */ public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {} /** @@ -455,6 +563,23 @@ public class AudioPolicy { public void onAudioFocusAbandon(AudioFocusInfo afi) {} } + @SystemApi + /** + * Callback class to receive volume change-related events. + * See {@link #Builder.setAudioPolicyVolumeCallback(AudioPolicyCallback)} to configure the + * {@link AudioPolicy} to receive those events. + * + */ + public static abstract class AudioPolicyVolumeCallback { + /** @hide */ + public AudioPolicyVolumeCallback() {} + /** + * Called when volume key-related changes are triggered, on the key down event. + * @param adjustment the type of volume adjustment for the key. + */ + public void onVolumeAdjustment(@AudioManager.VolumeAdjustment int adjustment) {} + } + private void onPolicyStatusChange() { AudioPolicyStatusListener l; synchronized (mLock) { @@ -494,7 +619,7 @@ public class AudioPolicy { sendMsg(MSG_FOCUS_REQUEST, afi, requestResult); if (DEBUG) { Log.v(TAG, "notifyAudioFocusRequest: pack=" + afi.getPackageName() + " client=" - + afi.getClientId() + "reqRes=" + requestResult); + + afi.getClientId() + " gen=" + afi.getGen()); } } @@ -517,6 +642,13 @@ public class AudioPolicy { } } } + + public void notifyVolumeAdjust(int adjustment) { + sendMsg(MSG_VOL_ADJUST, null /* ignored */, adjustment); + if (DEBUG) { + Log.v(TAG, "notifyVolumeAdjust: " + adjustment); + } + } }; //================================================== @@ -528,6 +660,7 @@ public class AudioPolicy { private final static int MSG_MIX_STATE_UPDATE = 3; private final static int MSG_FOCUS_REQUEST = 4; private final static int MSG_FOCUS_ABANDON = 5; + private final static int MSG_VOL_ADJUST = 6; private class EventHandler extends Handler { public EventHandler(AudioPolicy ap, Looper looper) { @@ -571,6 +704,13 @@ public class AudioPolicy { Log.e(TAG, "Invalid null focus listener for focus abandon event"); } break; + case MSG_VOL_ADJUST: + if (mVolCb != null) { + mVolCb.onVolumeAdjustment(msg.arg1); + } else { // should never be null, but don't crash + Log.e(TAG, "Invalid null volume event"); + } + break; default: Log.e(TAG, "Unknown event " + msg.what); } diff --git a/android/media/audiopolicy/AudioPolicyConfig.java b/android/media/audiopolicy/AudioPolicyConfig.java index cafa5a8c..f725cacf 100644 --- a/android/media/audiopolicy/AudioPolicyConfig.java +++ b/android/media/audiopolicy/AudioPolicyConfig.java @@ -16,6 +16,7 @@ package android.media.audiopolicy; +import android.annotation.NonNull; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioPatch; @@ -24,6 +25,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.util.ArrayList; import java.util.Objects; @@ -35,11 +38,16 @@ public class AudioPolicyConfig implements Parcelable { private static final String TAG = "AudioPolicyConfig"; - protected ArrayList<AudioMix> mMixes; + protected final ArrayList<AudioMix> mMixes; protected int mDuckingPolicy = AudioPolicy.FOCUS_POLICY_DUCKING_IN_APP; private String mRegistrationId = null; + /** counter for the mixes that are / have been in the list of AudioMix + * e.g. register 4 mixes (counter is 3), remove 1 (counter is 3), add 1 (counter is 4) + */ + private int mMixCounter = 0; + protected AudioPolicyConfig(AudioPolicyConfig conf) { mMixes = conf.mMixes; } @@ -201,20 +209,39 @@ public class AudioPolicyConfig implements Parcelable { return; } mRegistrationId = regId == null ? "" : regId; - int mixIndex = 0; for (AudioMix mix : mMixes) { - if (!mRegistrationId.isEmpty()) { - if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) == - AudioMix.ROUTE_FLAG_LOOP_BACK) { - mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":" - + mixIndex++); - } else if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_RENDER) == - AudioMix.ROUTE_FLAG_RENDER) { - mix.setRegistration(mix.mDeviceAddress); - } - } else { - mix.setRegistration(""); + setMixRegistration(mix); + } + } + + private void setMixRegistration(@NonNull final AudioMix mix) { + if (!mRegistrationId.isEmpty()) { + if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) == + AudioMix.ROUTE_FLAG_LOOP_BACK) { + mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":" + + mMixCounter); + } else if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_RENDER) == + AudioMix.ROUTE_FLAG_RENDER) { + mix.setRegistration(mix.mDeviceAddress); } + } else { + mix.setRegistration(""); + } + mMixCounter++; + } + + @GuardedBy("mMixes") + protected void add(@NonNull ArrayList<AudioMix> mixes) { + for (AudioMix mix : mixes) { + setMixRegistration(mix); + mMixes.add(mix); + } + } + + @GuardedBy("mMixes") + protected void remove(@NonNull ArrayList<AudioMix> mixes) { + for (AudioMix mix : mixes) { + mMixes.remove(mix); } } |