diff options
| -rw-r--r-- | api/system-current.txt | 5 | ||||
| -rw-r--r-- | media/java/android/media/AudioManager.java | 14 | ||||
| -rw-r--r-- | media/java/android/media/IAudioService.aidl | 3 | ||||
| -rw-r--r-- | media/java/android/media/audiopolicy/AudioPolicy.java | 58 | ||||
| -rw-r--r-- | media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl | 3 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioService.java | 53 |
6 files changed, 125 insertions, 11 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index ed3897c7a8bb..396ff1a9aa33 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2603,12 +2603,17 @@ package android.media.audiopolicy { method public void onStatusChange(); } + public static abstract class AudioPolicy.AudioPolicyVolumeCallback { + method public void onVolumeAdjustment(int); + } + public static class AudioPolicy.Builder { ctor public AudioPolicy.Builder(android.content.Context); method public android.media.audiopolicy.AudioPolicy.Builder addMix(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException; method 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(android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback); method public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean); method public android.media.audiopolicy.AudioPolicy.Builder setLooper(android.os.Looper) throws java.lang.IllegalArgumentException; } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 2ac4063d1b08..7533701138d0 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -400,6 +400,18 @@ public class AudioManager { public static final int ADJUST_TOGGLE_MUTE = 101; /** @hide */ + @IntDef(flag = false, prefix = "ADJUST", value = { + ADJUST_RAISE, + ADJUST_LOWER, + ADJUST_SAME, + ADJUST_MUTE, + ADJUST_UNMUTE, + ADJUST_TOGGLE_MUTE } + ) + @Retention(RetentionPolicy.SOURCE) + public @interface VolumeAdjustement {} + + /** @hide */ public static final String adjustToString(int adj) { switch (adj) { case ADJUST_RAISE: return "ADJUST_RAISE"; @@ -2989,7 +3001,7 @@ public class AudioManager { final IAudioService service = getService(); try { String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), - policy.hasFocusListener(), policy.isFocusPolicy()); + policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController()); if (regId == null) { return ERROR; } else { diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 6c6522328e8d..88d0a6088026 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -166,7 +166,8 @@ interface IAudioService { boolean isHdmiSystemAudioSupported(); String registerAudioPolicy(in AudioPolicyConfig policyConfig, - in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy); + in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy, + boolean isVolumeController); 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 7e88c277cc23..d0bba6db9db5 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -89,6 +89,8 @@ public class AudioPolicy { private AudioPolicyFocusListener mFocusListener; + private final AudioPolicyVolumeCallback mVolCb; + private Context mContext; private AudioPolicyConfig mConfig; @@ -99,12 +101,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 +125,7 @@ public class AudioPolicy { mFocusListener = fl; mStatusListener = sl; mIsFocusPolicy = isFocusPolicy; + mVolCb = vc; } /** @@ -134,6 +140,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 +215,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 +252,7 @@ public class AudioPolicy { + "an AudioPolicyFocusListener"); } return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper, - mFocusListener, mStatusListener, mIsFocusPolicy); + mFocusListener, mStatusListener, mIsFocusPolicy, mVolCb); } } @@ -455,6 +478,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 adjustement the type of volume adjustment for the key. + */ + public void onVolumeAdjustment(@AudioManager.VolumeAdjustement int adjustement) {} + } + private void onPolicyStatusChange() { AudioPolicyStatusListener l; synchronized (mLock) { @@ -517,6 +557,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 +575,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 +619,12 @@ 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"); + } default: Log.e(TAG, "Unknown event " + msg.what); } diff --git a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl index 86abbb4dc8d9..107e7cd59ca2 100644 --- a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl +++ b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl @@ -31,4 +31,7 @@ oneway interface IAudioPolicyCallback { // callback for mix activity status update void notifyMixStateUpdate(in String regId, int state); + + // callback for volume events + void notifyVolumeAdjust(int adjustment); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index f6bcb2524534..f247de7adadc 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1329,8 +1329,20 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#adjustVolume(int, int) */ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage, String caller) { - adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage, - caller, Binder.getCallingUid()); + final IAudioPolicyCallback extVolCtlr; + synchronized (mExtVolumeControllerLock) { + extVolCtlr = mExtVolumeController; + } + if (extVolCtlr != null) { + try { + mExtVolumeController.notifyVolumeAdjust(direction); + } catch(RemoteException e) { + // nothing we can do about this. Do not log error, too much potential for spam + } + } else { + adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage, + caller, Binder.getCallingUid()); + } } private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, @@ -6964,7 +6976,7 @@ public class AudioService extends IAudioService.Stub // Audio policy management //========================================================================================== public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb, - boolean hasFocusListener, boolean isFocusPolicy) { + boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController) { AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback); if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder() @@ -6987,7 +6999,7 @@ public class AudioService extends IAudioService.Stub return null; } AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener, - isFocusPolicy); + isFocusPolicy, isVolumeController); pcb.asBinder().linkToDeath(app, 0/*flags*/); regId = app.getRegistrationId(); mAudioPolicies.put(pcb.asBinder(), app); @@ -7053,6 +7065,23 @@ public class AudioService extends IAudioService.Stub return AudioManager.SUCCESS; } + private final Object mExtVolumeControllerLock = new Object(); + private IAudioPolicyCallback mExtVolumeController; + private void setExtVolumeController(IAudioPolicyCallback apc) { + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_handleVolumeKeysInWindowManager)) { + Log.e(TAG, "Cannot set external volume controller: device not set for volume keys" + + " handled in PhoneWindowManager"); + return; + } + synchronized (mExtVolumeControllerLock) { + if (mExtVolumeController != null && !mExtVolumeController.asBinder().pingBinder()) { + Log.e(TAG, "Cannot set external volume controller: existing controller"); + } + mExtVolumeController = apc; + } + } + private void dumpAudioPolicies(PrintWriter pw) { pw.println("\nAudio policies:"); synchronized (mAudioPolicies) { @@ -7185,8 +7214,9 @@ public class AudioService extends IAudioService.Stub */ public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient { private static final String TAG = "AudioPolicyProxy"; - IAudioPolicyCallback mPolicyCallback; - boolean mHasFocusListener; + final IAudioPolicyCallback mPolicyCallback; + final boolean mHasFocusListener; + final boolean mIsVolumeController; /** * Audio focus ducking behavior for an audio policy. * This variable reflects the value that was successfully set in @@ -7198,11 +7228,12 @@ public class AudioService extends IAudioService.Stub boolean mIsFocusPolicy = false; AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token, - boolean hasFocusListener, boolean isFocusPolicy) { + boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController) { super(config); setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++)); mPolicyCallback = token; mHasFocusListener = hasFocusListener; + mIsVolumeController = isVolumeController; if (mHasFocusListener) { mMediaFocusControl.addFocusFollower(mPolicyCallback); // can only ever be true if there is a focus listener @@ -7211,6 +7242,9 @@ public class AudioService extends IAudioService.Stub mMediaFocusControl.setFocusPolicy(mPolicyCallback); } } + if (mIsVolumeController) { + setExtVolumeController(mPolicyCallback); + } connectMixes(); } @@ -7220,6 +7254,11 @@ public class AudioService extends IAudioService.Stub release(); mAudioPolicies.remove(mPolicyCallback.asBinder()); } + if (mIsVolumeController) { + synchronized (mExtVolumeControllerLock) { + mExtVolumeController = null; + } + } } String getRegistrationId() { |