Loading media/java/android/media/AudioManager.java +21 −3 Original line number Diff line number Diff line Loading @@ -4597,6 +4597,12 @@ public class AudioManager { } } /** * @hide * Volume behavior for an audio device that has no particular volume behavior set. Invalid as * an argument to {@link #setDeviceVolumeBehavior(int, String, int)}. */ public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1; /** * @hide * Volume behavior for an audio device where a software attenuation is applied Loading Loading @@ -4647,6 +4653,18 @@ public class AudioManager { @Retention(RetentionPolicy.SOURCE) public @interface DeviceVolumeBehavior {} /** @hide */ @IntDef({ DEVICE_VOLUME_BEHAVIOR_UNSET, DEVICE_VOLUME_BEHAVIOR_VARIABLE, DEVICE_VOLUME_BEHAVIOR_FULL, DEVICE_VOLUME_BEHAVIOR_FIXED, DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE, }) @Retention(RetentionPolicy.SOURCE) public @interface DeviceVolumeBehaviorState {} /** * @hide * Throws IAE on an invalid volume behavior value Loading Loading @@ -4713,7 +4731,7 @@ public class AudioManager { * @return the volume behavior for the device */ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public @DeviceVolumeBehavior int getDeviceVolumeBehavior(int deviceType, public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(int deviceType, @Nullable String deviceAddress) { // verify arguments AudioDeviceInfo.enforceValidAudioDeviceTypeOut(deviceType); Loading @@ -4728,8 +4746,8 @@ public class AudioManager { * @return the volume behavior for the device */ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public @DeviceVolumeBehavior int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior( @NonNull AudioDeviceAttributes device) { // verify arguments (validity of device type is enforced in server) Objects.requireNonNull(device); // communicate with service Loading services/core/java/com/android/server/audio/AudioService.java +157 −72 Original line number Diff line number Diff line Loading @@ -413,6 +413,13 @@ public class AudioService extends IAudioService.Stub AppOpsManager.OP_AUDIO_MEDIA_VOLUME // STREAM_ASSISTANT }; private static Set<Integer> sDeviceVolumeBehaviorSupportedDeviceOutSet = new HashSet<>( Arrays.asList( AudioSystem.DEVICE_OUT_HDMI, AudioSystem.DEVICE_OUT_HDMI_ARC, AudioSystem.DEVICE_OUT_SPDIF, AudioSystem.DEVICE_OUT_LINE)); private final boolean mUseFixedVolume; /** Loading Loading @@ -525,7 +532,6 @@ public class AudioService extends IAudioService.Stub // Devices for which the volume is fixed (volume is either max or muted) Set<Integer> mFixedVolumeDevices = new HashSet<>(Arrays.asList( AudioSystem.DEVICE_OUT_HDMI, AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, AudioSystem.DEVICE_OUT_HDMI_ARC, Loading Loading @@ -929,11 +935,6 @@ public class AudioService extends IAudioService.Stub AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET); } mHdmiPlaybackClient = mHdmiManager.getPlaybackClient(); if (mHdmiPlaybackClient != null) { // not a television: HDMI output will be always at max mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI); mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI); } mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient(); } } Loading Loading @@ -4049,6 +4050,11 @@ public class AudioService extends IAudioService.Stub } readVolumeGroupsSettings(); if (DEBUG_VOL) { Log.d(TAG, "Restoring device volume behavior"); } restoreDeviceVolumeBehavior(); } /** @see AudioManager#setSpeakerphoneOn(boolean) */ Loading Loading @@ -4908,50 +4914,47 @@ public class AudioService extends IAudioService.Stub if (pkgName == null) { pkgName = ""; } // translate Java device type to native device type (for the devices masks for full / fixed) final int type; switch (device.getType()) { case AudioDeviceInfo.TYPE_HDMI: type = AudioSystem.DEVICE_OUT_HDMI; break; case AudioDeviceInfo.TYPE_HDMI_ARC: type = AudioSystem.DEVICE_OUT_HDMI_ARC; break; case AudioDeviceInfo.TYPE_LINE_DIGITAL: type = AudioSystem.DEVICE_OUT_SPDIF; break; case AudioDeviceInfo.TYPE_AUX_LINE: type = AudioSystem.DEVICE_OUT_LINE; break; default: int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice( device.getType()); setDeviceVolumeBehaviorInternal(audioSystemDeviceOut, deviceVolumeBehavior, pkgName); persistDeviceVolumeBehavior(audioSystemDeviceOut, deviceVolumeBehavior); } private void setDeviceVolumeBehaviorInternal(int audioSystemDeviceOut, @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) { if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)) { // unsupported for now throw new IllegalArgumentException("Unsupported device type " + device.getType()); throw new IllegalArgumentException("Unsupported device type " + audioSystemDeviceOut); } // update device masks based on volume behavior switch (deviceVolumeBehavior) { case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE: mFullVolumeDevices.remove(type); mFixedVolumeDevices.remove(type); removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut); removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED: mFullVolumeDevices.remove(type); mFixedVolumeDevices.add(type); removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut); addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL: mFullVolumeDevices.add(type); mFixedVolumeDevices.remove(type); addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut); removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE: case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE: throw new IllegalArgumentException("Absolute volume unsupported for now"); } // log event and caller sDeviceLogger.log(new AudioEventLogger.StringEvent( "Volume behavior " + deviceVolumeBehavior + " for dev=0x" + Integer.toHexString(type) + " by pkg:" + pkgName)); "Volume behavior " + deviceVolumeBehavior + " for dev=0x" + Integer.toHexString(audioSystemDeviceOut) + " from:" + caller)); // make sure we have a volume entry for this device, and that volume is updated according // to volume behavior checkAddAllFixedVolumeDevices(type, "setDeviceVolumeBehavior:" + pkgName); checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller); } /** Loading @@ -4959,45 +4962,38 @@ public class AudioService extends IAudioService.Stub * @param device the audio output device type * @return the volume behavior for the device */ public @AudioManager.DeviceVolumeBehavior int getDeviceVolumeBehavior( public @AudioManager.DeviceVolumeBehaviorState int getDeviceVolumeBehavior( @NonNull AudioDeviceAttributes device) { // verify permissions enforceModifyAudioRoutingPermission(); // translate Java device type to native device type (for the devices masks for full / fixed) final int type; switch (device.getType()) { case AudioDeviceInfo.TYPE_HEARING_AID: type = AudioSystem.DEVICE_OUT_HEARING_AID; break; case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP: type = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; break; case AudioDeviceInfo.TYPE_HDMI: type = AudioSystem.DEVICE_OUT_HDMI; break; case AudioDeviceInfo.TYPE_HDMI_ARC: type = AudioSystem.DEVICE_OUT_HDMI_ARC; break; case AudioDeviceInfo.TYPE_LINE_DIGITAL: type = AudioSystem.DEVICE_OUT_SPDIF; break; case AudioDeviceInfo.TYPE_AUX_LINE: type = AudioSystem.DEVICE_OUT_LINE; break; default: // unsupported for now throw new IllegalArgumentException("Unsupported device type " + device.getType()); final int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice( device.getType()); if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut) && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_HEARING_AID) { throw new IllegalArgumentException("Unsupported volume behavior " + audioSystemDeviceOut); } int setDeviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut); if (setDeviceVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) { return setDeviceVolumeBehavior; } if ((mFullVolumeDevices.contains(type))) { // setDeviceVolumeBehavior has not been explicitly called for the device type. Deduce the // current volume behavior. if ((mFullVolumeDevices.contains(audioSystemDeviceOut))) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL; } if ((mFixedVolumeDevices.contains(type))) { if ((mFixedVolumeDevices.contains(audioSystemDeviceOut))) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED; } if ((mAbsVolumeMultiModeCaseDevices.contains(type))) { if ((mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut))) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE; } if (type == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP if (audioSystemDeviceOut == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP && mDeviceBroker.isAvrcpAbsoluteVolumeSupported()) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE; } Loading Loading @@ -7120,18 +7116,20 @@ public class AudioService extends IAudioService.Stub @GuardedBy("mHdmiClientLock") private void updateHdmiCecSinkLocked(boolean hdmiCecSink) { mHdmiCecSink = hdmiCecSink; if (!hasDeviceVolumeBehavior(AudioSystem.DEVICE_OUT_HDMI)) { if (mHdmiCecSink) { if (DEBUG_VOL) { Log.d(TAG, "CEC sink: setting HDMI as full vol device"); } mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI); addAudioSystemDeviceOutToFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI); } else { if (DEBUG_VOL) { Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device"); } // Android TV devices without CEC service apply software volume on // HDMI output mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI); removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI); } } checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, Loading Loading @@ -8970,4 +8968,91 @@ public class AudioService extends IAudioService.Stub } return mFullVolumeDevices.contains(deviceType); } //==================== // Helper functions for {set,get}DeviceVolumeBehavior //==================== private static String getSettingsNameForDeviceVolumeBehavior(int deviceType) { return "AudioService_DeviceVolumeBehavior_" + AudioSystem.getOutputDeviceName(deviceType); } private void persistDeviceVolumeBehavior(int deviceType, @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior) { if (DEBUG_VOL) { Log.d(TAG, "Persisting Volume Behavior for DeviceType: " + deviceType); } System.putIntForUser(mContentResolver, getSettingsNameForDeviceVolumeBehavior(deviceType), deviceVolumeBehavior, UserHandle.USER_CURRENT); } @AudioManager.DeviceVolumeBehaviorState private int retrieveStoredDeviceVolumeBehavior(int deviceType) { return System.getIntForUser(mContentResolver, getSettingsNameForDeviceVolumeBehavior(deviceType), AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET, UserHandle.USER_CURRENT); } private void restoreDeviceVolumeBehavior() { for (int deviceType : sDeviceVolumeBehaviorSupportedDeviceOutSet) { if (DEBUG_VOL) { Log.d(TAG, "Retrieving Volume Behavior for DeviceType: " + deviceType); } int deviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(deviceType); if (deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) { if (DEBUG_VOL) { Log.d(TAG, "Skipping Setting Volume Behavior for DeviceType: " + deviceType); } continue; } setDeviceVolumeBehaviorInternal(deviceType, deviceVolumeBehavior, "AudioService.restoreDeviceVolumeBehavior()"); } } /** * @param audioSystemDeviceOut one of AudioSystem.DEVICE_OUT_* * @return whether {@code audioSystemDeviceOut} has previously been set to a specific volume * behavior */ private boolean hasDeviceVolumeBehavior( int audioSystemDeviceOut) { return retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut) != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET; } private void addAudioSystemDeviceOutToFixedVolumeDevices(int audioSystemDeviceOut) { if (DEBUG_VOL) { Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " to mFixedVolumeDevices"); } mFixedVolumeDevices.add(audioSystemDeviceOut); } private void removeAudioSystemDeviceOutFromFixedVolumeDevices(int audioSystemDeviceOut) { if (DEBUG_VOL) { Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " from mFixedVolumeDevices"); } mFixedVolumeDevices.remove(audioSystemDeviceOut); } private void addAudioSystemDeviceOutToFullVolumeDevices(int audioSystemDeviceOut) { if (DEBUG_VOL) { Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " to mFullVolumeDevices"); } mFullVolumeDevices.add(audioSystemDeviceOut); } private void removeAudioSystemDeviceOutFromFullVolumeDevices(int audioSystemDeviceOut) { if (DEBUG_VOL) { Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " from mFullVolumeDevices"); } mFullVolumeDevices.remove(audioSystemDeviceOut); } } Loading
media/java/android/media/AudioManager.java +21 −3 Original line number Diff line number Diff line Loading @@ -4597,6 +4597,12 @@ public class AudioManager { } } /** * @hide * Volume behavior for an audio device that has no particular volume behavior set. Invalid as * an argument to {@link #setDeviceVolumeBehavior(int, String, int)}. */ public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1; /** * @hide * Volume behavior for an audio device where a software attenuation is applied Loading Loading @@ -4647,6 +4653,18 @@ public class AudioManager { @Retention(RetentionPolicy.SOURCE) public @interface DeviceVolumeBehavior {} /** @hide */ @IntDef({ DEVICE_VOLUME_BEHAVIOR_UNSET, DEVICE_VOLUME_BEHAVIOR_VARIABLE, DEVICE_VOLUME_BEHAVIOR_FULL, DEVICE_VOLUME_BEHAVIOR_FIXED, DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE, }) @Retention(RetentionPolicy.SOURCE) public @interface DeviceVolumeBehaviorState {} /** * @hide * Throws IAE on an invalid volume behavior value Loading Loading @@ -4713,7 +4731,7 @@ public class AudioManager { * @return the volume behavior for the device */ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public @DeviceVolumeBehavior int getDeviceVolumeBehavior(int deviceType, public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(int deviceType, @Nullable String deviceAddress) { // verify arguments AudioDeviceInfo.enforceValidAudioDeviceTypeOut(deviceType); Loading @@ -4728,8 +4746,8 @@ public class AudioManager { * @return the volume behavior for the device */ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public @DeviceVolumeBehavior int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior( @NonNull AudioDeviceAttributes device) { // verify arguments (validity of device type is enforced in server) Objects.requireNonNull(device); // communicate with service Loading
services/core/java/com/android/server/audio/AudioService.java +157 −72 Original line number Diff line number Diff line Loading @@ -413,6 +413,13 @@ public class AudioService extends IAudioService.Stub AppOpsManager.OP_AUDIO_MEDIA_VOLUME // STREAM_ASSISTANT }; private static Set<Integer> sDeviceVolumeBehaviorSupportedDeviceOutSet = new HashSet<>( Arrays.asList( AudioSystem.DEVICE_OUT_HDMI, AudioSystem.DEVICE_OUT_HDMI_ARC, AudioSystem.DEVICE_OUT_SPDIF, AudioSystem.DEVICE_OUT_LINE)); private final boolean mUseFixedVolume; /** Loading Loading @@ -525,7 +532,6 @@ public class AudioService extends IAudioService.Stub // Devices for which the volume is fixed (volume is either max or muted) Set<Integer> mFixedVolumeDevices = new HashSet<>(Arrays.asList( AudioSystem.DEVICE_OUT_HDMI, AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, AudioSystem.DEVICE_OUT_HDMI_ARC, Loading Loading @@ -929,11 +935,6 @@ public class AudioService extends IAudioService.Stub AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET); } mHdmiPlaybackClient = mHdmiManager.getPlaybackClient(); if (mHdmiPlaybackClient != null) { // not a television: HDMI output will be always at max mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI); mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI); } mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient(); } } Loading Loading @@ -4049,6 +4050,11 @@ public class AudioService extends IAudioService.Stub } readVolumeGroupsSettings(); if (DEBUG_VOL) { Log.d(TAG, "Restoring device volume behavior"); } restoreDeviceVolumeBehavior(); } /** @see AudioManager#setSpeakerphoneOn(boolean) */ Loading Loading @@ -4908,50 +4914,47 @@ public class AudioService extends IAudioService.Stub if (pkgName == null) { pkgName = ""; } // translate Java device type to native device type (for the devices masks for full / fixed) final int type; switch (device.getType()) { case AudioDeviceInfo.TYPE_HDMI: type = AudioSystem.DEVICE_OUT_HDMI; break; case AudioDeviceInfo.TYPE_HDMI_ARC: type = AudioSystem.DEVICE_OUT_HDMI_ARC; break; case AudioDeviceInfo.TYPE_LINE_DIGITAL: type = AudioSystem.DEVICE_OUT_SPDIF; break; case AudioDeviceInfo.TYPE_AUX_LINE: type = AudioSystem.DEVICE_OUT_LINE; break; default: int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice( device.getType()); setDeviceVolumeBehaviorInternal(audioSystemDeviceOut, deviceVolumeBehavior, pkgName); persistDeviceVolumeBehavior(audioSystemDeviceOut, deviceVolumeBehavior); } private void setDeviceVolumeBehaviorInternal(int audioSystemDeviceOut, @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) { if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)) { // unsupported for now throw new IllegalArgumentException("Unsupported device type " + device.getType()); throw new IllegalArgumentException("Unsupported device type " + audioSystemDeviceOut); } // update device masks based on volume behavior switch (deviceVolumeBehavior) { case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE: mFullVolumeDevices.remove(type); mFixedVolumeDevices.remove(type); removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut); removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED: mFullVolumeDevices.remove(type); mFixedVolumeDevices.add(type); removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut); addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL: mFullVolumeDevices.add(type); mFixedVolumeDevices.remove(type); addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut); removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE: case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE: throw new IllegalArgumentException("Absolute volume unsupported for now"); } // log event and caller sDeviceLogger.log(new AudioEventLogger.StringEvent( "Volume behavior " + deviceVolumeBehavior + " for dev=0x" + Integer.toHexString(type) + " by pkg:" + pkgName)); "Volume behavior " + deviceVolumeBehavior + " for dev=0x" + Integer.toHexString(audioSystemDeviceOut) + " from:" + caller)); // make sure we have a volume entry for this device, and that volume is updated according // to volume behavior checkAddAllFixedVolumeDevices(type, "setDeviceVolumeBehavior:" + pkgName); checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller); } /** Loading @@ -4959,45 +4962,38 @@ public class AudioService extends IAudioService.Stub * @param device the audio output device type * @return the volume behavior for the device */ public @AudioManager.DeviceVolumeBehavior int getDeviceVolumeBehavior( public @AudioManager.DeviceVolumeBehaviorState int getDeviceVolumeBehavior( @NonNull AudioDeviceAttributes device) { // verify permissions enforceModifyAudioRoutingPermission(); // translate Java device type to native device type (for the devices masks for full / fixed) final int type; switch (device.getType()) { case AudioDeviceInfo.TYPE_HEARING_AID: type = AudioSystem.DEVICE_OUT_HEARING_AID; break; case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP: type = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; break; case AudioDeviceInfo.TYPE_HDMI: type = AudioSystem.DEVICE_OUT_HDMI; break; case AudioDeviceInfo.TYPE_HDMI_ARC: type = AudioSystem.DEVICE_OUT_HDMI_ARC; break; case AudioDeviceInfo.TYPE_LINE_DIGITAL: type = AudioSystem.DEVICE_OUT_SPDIF; break; case AudioDeviceInfo.TYPE_AUX_LINE: type = AudioSystem.DEVICE_OUT_LINE; break; default: // unsupported for now throw new IllegalArgumentException("Unsupported device type " + device.getType()); final int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice( device.getType()); if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut) && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_HEARING_AID) { throw new IllegalArgumentException("Unsupported volume behavior " + audioSystemDeviceOut); } int setDeviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut); if (setDeviceVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) { return setDeviceVolumeBehavior; } if ((mFullVolumeDevices.contains(type))) { // setDeviceVolumeBehavior has not been explicitly called for the device type. Deduce the // current volume behavior. if ((mFullVolumeDevices.contains(audioSystemDeviceOut))) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL; } if ((mFixedVolumeDevices.contains(type))) { if ((mFixedVolumeDevices.contains(audioSystemDeviceOut))) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED; } if ((mAbsVolumeMultiModeCaseDevices.contains(type))) { if ((mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut))) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE; } if (type == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP if (audioSystemDeviceOut == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP && mDeviceBroker.isAvrcpAbsoluteVolumeSupported()) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE; } Loading Loading @@ -7120,18 +7116,20 @@ public class AudioService extends IAudioService.Stub @GuardedBy("mHdmiClientLock") private void updateHdmiCecSinkLocked(boolean hdmiCecSink) { mHdmiCecSink = hdmiCecSink; if (!hasDeviceVolumeBehavior(AudioSystem.DEVICE_OUT_HDMI)) { if (mHdmiCecSink) { if (DEBUG_VOL) { Log.d(TAG, "CEC sink: setting HDMI as full vol device"); } mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI); addAudioSystemDeviceOutToFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI); } else { if (DEBUG_VOL) { Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device"); } // Android TV devices without CEC service apply software volume on // HDMI output mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI); removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI); } } checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, Loading Loading @@ -8970,4 +8968,91 @@ public class AudioService extends IAudioService.Stub } return mFullVolumeDevices.contains(deviceType); } //==================== // Helper functions for {set,get}DeviceVolumeBehavior //==================== private static String getSettingsNameForDeviceVolumeBehavior(int deviceType) { return "AudioService_DeviceVolumeBehavior_" + AudioSystem.getOutputDeviceName(deviceType); } private void persistDeviceVolumeBehavior(int deviceType, @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior) { if (DEBUG_VOL) { Log.d(TAG, "Persisting Volume Behavior for DeviceType: " + deviceType); } System.putIntForUser(mContentResolver, getSettingsNameForDeviceVolumeBehavior(deviceType), deviceVolumeBehavior, UserHandle.USER_CURRENT); } @AudioManager.DeviceVolumeBehaviorState private int retrieveStoredDeviceVolumeBehavior(int deviceType) { return System.getIntForUser(mContentResolver, getSettingsNameForDeviceVolumeBehavior(deviceType), AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET, UserHandle.USER_CURRENT); } private void restoreDeviceVolumeBehavior() { for (int deviceType : sDeviceVolumeBehaviorSupportedDeviceOutSet) { if (DEBUG_VOL) { Log.d(TAG, "Retrieving Volume Behavior for DeviceType: " + deviceType); } int deviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(deviceType); if (deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) { if (DEBUG_VOL) { Log.d(TAG, "Skipping Setting Volume Behavior for DeviceType: " + deviceType); } continue; } setDeviceVolumeBehaviorInternal(deviceType, deviceVolumeBehavior, "AudioService.restoreDeviceVolumeBehavior()"); } } /** * @param audioSystemDeviceOut one of AudioSystem.DEVICE_OUT_* * @return whether {@code audioSystemDeviceOut} has previously been set to a specific volume * behavior */ private boolean hasDeviceVolumeBehavior( int audioSystemDeviceOut) { return retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut) != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET; } private void addAudioSystemDeviceOutToFixedVolumeDevices(int audioSystemDeviceOut) { if (DEBUG_VOL) { Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " to mFixedVolumeDevices"); } mFixedVolumeDevices.add(audioSystemDeviceOut); } private void removeAudioSystemDeviceOutFromFixedVolumeDevices(int audioSystemDeviceOut) { if (DEBUG_VOL) { Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " from mFixedVolumeDevices"); } mFixedVolumeDevices.remove(audioSystemDeviceOut); } private void addAudioSystemDeviceOutToFullVolumeDevices(int audioSystemDeviceOut) { if (DEBUG_VOL) { Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " to mFullVolumeDevices"); } mFullVolumeDevices.add(audioSystemDeviceOut); } private void removeAudioSystemDeviceOutFromFullVolumeDevices(int audioSystemDeviceOut) { if (DEBUG_VOL) { Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " from mFullVolumeDevices"); } mFullVolumeDevices.remove(audioSystemDeviceOut); } }