From 6d69bde308f8ea6c04f54b0b3cb807d310ae8ccb Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Thu, 4 Apr 2019 13:10:13 -0700 Subject: [PATCH 1/4] Replacing AudioProductStrategies with List - Removed AudioProductStrategies and updated usages to work with List - ditributed looping logic to the respective callers Test: built successfully with make and ran on device Bug: 129265140 Change-Id: If95ba9c2418a1fda29590ca1af2d04e7395c2130 --- api/system-current.txt | 18 +- .../android/preference/SeekBarVolumizer.java | 62 +++- .../android_media_AudioProductStrategies.cpp | 24 +- media/java/android/media/AudioAttributes.java | 14 +- media/java/android/media/AudioManager.java | 5 +- media/java/android/media/IAudioService.aidl | 4 +- .../audiopolicy/AudioProductStrategies.aidl | 18 -- .../audiopolicy/AudioProductStrategies.java | 277 ------------------ .../audiopolicy/AudioProductStrategy.java | 91 +++++- .../media/audiopolicy/AudioVolumeGroup.java | 2 +- .../android/server/audio/AudioService.java | 49 +++- 11 files changed, 191 insertions(+), 373 deletions(-) delete mode 100644 media/java/android/media/audiopolicy/AudioProductStrategies.aidl delete mode 100644 media/java/android/media/audiopolicy/AudioProductStrategies.java diff --git a/api/system-current.txt b/api/system-current.txt index 282f6f7491287..648a97d5c0d11 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3497,7 +3497,7 @@ package android.media { method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); method public void clearAudioServerStateCallback(); 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 static java.util.List getAudioProductStrategies(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioVolumeGroups getAudioVolumeGroups(); 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); @@ -3677,22 +3677,6 @@ package android.media.audiopolicy { method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException; } - public final class AudioProductStrategies implements java.lang.Iterable android.os.Parcelable { - ctor public AudioProductStrategies(); - method public int describeContents(); - method @NonNull public android.media.AudioAttributes getAudioAttributesForLegacyStreamType(int); - method @NonNull public android.media.AudioAttributes getAudioAttributesForProductStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); - method @Nullable public android.media.audiopolicy.AudioProductStrategy getById(int); - method public int getLegacyStreamTypeForAudioAttributes(@NonNull android.media.AudioAttributes); - method @Nullable public android.media.audiopolicy.AudioProductStrategy getProductStrategyForAudioAttributes(@NonNull android.media.AudioAttributes); - method public int getVolumeGroupIdForAttributes(@NonNull android.media.AudioAttributes); - method public int getVolumeGroupIdForLegacyStreamType(int); - method @NonNull public java.util.Iterator iterator(); - method public int size(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - } - public final class AudioProductStrategy implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.media.AudioAttributes getAudioAttributes(); diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 847b8e48b2961..aa930c8dcb1ee 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -16,6 +16,7 @@ package android.preference; +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.app.NotificationManager; import android.content.BroadcastReceiver; @@ -27,7 +28,7 @@ import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; -import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioProductStrategy; import android.media.audiopolicy.AudioVolumeGroups; import android.net.Uri; import android.os.Handler; @@ -44,6 +45,7 @@ import android.widget.SeekBar.OnSeekBarChangeListener; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.SomeArgs; +import com.android.internal.util.Preconditions; /** * Turns a {@link SeekBar} into a volume control. @@ -67,7 +69,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private static final int MSG_GROUP_VOLUME_CHANGED = 1; private final Handler mVolumeHandler = new VolumeHandler(); - private final AudioProductStrategies mAudioProductStrategies; private AudioAttributes mAttributes; private int mVolumeGroupId; @@ -161,11 +162,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } mZenMode = mNotificationManager.getZenMode(); - mAudioProductStrategies = mAudioManager.getAudioProductStrategies(); - if (mAudioProductStrategies.size() > 0) { - mVolumeGroupId = mAudioProductStrategies.getVolumeGroupIdForLegacyStreamType( - mStreamType); - mAttributes = mAudioProductStrategies.getAudioAttributesForLegacyStreamType( + if (AudioManager.getAudioProductStrategies().size() > 0) { + mVolumeGroupId = getVolumeGroupIdForLegacyStreamType(mStreamType); + mAttributes = getAudioAttributesForLegacyStreamType( mStreamType); } @@ -190,6 +189,44 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mDefaultUri = defaultUri; } + private int getVolumeGroupIdForLegacyStreamType(int streamType) { + for (final AudioProductStrategy productStrategy : + AudioManager.getAudioProductStrategies()) { + int volumeGroupId = productStrategy.getVolumeGroupIdForLegacyStreamType(streamType); + if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + return volumeGroupId; + } + } + // The default volume group is the one hosted by default product strategy, i.e. + // supporting Default Attributes + return getVolumeGroupIdForAttributesInt(AudioProductStrategy.sDefaultAttributes); + } + + private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) { + Preconditions.checkNotNull(attributes, "attributes must not be null"); + for (final AudioProductStrategy productStrategy : + AudioManager.getAudioProductStrategies()) { + int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes); + if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + return volumeGroupId; + } + } + return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; + } + + private @NonNull AudioAttributes getAudioAttributesForLegacyStreamType(int streamType) { + for (final AudioProductStrategy productStrategy : + AudioManager.getAudioProductStrategies()) { + AudioAttributes aa = productStrategy.getAudioAttributesForLegacyStreamType(streamType); + if (aa != null) { + return aa; + } + } + return new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) + .setUsage(AudioAttributes.USAGE_UNKNOWN).build(); + } + private static boolean isNotificationOrRing(int stream) { return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION; } @@ -329,7 +366,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba postStopSample(); mContext.getContentResolver().unregisterContentObserver(mVolumeObserver); mReceiver.setListening(false); - if (mAudioProductStrategies.size() > 0) { + if (AudioManager.getAudioProductStrategies().size() > 0) { unregisterVolumeGroupCb(); } mSeekBar.setOnSeekBarChangeListener(null); @@ -349,7 +386,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba System.getUriFor(System.VOLUME_SETTINGS_INT[mStreamType]), false, mVolumeObserver); mReceiver.setListening(true); - if (mAudioProductStrategies.size() > 0) { + if (AudioManager.getAudioProductStrategies().size() > 0) { registerVolumeGroupCb(); } } @@ -507,7 +544,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); - if (mAudioProductStrategies.size() == 0) { + if (AudioManager.getAudioProductStrategies().size() == 0) { updateVolumeSlider(streamType, streamValue); } } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { @@ -519,12 +556,11 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); - if (mAudioProductStrategies.size() == 0) { + if (AudioManager.getAudioProductStrategies().size() == 0) { int streamVolume = mAudioManager.getStreamVolume(streamType); updateVolumeSlider(streamType, streamVolume); } else { - int volumeGroup = mAudioProductStrategies.getVolumeGroupIdForLegacyStreamType( - streamType); + int volumeGroup = getVolumeGroupIdForLegacyStreamType(streamType); if (volumeGroup != AudioVolumeGroups.DEFAULT_VOLUME_GROUP && volumeGroup == mVolumeGroupId) { int streamVolume = mAudioManager.getStreamVolume(streamType); diff --git a/core/jni/android_media_AudioProductStrategies.cpp b/core/jni/android_media_AudioProductStrategies.cpp index 822b74a6b9901..17a02b24c6979 100644 --- a/core/jni/android_media_AudioProductStrategies.cpp +++ b/core/jni/android_media_AudioProductStrategies.cpp @@ -39,7 +39,7 @@ using namespace android; // ---------------------------------------------------------------------------- -static const char* const kClassPathName = "android/media/audiopolicy/AudioProductStrategies"; +static const char* const kClassPathName = "android/media/audiopolicy/AudioProductStrategy"; static const char* const kAudioProductStrategyClassPathName = "android/media/audiopolicy/AudioProductStrategy"; @@ -194,34 +194,12 @@ exit: return jStatus; } -static jint -android_media_AudioSystem_getProductStrategyFromAudioAttributes(JNIEnv *env, jobject clazz, - jobject jAudioAttributes) -{ - JNIAudioAttributeHelper::UniqueAaPtr attributes = JNIAudioAttributeHelper::makeUnique(); - jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, - jAudioAttributes, - attributes.get()); - if (jStatus != (jint)AUDIO_JAVA_SUCCESS) { - return jStatus; - } - product_strategy_t psId; - status_t status = AudioSystem::getProductStrategyFromAudioAttributes( - AudioAttributes(*attributes.get()), psId); - if (status != NO_ERROR) { - return nativeToJavaStatus(status); - } - return psId; -} - /* * JNI registration. */ static const JNINativeMethod gMethods[] = { {"native_list_audio_product_strategies", "(Ljava/util/ArrayList;)I", (void *)android_media_AudioSystem_listAudioProductStrategies}, - {"native_get_product_strategies_from_audio_attributes", "(Landroid/media/AudioAttributes;)I", - (void *)android_media_AudioSystem_getProductStrategyFromAudioAttributes}, }; int register_android_media_AudioProductStrategies(JNIEnv *env) diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 9d4bce7b43010..d8640967a30ae 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; -import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioProductStrategy; import android.os.Build; import android.os.Bundle; import android.os.Parcel; @@ -783,9 +783,10 @@ public final class AudioAttributes implements Parcelable { */ @UnsupportedAppUsage public Builder setInternalLegacyStreamType(int streamType) { - final AudioProductStrategies ps = new AudioProductStrategies(); - if (ps.size() > 0) { - AudioAttributes attributes = ps.getAudioAttributesForLegacyStreamType(streamType); + if (AudioProductStrategy.getAudioProductStrategies().size() > 0) { + AudioAttributes attributes = + AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( + streamType); if (attributes != null) { return new Builder(attributes); } @@ -1165,9 +1166,8 @@ public final class AudioAttributes implements Parcelable { AudioSystem.STREAM_MUSIC : AudioSystem.STREAM_TTS; } - final AudioProductStrategies ps = new AudioProductStrategies(); - if (ps.size() > 0) { - return ps.getLegacyStreamTypeForAudioAttributes(aa); + if (AudioProductStrategy.getAudioProductStrategies().size() > 0) { + return AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(aa); } // usage to stream type mapping switch (aa.getUsage()) { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index a5a4092867540..f80c8c61cec98 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -37,7 +37,7 @@ import android.content.Context; import android.content.Intent; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener; -import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioProductStrategy; import android.media.audiopolicy.AudioVolumeGroupChangeHandler; import android.media.audiopolicy.AudioVolumeGroups; import android.media.projection.MediaProjection; @@ -5406,8 +5406,9 @@ public class AudioManager { * {@see android.media.audiopolicy.AudioProductStrategy} objects. */ @SystemApi + @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public @NonNull AudioProductStrategies getAudioProductStrategies() { + public static List getAudioProductStrategies() { final IAudioService service = getService(); try { return service.getAudioProductStrategies(); diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 980cb04598217..36c9b5a9dbb86 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -33,7 +33,7 @@ import android.media.IVolumeController; import android.media.PlayerBase; import android.media.VolumePolicy; import android.media.audiopolicy.AudioPolicyConfig; -import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioProductStrategy; import android.media.audiopolicy.AudioVolumeGroups; import android.media.audiopolicy.IAudioPolicyCallback; import android.media.projection.IMediaProjection; @@ -98,7 +98,7 @@ interface IAudioService { int getLastAudibleStreamVolume(int streamType); - AudioProductStrategies getAudioProductStrategies(); + List getAudioProductStrategies(); void setMicrophoneMute(boolean on, String callingPackage, int userId); diff --git a/media/java/android/media/audiopolicy/AudioProductStrategies.aidl b/media/java/android/media/audiopolicy/AudioProductStrategies.aidl deleted file mode 100644 index bec11bcfab5d5..0000000000000 --- a/media/java/android/media/audiopolicy/AudioProductStrategies.aidl +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2018, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.media.audiopolicy; - -parcelable AudioProductStrategies; diff --git a/media/java/android/media/audiopolicy/AudioProductStrategies.java b/media/java/android/media/audiopolicy/AudioProductStrategies.java deleted file mode 100644 index c305b683f1366..0000000000000 --- a/media/java/android/media/audiopolicy/AudioProductStrategies.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media.audiopolicy; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.media.AudioAttributes; -import android.media.AudioSystem; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import com.android.internal.util.Preconditions; - -import java.util.ArrayList; -import java.util.Iterator; - -/** - * @hide - * A class to encapsulate a collection of {@link AudioProductStrategy}. - * Provides helper functions to easily retrieve the {@link AudioAttributes} for a given product - * strategy or legacy stream type. - */ -@SystemApi -public final class AudioProductStrategies implements Iterable, Parcelable { - - private final ArrayList mAudioProductStrategyList; - - private static final String TAG = "AudioProductStrategies"; - - public AudioProductStrategies() { - ArrayList apsList = new ArrayList(); - int status = native_list_audio_product_strategies(apsList); - if (status != AudioSystem.SUCCESS) { - Log.w(TAG, ": createAudioProductStrategies failed"); - } - mAudioProductStrategyList = apsList; - } - - private AudioProductStrategies(ArrayList audioProductStrategy) { - mAudioProductStrategyList = audioProductStrategy; - } - - /** - * @hide - * @return number of {@link AudioProductStrategy} objects - */ - @SystemApi - public int size() { - return mAudioProductStrategyList.size(); - } - - /** - * @hide - * @return the matching {@link AudioProductStrategy} objects with the given id, - * null object if not found. - */ - @SystemApi - public @Nullable AudioProductStrategy getById(int productStrategyId) { - for (final AudioProductStrategy avg : this) { - if (avg.getId() == productStrategyId) { - return avg; - } - } - Log.e(TAG, ": invalid product strategy id: " + productStrategyId + " requested"); - return null; - } - - /** - * Returns an {@link Iterator} - */ - @Override - public @NonNull Iterator iterator() { - return mAudioProductStrategyList.iterator(); - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - AudioProductStrategies that = (AudioProductStrategies) o; - - return mAudioProductStrategyList.equals(that.mAudioProductStrategyList); - } - - /** - * @hide - * @param aps {@link AudioProductStrategy} (which is the generalisation of Car Audio Usage / - * legacy routing_strategy linked to {@link AudioAttributes#getUsage()} ) - * @return the {@link AudioAttributes} relevant for the given product strategy. - * If none is found, it builds the default attributes. - * TODO: shall the helper collection be able to identify the platform default? - */ - @SystemApi - @NonNull - public AudioAttributes getAudioAttributesForProductStrategy(@NonNull AudioProductStrategy aps) { - Preconditions.checkNotNull(aps, "AudioProductStrategy must not be null"); - for (final AudioProductStrategy audioProductStrategy : this) { - if (audioProductStrategy.equals(aps)) { - return audioProductStrategy.getAudioAttributes(); - } - } - return new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) - .setUsage(AudioAttributes.USAGE_UNKNOWN).build(); - } - - /** - * @hide - * @param streamType legacy stream type used for volume operation only - * @return the {@link AudioAttributes} relevant for the given streamType. - * If none is found, it builds the default attributes. - */ - @SystemApi - public @NonNull AudioAttributes getAudioAttributesForLegacyStreamType(int streamType) { - for (final AudioProductStrategy productStrategy : this) { - AudioAttributes aa = productStrategy.getAudioAttributesForLegacyStreamType(streamType); - if (aa != null) { - return aa; - } - } - return new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) - .setUsage(AudioAttributes.USAGE_UNKNOWN).build(); - } - - /** - * @hide - * @param aa the {@link AudioAttributes} for which stream type is requested - * @return the legacy stream type relevant for the given {@link AudioAttributes}. - * If the product strategy is not associated to any stream, it returns - * {@link AudioSystem#STREAM_MUSIC}. - * If no product strategy supports the stream type, it returns - * {@link AudioSystem#STREAM_MUSIC}. - */ - @SystemApi - public int getLegacyStreamTypeForAudioAttributes(@NonNull AudioAttributes aa) { - Preconditions.checkNotNull(aa, "AudioAttributes must not be null"); - for (final AudioProductStrategy productStrategy : this) { - if (productStrategy.supportsAudioAttributes(aa)) { - int streamType = productStrategy.getLegacyStreamTypeForAudioAttributes(aa); - if (streamType == AudioSystem.STREAM_DEFAULT) { - Log.w(TAG, "Attributes " + aa.toString() + " ported by strategy " - + productStrategy.name() + " has no stream type associated, " - + "DO NOT USE STREAM TO CONTROL THE VOLUME"); - return AudioSystem.STREAM_MUSIC; - } - return streamType; - } - } - return AudioSystem.STREAM_MUSIC; - } - - /** - * @hide - * @param aa the {@link AudioAttributes} to be considered - * @return {@link AudioProductStrategy} supporting the given {@link AudioAttributes}. - * null is returned if no match with given attributes. - */ - @SystemApi - @Nullable - public AudioProductStrategy getProductStrategyForAudioAttributes(@NonNull AudioAttributes aa) { - Preconditions.checkNotNull(aa, "attributes must not be null"); - int productStrategyId = native_get_product_strategies_from_audio_attributes(aa); - if (productStrategyId < 0) { - Log.w(TAG, "no strategy found for Attributes " + aa.toString()); - return null; - } - return getById(productStrategyId); - } - - /** - * @hide - * @param attributes the {@link AudioAttributes} to be considered - * @return volume group associated to the given {@link AudioAttributes}. - * If no group supports the given {@link AudioAttributes}, it returns the volume group - * for the default attributes. - * If no group supports the default attributes, it returns {@link #DEFAULT_VOLUME_GROUP} - */ - @SystemApi - public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) { - Preconditions.checkNotNull(attributes, "attributes must not be null"); - int volumeGroupId = getVolumeGroupIdForAttributesInt(attributes); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { - return volumeGroupId; - } - // The default volume group is the one hosted by default product strategy, i.e. - // supporting Default Attributes - return getVolumeGroupIdForAttributesInt(AudioProductStrategy.sDefaultAttributes); - } - - /** - * @hide - * @param streamType to be considered - * @return volume group associated to the given stream type. - */ - @SystemApi - public int getVolumeGroupIdForLegacyStreamType(int streamType) { - for (final AudioProductStrategy productStrategy : this) { - int volumeGroupId = productStrategy.getVolumeGroupIdForLegacyStreamType(streamType); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { - return volumeGroupId; - } - } - // The default volume group is the one hosted by default product strategy, i.e. - // supporting Default Attributes - return getVolumeGroupIdForAttributesInt(AudioProductStrategy.sDefaultAttributes); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(size()); - for (final AudioProductStrategy productStrategy : this) { - productStrategy.writeToParcel(dest, flags); - } - } - - /** - * @param attributes to be considered - * @return volume group associated to the given {@link AudioAttributes}. - */ - private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) { - Preconditions.checkNotNull(attributes, "attributes must not be null"); - for (final AudioProductStrategy productStrategy : this) { - int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { - return volumeGroupId; - } - } - return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public AudioProductStrategies createFromParcel(@NonNull Parcel in) { - ArrayList apsList = new ArrayList(); - int size = in.readInt(); - for (int index = 0; index < size; index++) { - apsList.add(AudioProductStrategy.CREATOR.createFromParcel(in)); - } - return new AudioProductStrategies(apsList); - } - - @Override - public @NonNull AudioProductStrategies[] newArray(int size) { - return new AudioProductStrategies[size]; - } - }; - - private static native int native_list_audio_product_strategies( - ArrayList strategies); - - private static native int native_get_product_strategies_from_audio_attributes( - AudioAttributes attributes); -} diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java index c1c255f68996a..578186353402e 100644 --- a/media/java/android/media/audiopolicy/AudioProductStrategy.java +++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java @@ -25,9 +25,14 @@ import android.media.MediaRecorder; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; +import java.util.ArrayList; +import java.util.List; + /** * @hide * A class to encapsulate a collection of attributes associated to a given product strategy @@ -41,6 +46,9 @@ public final class AudioProductStrategy implements Parcelable { */ public static final int DEFAULT_GROUP = -1; + + private static final String TAG = "AudioProductStrategy"; + private final AudioAttributesGroup[] mAudioAttributesGroups; private final String mName; /** @@ -51,6 +59,86 @@ public final class AudioProductStrategy implements Parcelable { */ private int mId; + private static final Object sLock = new Object(); + + @GuardedBy("sLock") + private static List sAudioProductStrategies; + + /** + * @hide + * @return the list of AudioProductStrategy discovered from platform configuration file. + */ + @NonNull + public static List getAudioProductStrategies() { + if (sAudioProductStrategies == null) { + synchronized (sLock) { + if (sAudioProductStrategies == null) { + sAudioProductStrategies = initializeAudioProductStrategies(); + } + } + } + return sAudioProductStrategies; + } + + /** + * @hide + * @param streamType to match against AudioProductStrategy + * @return the AudioAttributes for the first strategy found with the associated stream type + * If no match is found, returns AudioAttributes with unknown content_type and usage + */ + @NonNull + public static AudioAttributes getAudioAttributesForStrategyWithLegacyStreamType( + int streamType) { + for (final AudioProductStrategy productStrategy : + AudioProductStrategy.getAudioProductStrategies()) { + AudioAttributes aa = productStrategy.getAudioAttributesForLegacyStreamType(streamType); + if (aa != null) { + return aa; + } + } + return new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) + .setUsage(AudioAttributes.USAGE_UNKNOWN).build(); + } + + /** + * @hide + * @param audioAttributes to identify AudioProductStrategy with + * @return legacy stream type associated with matched AudioProductStrategy + * Defaults to STREAM_MUSIC if no match is found, or if matches is STREAM_DEFAULT + */ + public static int getLegacyStreamTypeForStrategyWithAudioAttributes( + @NonNull AudioAttributes audioAttributes) { + Preconditions.checkNotNull(audioAttributes, "AudioAttributes must not be null"); + for (final AudioProductStrategy productStrategy : + AudioProductStrategy.getAudioProductStrategies()) { + if (productStrategy.supportsAudioAttributes(audioAttributes)) { + int streamType = productStrategy.getLegacyStreamTypeForAudioAttributes( + audioAttributes); + if (streamType == AudioSystem.STREAM_DEFAULT) { + Log.w(TAG, "Attributes " + audioAttributes.toString() + " ported by strategy " + + productStrategy.name() + " has no stream type associated, " + + "DO NOT USE STREAM TO CONTROL THE VOLUME"); + return AudioSystem.STREAM_MUSIC; + } + return streamType; + } + } + return AudioSystem.STREAM_MUSIC; + } + + private static List initializeAudioProductStrategies() { + ArrayList apsList = new ArrayList(); + int status = native_list_audio_product_strategies(apsList); + if (status != AudioSystem.SUCCESS) { + Log.w(TAG, ": initializeAudioProductStrategies failed"); + } + return apsList; + } + + private static native int native_list_audio_product_strategies( + ArrayList strategies); + @Override public boolean equals(@Nullable Object o) { if (this == o) return true; @@ -200,7 +288,8 @@ public final class AudioProductStrategy implements Parcelable { } } - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = + @NonNull + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public AudioProductStrategy createFromParcel(@NonNull Parcel in) { diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroup.java b/media/java/android/media/audiopolicy/AudioVolumeGroup.java index b60947f13c1fc..964de95932c52 100644 --- a/media/java/android/media/audiopolicy/AudioVolumeGroup.java +++ b/media/java/android/media/audiopolicy/AudioVolumeGroup.java @@ -49,7 +49,7 @@ public final class AudioVolumeGroup implements Parcelable { /** * @param name of the volume group * @param id of the volume group - * @param followers {@link AudioProductStrategies} strategy following this volume group + * @param legacyStreamTypes of volume group */ AudioVolumeGroup(@NonNull String name, int id, @NonNull AudioAttributes[] audioAttributes, diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d58888a7c67b1..832cd877d0ade 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -90,7 +90,7 @@ import android.media.audiofx.AudioEffect; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicyConfig; -import android.media.audiopolicy.AudioProductStrategies; +import android.media.audiopolicy.AudioProductStrategy; import android.media.audiopolicy.AudioVolumeGroup; import android.media.audiopolicy.AudioVolumeGroups; import android.media.audiopolicy.IAudioPolicyCallback; @@ -281,8 +281,6 @@ public class AudioService extends IAudioService.Stub private SettingsObserver mSettingsObserver; - /** @see AudioProductStrategies */ - private static AudioProductStrategies sAudioProductStrategies; /** @see AudioVolumeGroups */ private static AudioVolumeGroups sAudioVolumeGroups; @@ -636,19 +634,19 @@ public class AudioService extends IAudioService.Stub mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator(); - sAudioProductStrategies = new AudioProductStrategies(); sAudioVolumeGroups = new AudioVolumeGroups(); // Initialize volume // Priority 1 - Android Property // Priority 2 - Audio Policy Service // Priority 3 - Default Value - if (sAudioProductStrategies.size() > 0) { + if (AudioProductStrategy.getAudioProductStrategies().size() > 0) { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { AudioAttributes attr = - sAudioProductStrategies.getAudioAttributesForLegacyStreamType(streamType); + AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( + streamType); int maxVolume = AudioSystem.getMaxVolumeIndexForAttributes(attr); if (maxVolume != -1) { MAX_STREAM_VOLUME[streamType] = maxVolume; @@ -1023,11 +1021,12 @@ public class AudioService extends IAudioService.Stub } /** - * @return the {@link android.media.audiopolicy.AudioProductStrategies} discovered from the + * @return the {@link android.media.audiopolicy.AudioProductStrategy} discovered from the * platform configuration file. */ - public @NonNull AudioProductStrategies getAudioProductStrategies() { - return sAudioProductStrategies; + @NonNull + public List getAudioProductStrategies() { + return AudioProductStrategy.getAudioProductStrategies(); } /** @@ -1947,14 +1946,14 @@ public class AudioService extends IAudioService.Stub enforceModifyAudioRoutingPermission(); Preconditions.checkNotNull(attr, "attr must not be null"); // @todo not hold the caller context, post message - int stream = sAudioProductStrategies.getLegacyStreamTypeForAudioAttributes(attr); + int stream = AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(attr); final int device = getDeviceForStream(stream); int oldIndex = AudioSystem.getVolumeIndexForAttributes(attr, device); AudioSystem.setVolumeIndexForAttributes(attr, index, device); - final int volumeGroup = sAudioProductStrategies.getVolumeGroupIdForAttributes(attr); + final int volumeGroup = getVolumeGroupIdForAttributes(attr); final AudioVolumeGroup avg = sAudioVolumeGroups.getById(volumeGroup); if (avg == null) { return; @@ -1969,7 +1968,7 @@ public class AudioService extends IAudioService.Stub public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { enforceModifyAudioRoutingPermission(); Preconditions.checkNotNull(attr, "attr must not be null"); - int stream = sAudioProductStrategies.getLegacyStreamTypeForAudioAttributes(attr); + int stream = AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(attr); final int device = getDeviceForStream(stream); return AudioSystem.getVolumeIndexForAttributes(attr, device); @@ -2144,6 +2143,32 @@ public class AudioService extends IAudioService.Stub sendVolumeUpdate(streamType, oldIndex, index, flags); } + + + private int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) { + Preconditions.checkNotNull(attributes, "attributes must not be null"); + int volumeGroupId = getVolumeGroupIdForAttributesInt(attributes); + if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + return volumeGroupId; + } + // The default volume group is the one hosted by default product strategy, i.e. + // supporting Default Attributes + return getVolumeGroupIdForAttributesInt(AudioProductStrategy.sDefaultAttributes); + } + + private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) { + Preconditions.checkNotNull(attributes, "attributes must not be null"); + for (final AudioProductStrategy productStrategy : + AudioProductStrategy.getAudioProductStrategies()) { + int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes); + if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + return volumeGroupId; + } + } + return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; + } + + // No ringer or zen muted stream volumes can be changed unless it'll exit dnd private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) { switch (mNm.getZenMode()) { From 8e8e9ce626f9234ec142e356c4010f59595bfebf Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Thu, 4 Apr 2019 13:12:39 -0700 Subject: [PATCH 2/4] Removing name getter from AudioProductStrategy Test: ran make and flashed onto device Bug: 129265140 Change-Id: Ia6dad73e954f45b30cab970386e8fd3a66416ede --- api/system-current.txt | 1 - .../media/audiopolicy/AudioProductStrategy.java | 14 ++------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 648a97d5c0d11..d651985b1f0d8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3681,7 +3681,6 @@ package android.media.audiopolicy { method public int describeContents(); method @NonNull public android.media.AudioAttributes getAudioAttributes(); method public int getId(); - method @NonNull public String name(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; } diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java index 578186353402e..eed4502364747 100644 --- a/media/java/android/media/audiopolicy/AudioProductStrategy.java +++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java @@ -117,7 +117,7 @@ public final class AudioProductStrategy implements Parcelable { audioAttributes); if (streamType == AudioSystem.STREAM_DEFAULT) { Log.w(TAG, "Attributes " + audioAttributes.toString() + " ported by strategy " - + productStrategy.name() + " has no stream type associated, " + + productStrategy.getId() + " has no stream type associated, " + "DO NOT USE STREAM TO CONTROL THE VOLUME"); return AudioSystem.STREAM_MUSIC; } @@ -153,8 +153,7 @@ public final class AudioProductStrategy implements Parcelable { /** * @param name of the product strategy * @param id of the product strategy - * @param audioAttributes {@link AudioAttributes} associated to the given product strategy - * @param legacyStreamTypes associated to the given product strategy. + * @param aag {@link AudioAttributesGroup} associated to the given product strategy */ private AudioProductStrategy(@NonNull String name, int id, @NonNull AudioAttributesGroup[] aag) { @@ -165,15 +164,6 @@ public final class AudioProductStrategy implements Parcelable { mAudioAttributesGroups = aag; } - /** - * @hide - * @return human-readable name of this product strategy, which is similar to a usage - */ - @SystemApi - public @NonNull String name() { - return mName; - } - /** * @hide * @return the product strategy ID (which is the generalisation of Car Audio Usage / legacy From 3c562e2474679b5e01816e362e5e6367c164cd01 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Thu, 4 Apr 2019 13:13:36 -0700 Subject: [PATCH 3/4] Cleaning up SeekBarVolumizer Bug: 129265140 Test: Built with make and ran on device Change-Id: Ifcd9a24cd768249f1b6ec5ad7e2361bcacfb9a4d --- .../android/preference/SeekBarVolumizer.java | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index aa930c8dcb1ee..f176dc3485f35 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -45,7 +45,6 @@ import android.widget.SeekBar.OnSeekBarChangeListener; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.SomeArgs; -import com.android.internal.util.Preconditions; /** * Turns a {@link SeekBar} into a volume control. @@ -162,7 +161,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } mZenMode = mNotificationManager.getZenMode(); - if (AudioManager.getAudioProductStrategies().size() > 0) { + if (hasAudioProductStrategies()) { mVolumeGroupId = getVolumeGroupIdForLegacyStreamType(mStreamType); mAttributes = getAudioAttributesForLegacyStreamType( mStreamType); @@ -189,6 +188,10 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mDefaultUri = defaultUri; } + private boolean hasAudioProductStrategies() { + return AudioManager.getAudioProductStrategies().size() > 0; + } + private int getVolumeGroupIdForLegacyStreamType(int streamType) { for (final AudioProductStrategy productStrategy : AudioManager.getAudioProductStrategies()) { @@ -197,21 +200,13 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba return volumeGroupId; } } - // The default volume group is the one hosted by default product strategy, i.e. - // supporting Default Attributes - return getVolumeGroupIdForAttributesInt(AudioProductStrategy.sDefaultAttributes); - } - private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) { - Preconditions.checkNotNull(attributes, "attributes must not be null"); - for (final AudioProductStrategy productStrategy : - AudioManager.getAudioProductStrategies()) { - int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { - return volumeGroupId; - } - } - return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; + return AudioManager.getAudioProductStrategies().stream() + .map(strategy -> strategy.getVolumeGroupIdForAudioAttributes( + AudioProductStrategy.sDefaultAttributes)) + .filter(volumeGroupId -> volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) + .findFirst() + .orElse(AudioVolumeGroups.DEFAULT_VOLUME_GROUP); } private @NonNull AudioAttributes getAudioAttributesForLegacyStreamType(int streamType) { @@ -366,7 +361,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba postStopSample(); mContext.getContentResolver().unregisterContentObserver(mVolumeObserver); mReceiver.setListening(false); - if (AudioManager.getAudioProductStrategies().size() > 0) { + if (hasAudioProductStrategies()) { unregisterVolumeGroupCb(); } mSeekBar.setOnSeekBarChangeListener(null); @@ -386,7 +381,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba System.getUriFor(System.VOLUME_SETTINGS_INT[mStreamType]), false, mVolumeObserver); mReceiver.setListening(true); - if (AudioManager.getAudioProductStrategies().size() > 0) { + if (hasAudioProductStrategies()) { registerVolumeGroupCb(); } } @@ -544,7 +539,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); - if (AudioManager.getAudioProductStrategies().size() == 0) { + if (hasAudioProductStrategies()) { updateVolumeSlider(streamType, streamValue); } } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { @@ -556,7 +551,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); - if (AudioManager.getAudioProductStrategies().size() == 0) { + if (hasAudioProductStrategies()) { int streamVolume = mAudioManager.getStreamVolume(streamType); updateVolumeSlider(streamType, streamVolume); } else { From ebd6aaa4b0f7b302e9733dd5a801b01bc450af4f Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Thu, 4 Apr 2019 13:14:21 -0700 Subject: [PATCH 4/4] Replacing AudioVolumeGroups with List Bug: 129262395 Test: Built and ran on device Change-Id: I838296ead584b85be50028c410b9a2d0ba3b0398 --- api/system-current.txt | 12 +- .../android/preference/SeekBarVolumizer.java | 16 +-- core/jni/android_media_AudioVolumeGroups.cpp | 2 +- media/java/android/media/AudioManager.java | 11 +- media/java/android/media/IAudioService.aidl | 4 +- .../audiopolicy/AudioProductStrategy.java | 8 +- .../media/audiopolicy/AudioVolumeGroup.java | 43 ++++++ .../media/audiopolicy/AudioVolumeGroups.aidl | 18 --- .../media/audiopolicy/AudioVolumeGroups.java | 135 ------------------ .../android/server/audio/AudioService.java | 33 +++-- 10 files changed, 85 insertions(+), 197 deletions(-) delete mode 100644 media/java/android/media/audiopolicy/AudioVolumeGroups.aidl delete mode 100644 media/java/android/media/audiopolicy/AudioVolumeGroups.java diff --git a/api/system-current.txt b/api/system-current.txt index d651985b1f0d8..4eef9aaeea865 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3498,7 +3498,7 @@ package android.media { method public void clearAudioServerStateCallback(); 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 static java.util.List getAudioProductStrategies(); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioVolumeGroups getAudioVolumeGroups(); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List getAudioVolumeGroups(); 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); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); @@ -3693,16 +3693,6 @@ package android.media.audiopolicy { method @NonNull public String name(); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; - } - - public final class AudioVolumeGroups implements java.lang.Iterable android.os.Parcelable { - ctor public AudioVolumeGroups(); - method public int describeContents(); - method @Nullable public android.media.audiopolicy.AudioVolumeGroup getById(int); - method @NonNull public java.util.Iterator iterator(); - method public int size(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; field public static final int DEFAULT_VOLUME_GROUP = -1; // 0xffffffff } diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index f176dc3485f35..02f99258395c6 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -29,7 +29,7 @@ import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.media.audiopolicy.AudioProductStrategy; -import android.media.audiopolicy.AudioVolumeGroups; +import android.media.audiopolicy.AudioVolumeGroup; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; @@ -196,7 +196,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba for (final AudioProductStrategy productStrategy : AudioManager.getAudioProductStrategies()) { int volumeGroupId = productStrategy.getVolumeGroupIdForLegacyStreamType(streamType); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { return volumeGroupId; } } @@ -204,9 +204,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba return AudioManager.getAudioProductStrategies().stream() .map(strategy -> strategy.getVolumeGroupIdForAudioAttributes( AudioProductStrategy.sDefaultAttributes)) - .filter(volumeGroupId -> volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) + .filter(volumeGroupId -> volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) .findFirst() - .orElse(AudioVolumeGroups.DEFAULT_VOLUME_GROUP); + .orElse(AudioVolumeGroup.DEFAULT_VOLUME_GROUP); } private @NonNull AudioAttributes getAudioAttributesForLegacyStreamType(int streamType) { @@ -556,7 +556,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba updateVolumeSlider(streamType, streamVolume); } else { int volumeGroup = getVolumeGroupIdForLegacyStreamType(streamType); - if (volumeGroup != AudioVolumeGroups.DEFAULT_VOLUME_GROUP + if (volumeGroup != AudioVolumeGroup.DEFAULT_VOLUME_GROUP && volumeGroup == mVolumeGroupId) { int streamVolume = mAudioManager.getStreamVolume(streamType); updateVolumeSlider(streamType, streamVolume); @@ -589,14 +589,14 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } private void registerVolumeGroupCb() { - if (mVolumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + if (mVolumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { mAudioManager.registerVolumeGroupCallback(Runnable::run, mVolumeGroupCallback); mLastProgress = mAudioManager.getVolumeIndexForAttributes(mAttributes); } } private void unregisterVolumeGroupCb() { - if (mVolumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + if (mVolumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { mAudioManager.unregisterVolumeGroupCallback(mVolumeGroupCallback); } } @@ -609,7 +609,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba case MSG_GROUP_VOLUME_CHANGED: int group = (int) args.arg1; if (mVolumeGroupId != group - || mVolumeGroupId == AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + || mVolumeGroupId == AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { return; } updateSlider(); diff --git a/core/jni/android_media_AudioVolumeGroups.cpp b/core/jni/android_media_AudioVolumeGroups.cpp index 64f0c1e33e1c3..7098451901c42 100644 --- a/core/jni/android_media_AudioVolumeGroups.cpp +++ b/core/jni/android_media_AudioVolumeGroups.cpp @@ -39,7 +39,7 @@ using namespace android; // ---------------------------------------------------------------------------- -static const char* const kClassPathName = "android/media/audiopolicy/AudioVolumeGroups"; +static const char* const kClassPathName = "android/media/audiopolicy/AudioVolumeGroup"; static const char* const kAudioVolumeGroupClassPathName = "android/media/audiopolicy/AudioVolumeGroup"; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index f80c8c61cec98..d5eee6308ae09 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -38,8 +38,8 @@ import android.content.Intent; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener; import android.media.audiopolicy.AudioProductStrategy; +import android.media.audiopolicy.AudioVolumeGroup; import android.media.audiopolicy.AudioVolumeGroupChangeHandler; -import android.media.audiopolicy.AudioVolumeGroups; import android.media.projection.MediaProjection; import android.media.session.MediaController; import android.media.session.MediaSession; @@ -5422,15 +5422,16 @@ public class AudioManager { * Introspection API to retrieve audio volume groups. * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of * audio volume groups. - * @return a (possibly zero-length) array of - * {@see android.media.audiopolicy.AudioVolumeGroups} objects. + * @return a (possibly zero-length) List of + * {@see android.media.audiopolicy.AudioVolumeGroup} objects. */ @SystemApi + @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public @NonNull AudioVolumeGroups getAudioVolumeGroups() { + public static List getAudioVolumeGroups() { final IAudioService service = getService(); try { - return service.listAudioVolumeGroups(); + return service.getAudioVolumeGroups(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 36c9b5a9dbb86..eddbee46252e4 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -34,7 +34,7 @@ import android.media.PlayerBase; import android.media.VolumePolicy; import android.media.audiopolicy.AudioPolicyConfig; import android.media.audiopolicy.AudioProductStrategy; -import android.media.audiopolicy.AudioVolumeGroups; +import android.media.audiopolicy.AudioVolumeGroup; import android.media.audiopolicy.IAudioPolicyCallback; import android.media.projection.IMediaProjection; import android.net.Uri; @@ -86,7 +86,7 @@ interface IAudioService { @UnsupportedAppUsage int getStreamMaxVolume(int streamType); - AudioVolumeGroups listAudioVolumeGroups(); + List getAudioVolumeGroups(); void setVolumeIndexForAttributes(in AudioAttributes aa, int index, int flags, String callingPackage); diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java index eed4502364747..9ac9411370ab2 100644 --- a/media/java/android/media/audiopolicy/AudioProductStrategy.java +++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java @@ -236,7 +236,7 @@ public final class AudioProductStrategy implements Parcelable { * @hide * @param streamType legacy stream type used for volume operation only * @return the volume group id relevant for the given streamType. - * If none is found, {@link AudioVolumeGroups#DEFAULT_VOLUME_GROUP} is returned. + * If none is found, {@link AudioVolumeGroup#DEFAULT_VOLUME_GROUP} is returned. */ public int getVolumeGroupIdForLegacyStreamType(int streamType) { for (final AudioAttributesGroup aag : mAudioAttributesGroups) { @@ -244,14 +244,14 @@ public final class AudioProductStrategy implements Parcelable { return aag.getVolumeGroupId(); } } - return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; + return AudioVolumeGroup.DEFAULT_VOLUME_GROUP; } /** * @hide * @param aa the {@link AudioAttributes} to be considered * @return the volume group id associated with the given audio attributes if found, - * {@link AudioVolumeGroups#DEFAULT_VOLUME_GROUP} otherwise. + * {@link AudioVolumeGroup#DEFAULT_VOLUME_GROUP} otherwise. */ public int getVolumeGroupIdForAudioAttributes(@NonNull AudioAttributes aa) { Preconditions.checkNotNull(aa, "AudioAttributes must not be null"); @@ -260,7 +260,7 @@ public final class AudioProductStrategy implements Parcelable { return aag.getVolumeGroupId(); } } - return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; + return AudioVolumeGroup.DEFAULT_VOLUME_GROUP; } @Override diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroup.java b/media/java/android/media/audiopolicy/AudioVolumeGroup.java index 964de95932c52..79be922144556 100644 --- a/media/java/android/media/audiopolicy/AudioVolumeGroup.java +++ b/media/java/android/media/audiopolicy/AudioVolumeGroup.java @@ -19,11 +19,15 @@ package android.media.audiopolicy; import android.annotation.NonNull; import android.annotation.SystemApi; import android.media.AudioAttributes; +import android.media.AudioSystem; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -34,6 +38,12 @@ import java.util.List; */ @SystemApi public final class AudioVolumeGroup implements Parcelable { + private static final String TAG = "AudioVolumeGroup"; + /** + * Volume group value to use when introspection API fails. + */ + public static final int DEFAULT_VOLUME_GROUP = -1; + /** * Unique identifier of a volume group. */ @@ -46,6 +56,39 @@ public final class AudioVolumeGroup implements Parcelable { private final AudioAttributes[] mAudioAttributes; private int[] mLegacyStreamTypes; + private static final Object sLock = new Object(); + + @GuardedBy("sLock") + private static List sAudioVolumeGroups; + + /** + * @hide + * @return the List of AudioVolumeGroup discovered from platform configuration file. + */ + @NonNull + public static List getAudioVolumeGroups() { + if (sAudioVolumeGroups == null) { + synchronized (sLock) { + if (sAudioVolumeGroups == null) { + sAudioVolumeGroups = initializeAudioVolumeGroups(); + } + } + } + return sAudioVolumeGroups; + } + + private static List initializeAudioVolumeGroups() { + ArrayList avgList = new ArrayList<>(); + int status = native_list_audio_volume_groups(avgList); + if (status != AudioSystem.SUCCESS) { + Log.w(TAG, ": listAudioVolumeGroups failed"); + } + return avgList; + } + + private static native int native_list_audio_volume_groups( + ArrayList groups); + /** * @param name of the volume group * @param id of the volume group diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroups.aidl b/media/java/android/media/audiopolicy/AudioVolumeGroups.aidl deleted file mode 100644 index 918cac39f19ac..0000000000000 --- a/media/java/android/media/audiopolicy/AudioVolumeGroups.aidl +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2018, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.media.audiopolicy; - -parcelable AudioVolumeGroups; diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroups.java b/media/java/android/media/audiopolicy/AudioVolumeGroups.java deleted file mode 100644 index 2e56f846e5748..0000000000000 --- a/media/java/android/media/audiopolicy/AudioVolumeGroups.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media.audiopolicy; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.media.AudioSystem; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -import com.android.internal.util.Preconditions; - -import java.util.ArrayList; -import java.util.Iterator; - -/** - * @hide - * A class to encapsulate a collection of {@link AudioVolumeGroup}. - */ -@SystemApi -public final class AudioVolumeGroups implements Iterable, Parcelable { - - private final ArrayList mAudioVolumeGroupList; - - private static final String TAG = "AudioVolumeGroups"; - - /** - * Volume group value to use when introspection API fails. - */ - public static final int DEFAULT_VOLUME_GROUP = -1; - - public AudioVolumeGroups() { - ArrayList avgList = new ArrayList(); - int status = native_list_audio_volume_groups(avgList); - if (status != AudioSystem.SUCCESS) { - Log.w(TAG, ": listAudioVolumeGroups failed"); - } - mAudioVolumeGroupList = avgList; - } - - private AudioVolumeGroups(@NonNull ArrayList audioVolumeGroupList) { - Preconditions.checkNotNull(audioVolumeGroupList, "audioVolumeGroupList must not be null"); - mAudioVolumeGroupList = audioVolumeGroupList; - } - - /** - * @return number of {@link AudioProductStrategy} objects - */ - public int size() { - return mAudioVolumeGroupList.size(); - } - - /** - * Returns an {@link Iterator} - */ - @Override - public @NonNull Iterator iterator() { - return mAudioVolumeGroupList.iterator(); - } - - @Override - public boolean equals(@NonNull Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - AudioVolumeGroups that = (AudioVolumeGroups) o; - - return mAudioVolumeGroupList.equals(that.mAudioVolumeGroupList); - } - - /** - * @return the matching {@link AudioVolumeGroup} objects with the given id, - * null object if not found. - */ - public @Nullable AudioVolumeGroup getById(int volumeGroupId) { - for (final AudioVolumeGroup avg : this) { - if (avg.getId() == volumeGroupId) { - return avg; - } - } - Log.e(TAG, ": invalid volume group id: " + volumeGroupId + " requested"); - return null; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(size()); - for (final AudioVolumeGroup volumeGroup : this) { - volumeGroup.writeToParcel(dest, flags); - } - } - - private static native int native_list_audio_volume_groups( - ArrayList groups); - - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public @NonNull AudioVolumeGroups createFromParcel(@NonNull Parcel in) { - Preconditions.checkNotNull(in, "in Parcel must not be null"); - ArrayList avgList = new ArrayList(); - int size = in.readInt(); - for (int index = 0; index < size; index++) { - avgList.add(AudioVolumeGroup.CREATOR.createFromParcel(in)); - } - return new AudioVolumeGroups(avgList); - } - - @Override - public @NonNull AudioVolumeGroups[] newArray(int size) { - return new AudioVolumeGroups[size]; - } - }; -} diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 832cd877d0ade..77472ed288c3a 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -92,7 +92,6 @@ import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicyConfig; import android.media.audiopolicy.AudioProductStrategy; 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; @@ -281,9 +280,6 @@ public class AudioService extends IAudioService.Stub private SettingsObserver mSettingsObserver; - /** @see AudioVolumeGroups */ - private static AudioVolumeGroups sAudioVolumeGroups; - private int mMode = AudioSystem.MODE_NORMAL; // protects mRingerMode private final Object mSettingsLock = new Object(); @@ -634,8 +630,6 @@ public class AudioService extends IAudioService.Stub mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator(); - sAudioVolumeGroups = new AudioVolumeGroups(); - // Initialize volume // Priority 1 - Android Property // Priority 2 - Audio Policy Service @@ -1030,11 +1024,12 @@ public class AudioService extends IAudioService.Stub } /** - * @return the {@link android.media.audiopolicy.AudioVolumeGroups} discovered from the + * @return the List of {@link android.media.audiopolicy.AudioVolumeGroup} discovered from the * platform configuration file. */ - public @NonNull AudioVolumeGroups listAudioVolumeGroups() { - return sAudioVolumeGroups; + @NonNull + public List getAudioVolumeGroups() { + return AudioVolumeGroup.getAudioVolumeGroups(); } private void checkAllAliasStreamVolumes() { @@ -1954,7 +1949,7 @@ public class AudioService extends IAudioService.Stub AudioSystem.setVolumeIndexForAttributes(attr, index, device); final int volumeGroup = getVolumeGroupIdForAttributes(attr); - final AudioVolumeGroup avg = sAudioVolumeGroups.getById(volumeGroup); + final AudioVolumeGroup avg = getAudioVolumeGroupById(volumeGroup); if (avg == null) { return; } @@ -1964,6 +1959,18 @@ public class AudioService extends IAudioService.Stub } } + @Nullable + private AudioVolumeGroup getAudioVolumeGroupById(int volumeGroupId) { + for (final AudioVolumeGroup avg : AudioVolumeGroup.getAudioVolumeGroups()) { + if (avg.getId() == volumeGroupId) { + return avg; + } + } + + Log.e(TAG, ": invalid volume group id: " + volumeGroupId + " requested"); + return null; + } + /** @see AudioManager#getVolumeIndexForAttributes(attr) */ public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { enforceModifyAudioRoutingPermission(); @@ -2148,7 +2155,7 @@ public class AudioService extends IAudioService.Stub private int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) { Preconditions.checkNotNull(attributes, "attributes must not be null"); int volumeGroupId = getVolumeGroupIdForAttributesInt(attributes); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { return volumeGroupId; } // The default volume group is the one hosted by default product strategy, i.e. @@ -2161,11 +2168,11 @@ public class AudioService extends IAudioService.Stub for (final AudioProductStrategy productStrategy : AudioProductStrategy.getAudioProductStrategies()) { int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes); - if (volumeGroupId != AudioVolumeGroups.DEFAULT_VOLUME_GROUP) { + if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { return volumeGroupId; } } - return AudioVolumeGroups.DEFAULT_VOLUME_GROUP; + return AudioVolumeGroup.DEFAULT_VOLUME_GROUP; }