diff --git a/api/system-current.txt b/api/system-current.txt index ea64dc2b73018..81e9322400fea 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3457,6 +3457,9 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioProductStrategies getAudioProductStrategies(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioVolumeGroups getAudioVolumeGroups(); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method public boolean isAudioServerRunning(); method public boolean isHdmiSystemAudioSupported(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); @@ -3466,6 +3469,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy); method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); method public void unregisterVolumeGroupCallback(@NonNull android.media.AudioManager.VolumeGroupCallback); field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1 diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 69008ede0d7ea..15f9b47ede091 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1168,6 +1168,93 @@ public class AudioManager { } } + /** + * Sets the volume index for a particular {@link AudioAttributes}. + * @param attr The {@link AudioAttributes} whose volume index should be set. + * @param index The volume index to set. See + * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value + * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value. + * @param flags One or more flags. + * @see #getMaxVolumeIndexForAttributes(AudioAttributes) + * @see #getMinVolumeIndexForAttributes(AudioAttributes) + * @see #isVolumeFixed() + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) { + Preconditions.checkNotNull(attr, "attr must not be null"); + final IAudioService service = getService(); + try { + service.setVolumeIndexForAttributes(attr, index, flags, + getContext().getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the current volume index for a particular {@link AudioAttributes}. + * + * @param attr The {@link AudioAttributes} whose volume index is returned. + * @return The current volume index for the stream. + * @see #getMaxVolumeIndexForAttributes(AudioAttributes) + * @see #getMinVolumeIndexForAttributes(AudioAttributes) + * @see #setVolumeForAttributes(AudioAttributes, int, int) + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { + Preconditions.checkNotNull(attr, "attr must not be null"); + final IAudioService service = getService(); + try { + return service.getVolumeIndexForAttributes(attr); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the maximum volume index for a particular {@link AudioAttributes}. + * + * @param attr The {@link AudioAttributes} whose maximum volume index is returned. + * @return The maximum valid volume index for the {@link AudioAttributes}. + * @see #getVolumeIndexForAttributes(AudioAttributes) + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) { + Preconditions.checkNotNull(attr, "attr must not be null"); + final IAudioService service = getService(); + try { + return service.getMaxVolumeIndexForAttributes(attr); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the minimum volume index for a particular {@link AudioAttributes}. + * + * @param attr The {@link AudioAttributes} whose minimum volume index is returned. + * @return The minimum valid volume index for the {@link AudioAttributes}. + * @see #getVolumeIndexForAttributes(AudioAttributes) + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) { + Preconditions.checkNotNull(attr, "attr must not be null"); + final IAudioService service = getService(); + try { + return service.getMinVolumeIndexForAttributes(attr); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Solo or unsolo a particular stream. *

@@ -5262,7 +5349,12 @@ public class AudioManager { @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public @NonNull AudioVolumeGroups getAudioVolumeGroups() { - return new AudioVolumeGroups(); + final IAudioService service = getService(); + try { + return service.listAudioVolumeGroups(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index abdc3c9c834bb..3fe29d717762e 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -34,6 +34,7 @@ import android.media.PlayerBase; import android.media.VolumePolicy; import android.media.audiopolicy.AudioPolicyConfig; import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioVolumeGroups; import android.media.audiopolicy.IAudioPolicyCallback; import android.media.projection.IMediaProjection; @@ -81,6 +82,16 @@ interface IAudioService { int getStreamMaxVolume(int streamType); + AudioVolumeGroups listAudioVolumeGroups(); + + void setVolumeIndexForAttributes(in AudioAttributes aa, int index, int flags, String callingPackage); + + int getVolumeIndexForAttributes(in AudioAttributes aa); + + int getMaxVolumeIndexForAttributes(in AudioAttributes aa); + + int getMinVolumeIndexForAttributes(in AudioAttributes aa); + int getLastAudibleStreamVolume(int streamType); AudioProductStrategies getAudioProductStrategies(); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 5d802a76ae95c..6bd412bcd536e 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -89,6 +89,8 @@ import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicyConfig; import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioVolumeGroup; +import android.media.audiopolicy.AudioVolumeGroups; import android.media.audiopolicy.IAudioPolicyCallback; import android.media.projection.IMediaProjection; import android.media.projection.IMediaProjectionManager; @@ -128,6 +130,7 @@ import android.widget.Toast; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.DumpUtils; +import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.EventLogTags; import com.android.server.LocalServices; @@ -277,6 +280,8 @@ public class AudioService extends IAudioService.Stub /** @see AudioProductStrategies */ private static AudioProductStrategies sAudioProductStrategies; + /** @see AudioVolumeGroups */ + private static AudioVolumeGroups sAudioVolumeGroups; private int mMode = AudioSystem.MODE_NORMAL; // protects mRingerMode @@ -629,6 +634,7 @@ public class AudioService extends IAudioService.Stub mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator(); sAudioProductStrategies = new AudioProductStrategies(); + sAudioVolumeGroups = new AudioVolumeGroups(); // Initialize volume int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1); @@ -1002,6 +1008,14 @@ public class AudioService extends IAudioService.Stub return sAudioProductStrategies; } + /** + * @return the {@link android.media.audiopolicy.AudioVolumeGroups} discovered from the + * platform configuration file. + */ + public @NonNull AudioVolumeGroups listAudioVolumeGroups() { + return sAudioVolumeGroups; + } + private void checkAllAliasStreamVolumes() { synchronized (mSettingsLock) { synchronized (VolumeStreamState.class) { @@ -1892,6 +1906,62 @@ public class AudioService extends IAudioService.Stub mStreamStates[stream].mute(index == 0); } + private void enforceModifyAudioRoutingPermission() { + if (mContext.checkCallingPermission( + android.Manifest.permission.MODIFY_AUDIO_ROUTING) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Missing MODIFY_AUDIO_ROUTING permission"); + } + } + + /** @see AudioManager#setVolumeIndexForAttributes(attr, int, int) */ + public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags, + String callingPackage) { + enforceModifyAudioRoutingPermission(); + Preconditions.checkNotNull(attr, "attr must not be null"); + // @todo not hold the caller context, post message + int stream = sAudioProductStrategies.getLegacyStreamTypeForAudioAttributes(attr); + final int device = getDeviceForStream(stream); + + int oldIndex = AudioSystem.getVolumeIndexForAttributes(attr, device); + + AudioSystem.setVolumeIndexForAttributes(attr, index, device); + + final int volumeGroup = sAudioProductStrategies.getVolumeGroupIdForAttributes(attr); + final AudioVolumeGroup avg = sAudioVolumeGroups.getById(volumeGroup); + if (avg == null) { + return; + } + for (final int groupedStream : avg.getLegacyStreamTypes()) { + setStreamVolume(stream, index, flags, callingPackage, callingPackage, + Binder.getCallingUid()); + } + } + + /** @see AudioManager#getVolumeIndexForAttributes(attr) */ + public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { + enforceModifyAudioRoutingPermission(); + Preconditions.checkNotNull(attr, "attr must not be null"); + int stream = sAudioProductStrategies.getLegacyStreamTypeForAudioAttributes(attr); + final int device = getDeviceForStream(stream); + + return AudioSystem.getVolumeIndexForAttributes(attr, device); + } + + /** @see AudioManager#getMaxVolumeIndexForAttributes(attr) */ + public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) { + enforceModifyAudioRoutingPermission(); + Preconditions.checkNotNull(attr, "attr must not be null"); + return AudioSystem.getMaxVolumeIndexForAttributes(attr); + } + + /** @see AudioManager#getMinVolumeIndexForAttributes(attr) */ + public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) { + enforceModifyAudioRoutingPermission(); + Preconditions.checkNotNull(attr, "attr must not be null"); + return AudioSystem.getMinVolumeIndexForAttributes(attr); + } + /** @see AudioManager#setStreamVolume(int, int, int) */ public void setStreamVolume(int streamType, int index, int flags, String callingPackage) { if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {