diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 8aa451f9aab65..831ac6f0f107f 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -5062,8 +5062,8 @@ package android.media { method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List getAudioProductStrategies(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List getAudioVolumeGroups(); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List getDevicesForAttributes(@NonNull android.media.AudioAttributes); + method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public java.util.List getDevicesForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 2f859d73fde46..3e0094aec6f9b 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1335,6 +1335,7 @@ package android.media { public class AudioManager { method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int); method public boolean hasRegisteredDynamicPolicy(); + method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.QUERY_AUDIO_STATE}) public boolean isFullVolumeDevice(); } public static final class AudioRecord.MetricsConstants { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index e8e263147c6e7..9e9d02e4eebfe 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -5287,7 +5287,10 @@ public class AudioManager { * otherwise (typically one device, except for duplicated paths). */ @SystemApi - @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @RequiresPermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_ROUTING, + android.Manifest.permission.QUERY_AUDIO_STATE + }) public @NonNull List getDevicesForAttributes( @NonNull AudioAttributes attributes) { Objects.requireNonNull(attributes); @@ -5426,7 +5429,10 @@ public class AudioManager { * @return the volume behavior for the device */ @SystemApi - @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @RequiresPermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_ROUTING, + android.Manifest.permission.QUERY_AUDIO_STATE + }) public @DeviceVolumeBehavior int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { // verify arguments (validity of device type is enforced in server) @@ -5440,6 +5446,28 @@ public class AudioManager { } } + /** + * @hide + * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}. + */ + @TestApi + @RequiresPermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_ROUTING, + android.Manifest.permission.QUERY_AUDIO_STATE + }) + public boolean isFullVolumeDevice() { + final AudioAttributes attributes = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .build(); + final List devices = getDevicesForAttributes(attributes); + for (AudioDeviceAttributes device : devices) { + if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) { + return true; + } + } + return false; + } + /** * Indicate wired accessory connection state change. * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx) diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 1950710a36e0a..0a6847515137f 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2258,7 +2258,7 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#getDevicesForAttributes(AudioAttributes) */ public @NonNull ArrayList getDevicesForAttributes( @NonNull AudioAttributes attributes) { - enforceModifyAudioRoutingPermission(); + enforceQueryStateOrModifyRoutingPermission(); return getDevicesForAttributesInt(attributes); } @@ -2900,6 +2900,16 @@ public class AudioService extends IAudioService.Stub } } + private void enforceQueryStateOrModifyRoutingPermission() { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + != PackageManager.PERMISSION_GRANTED + && mContext.checkCallingOrSelfPermission(Manifest.permission.QUERY_AUDIO_STATE) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Missing MODIFY_AUDIO_ROUTING or QUERY_AUDIO_STATE permissions"); + } + } + /** @see AudioManager#setVolumeIndexForAttributes(attr, int, int) */ public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags, String callingPackage) { @@ -5814,7 +5824,7 @@ public class AudioService extends IAudioService.Stub public @AudioManager.DeviceVolumeBehavior int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { // verify permissions - enforceModifyAudioRoutingPermission(); + enforceQueryStateOrModifyRoutingPermission(); // translate Java device type to native device type (for the devices masks for full / fixed) final int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(