diff options
Diffstat (limited to 'android/media/audiopolicy/AudioPolicy.java')
-rw-r--r-- | android/media/audiopolicy/AudioPolicy.java | 152 |
1 files changed, 146 insertions, 6 deletions
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); } |