Merge "AudioService: update getDevicesForAttributes" into tm-dev
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index dc55c05..90b272c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2712,10 +2712,10 @@
     return AUDIO_JAVA_SUCCESS;
 }
 
-static jint
-android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz,
-        jobject jaa, jobjectArray jDeviceArray)
-{
+static jint android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz,
+                                                              jobject jaa,
+                                                              jobjectArray jDeviceArray,
+                                                              jboolean forVolume) {
     const jsize maxResultSize = env->GetArrayLength(jDeviceArray);
     // the JNI is always expected to provide us with an array capable of holding enough
     // devices i.e. the most we ever route a track to. This is preferred over receiving an ArrayList
@@ -2734,7 +2734,7 @@
 
     AudioDeviceTypeAddrVector devices;
     jStatus = check_AudioSystem_Command(
-            AudioSystem::getDevicesForAttributes(*(paa.get()), &devices));
+            AudioSystem::getDevicesForAttributes(*(paa.get()), &devices, forVolume));
     if (jStatus != NO_ERROR) {
         return jStatus;
     }
@@ -3045,7 +3045,7 @@
          {"getDevicesForRoleAndCapturePreset", "(IILjava/util/List;)I",
           (void *)android_media_AudioSystem_getDevicesForRoleAndCapturePreset},
          {"getDevicesForAttributes",
-          "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;)I",
+          "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;Z)I",
           (void *)android_media_AudioSystem_getDevicesForAttributes},
          {"setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I",
           (void *)android_media_AudioSystem_setUserIdDeviceAffinities},
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 6cacebb..210f3e5 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1668,13 +1668,14 @@
      *   otherwise (typically one device, except for duplicated paths).
      */
     public static @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
-            @NonNull AudioAttributes attributes) {
+            @NonNull AudioAttributes attributes, boolean forVolume) {
         Objects.requireNonNull(attributes);
         final AudioDeviceAttributes[] devices = new AudioDeviceAttributes[MAX_DEVICE_ROUTING];
-        final int res = getDevicesForAttributes(attributes, devices);
+        final int res = getDevicesForAttributes(attributes, devices, forVolume);
         final ArrayList<AudioDeviceAttributes> routeDevices = new ArrayList<>();
         if (res != SUCCESS) {
-            Log.e(TAG, "error " + res + " in getDevicesForAttributes for " + attributes);
+            Log.e(TAG, "error " + res + " in getDevicesForAttributes attributes: " + attributes
+                    + " forVolume: " + forVolume);
             return routeDevices;
         }
 
@@ -1693,7 +1694,8 @@
     private static final int MAX_DEVICE_ROUTING = 4;
 
     private static native int getDevicesForAttributes(@NonNull AudioAttributes aa,
-                                                      @NonNull AudioDeviceAttributes[] devices);
+                                                      @NonNull AudioDeviceAttributes[] devices,
+                                                      boolean forVolume);
 
     /** @hide returns true if master mono is enabled. */
     public static native boolean getMasterMono();
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index daf3561..ff7557a 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -396,7 +396,8 @@
             AudioAttributes attr =
                     AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(
                             AudioSystem.STREAM_VOICE_CALL);
-            List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr);
+            List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(
+                    attr, false /* forVolume */);
             if (devices.isEmpty()) {
                 if (mAudioService.isPlatformVoice()) {
                     Log.w(TAG,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0b9fb1a..24dfa25 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1808,6 +1808,10 @@
      * @param caller caller of this method
      */
     private void updateVolumeStates(int device, int streamType, String caller) {
+        // Handle device volume aliasing of SPEAKER_SAFE.
+        if (device == AudioSystem.DEVICE_OUT_SPEAKER_SAFE) {
+            device = AudioSystem.DEVICE_OUT_SPEAKER;
+        }
         if (!mStreamStates[streamType].hasIndexForDevice(device)) {
             // set the default value, if device is affected by a full/fix/abs volume rule, it
             // will taken into account in checkFixedVolumeDevices()
@@ -1819,7 +1823,8 @@
 
         // Check if device to be updated is routed for the given audio stream
         List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributesInt(
-                new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build());
+                new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build(),
+                true /* forVolume */);
         for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) {
             if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType(
                     device)) {
@@ -2687,7 +2692,7 @@
     public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
             @NonNull AudioAttributes attributes) {
         enforceQueryStateOrModifyRoutingPermission();
-        return getDevicesForAttributesInt(attributes);
+        return getDevicesForAttributesInt(attributes, false /* forVolume */);
     }
 
     /** @see AudioManager#getAudioDevicesForAttributes(AudioAttributes)
@@ -2697,7 +2702,7 @@
      */
     public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesUnprotected(
             @NonNull AudioAttributes attributes) {
-        return getDevicesForAttributesInt(attributes);
+        return getDevicesForAttributesInt(attributes, false /* forVolume */);
     }
 
     /**
@@ -2719,9 +2724,9 @@
     }
 
     protected @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesInt(
-            @NonNull AudioAttributes attributes) {
+            @NonNull AudioAttributes attributes, boolean forVolume) {
         Objects.requireNonNull(attributes);
-        return mAudioSystem.getDevicesForAttributes(attributes);
+        return mAudioSystem.getDevicesForAttributes(attributes, forVolume);
     }
 
     /** Indicates no special treatment in the handling of the volume adjustement */
@@ -6490,7 +6495,8 @@
                 .setUsage(AudioAttributes.USAGE_MEDIA)
                 .build();
         // calling getDevice*Int to bypass permission check
-        final List<AudioDeviceAttributes> devices = getDevicesForAttributesInt(attributes);
+        final List<AudioDeviceAttributes> devices =
+                getDevicesForAttributesInt(attributes, true /* forVolume */);
         for (AudioDeviceAttributes device : devices) {
             if (getDeviceVolumeBehaviorInt(device) == AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED) {
                 return true;
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index a70b470..6ef8e87 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -24,12 +24,14 @@
 import android.media.audiopolicy.AudioMix;
 import android.os.SystemClock;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -59,7 +61,7 @@
 
     private static final boolean USE_CACHE_FOR_GETDEVICES = true;
     private ConcurrentHashMap<Integer, Integer> mDevicesForStreamCache;
-    private ConcurrentHashMap<AudioAttributes, ArrayList<AudioDeviceAttributes>>
+    private ConcurrentHashMap<Pair<AudioAttributes, Boolean>, ArrayList<AudioDeviceAttributes>>
             mDevicesForAttrCache;
     private int[] mMethodCacheHit;
     private static final Object sRoutingListenerLock = new Object();
@@ -201,26 +203,28 @@
      * @return the devices that the stream with the given attributes would be routed to
      */
     public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
-            @NonNull AudioAttributes attributes) {
+            @NonNull AudioAttributes attributes, boolean forVolume) {
         if (!ENABLE_GETDEVICES_STATS) {
-            return getDevicesForAttributesImpl(attributes);
+            return getDevicesForAttributesImpl(attributes, forVolume);
         }
         mMethodCallCounter[METHOD_GETDEVICESFORATTRIBUTES]++;
         final long startTime = SystemClock.uptimeNanos();
-        final ArrayList<AudioDeviceAttributes> res = getDevicesForAttributesImpl(attributes);
+        final ArrayList<AudioDeviceAttributes> res = getDevicesForAttributesImpl(
+                attributes, forVolume);
         mMethodTimeNs[METHOD_GETDEVICESFORATTRIBUTES] += SystemClock.uptimeNanos() - startTime;
         return res;
     }
 
     private @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesImpl(
-            @NonNull AudioAttributes attributes) {
+            @NonNull AudioAttributes attributes, boolean forVolume) {
         if (USE_CACHE_FOR_GETDEVICES) {
             ArrayList<AudioDeviceAttributes> res;
+            final Pair<AudioAttributes, Boolean> key = new Pair(attributes, forVolume);
             synchronized (mDevicesForAttrCache) {
-                res = mDevicesForAttrCache.get(attributes);
+                res = mDevicesForAttrCache.get(key);
                 if (res == null) {
-                    res = AudioSystem.getDevicesForAttributes(attributes);
-                    mDevicesForAttrCache.put(attributes, res);
+                    res = AudioSystem.getDevicesForAttributes(attributes, forVolume);
+                    mDevicesForAttrCache.put(key, res);
                     if (DEBUG_CACHE) {
                         Log.d(TAG, mMethodNames[METHOD_GETDEVICESFORATTRIBUTES]
                                 + attrDeviceToDebugString(attributes, res));
@@ -231,7 +235,7 @@
                 mMethodCacheHit[METHOD_GETDEVICESFORATTRIBUTES]++;
                 if (DEBUG_CACHE) {
                     final ArrayList<AudioDeviceAttributes> real =
-                            AudioSystem.getDevicesForAttributes(attributes);
+                            AudioSystem.getDevicesForAttributes(attributes, forVolume);
                     if (res.equals(real)) {
                         Log.d(TAG, mMethodNames[METHOD_GETDEVICESFORATTRIBUTES]
                                 + attrDeviceToDebugString(attributes, res) + " CACHE");
@@ -245,7 +249,7 @@
             return res;
         }
         // not using cache
-        return AudioSystem.getDevicesForAttributes(attributes);
+        return AudioSystem.getDevicesForAttributes(attributes, forVolume);
     }
 
     private static String attrDeviceToDebugString(@NonNull AudioAttributes attr,
@@ -523,9 +527,10 @@
         }
         pw.println(" mDevicesForAttrCache:");
         if (mDevicesForAttrCache != null) {
-            for (AudioAttributes attr : mDevicesForAttrCache.keySet()) {
-                pw.println("\t" + attr);
-                for (AudioDeviceAttributes devAttr : mDevicesForAttrCache.get(attr)) {
+            for (Map.Entry<Pair<AudioAttributes, Boolean>, ArrayList<AudioDeviceAttributes>>
+                    entry : mDevicesForAttrCache.entrySet()) {
+                pw.println("\t" + entry.getKey().first + " forVolume: " + entry.getKey().second);
+                for (AudioDeviceAttributes devAttr : entry.getValue()) {
                     pw.println("\t\t" + devAttr);
                 }
             }
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 63b27d8..193cc5f 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -264,7 +264,8 @@
             return;
         }
         mState = STATE_DISABLED_UNAVAILABLE;
-        mASA.getDevicesForAttributes(DEFAULT_ATTRIBUTES).toArray(ROUTING_DEVICES);
+        mASA.getDevicesForAttributes(
+                DEFAULT_ATTRIBUTES, false /* forVolume */).toArray(ROUTING_DEVICES);
         // note at this point mSpat is still not instantiated
     }
 
@@ -298,7 +299,8 @@
             case STATE_DISABLED_AVAILABLE:
                 break;
         }
-        mASA.getDevicesForAttributes(DEFAULT_ATTRIBUTES).toArray(ROUTING_DEVICES);
+        mASA.getDevicesForAttributes(
+                DEFAULT_ATTRIBUTES, false /* forVolume */).toArray(ROUTING_DEVICES);
 
         // is media routed to a new device?
         if (isWireless(ROUTING_DEVICES[0].getType())) {
@@ -865,7 +867,8 @@
         }
         AudioDeviceAttributes[] devices = new AudioDeviceAttributes[1];
         // going through adapter to take advantage of routing cache
-        mASA.getDevicesForAttributes(attributes).toArray(devices);
+        mASA.getDevicesForAttributes(
+                attributes, false /* forVolume */).toArray(devices);
         final boolean able = canBeSpatializedOnDevice(attributes, format, devices);
         logd("canBeSpatialized returning " + able);
         return able;