Merge "Add CDM core test OWNERS file"
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 9235ba1..3e509e4 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -36,10 +36,12 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ConcurrentUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -69,6 +71,32 @@
     private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
 
     /**
+     * A cache of the current device's physical address. When device's HDMI out port
+     * is not connected to any device, it is set to {@link #INVALID_PHYSICAL_ADDRESS}.
+     *
+     * <p>Otherwise it is updated by the {@link ClientHotplugEventListener} registered
+     * with {@link com.android.server.hdmi.HdmiControlService} by the
+     * {@link #addHotplugEventListener(HotplugEventListener)} and the address is from
+     * {@link com.android.server.hdmi.HdmiControlService#getPortInfo()}
+     */
+    @GuardedBy("mLock")
+    private int mLocalPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+
+    private void setLocalPhysicalAddress(int physicalAddress) {
+        synchronized (mLock) {
+            mLocalPhysicalAddress = physicalAddress;
+        }
+    }
+
+    private int getLocalPhysicalAddress() {
+        synchronized (mLock) {
+            return mLocalPhysicalAddress;
+        }
+    }
+
+    private final Object mLock = new Object();
+
+    /**
      * Broadcast Action: Display OSD message.
      * <p>Send when the service has a message to display on screen for events
      * that need user's attention such as ARC status change.
@@ -1094,6 +1122,37 @@
         mHasAudioSystemDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
         mHasSwitchDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
         mIsSwitchDevice = HdmiProperties.is_switch().orElse(false);
+        addHotplugEventListener(new ClientHotplugEventListener());
+    }
+
+    private final class ClientHotplugEventListener implements HotplugEventListener {
+
+        @Override
+        public void onReceived(HdmiHotplugEvent event) {
+            List<HdmiPortInfo> ports = new ArrayList<>();
+            try {
+                ports = mService.getPortInfo();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            if (ports.isEmpty()) {
+                Log.e(TAG, "Can't find port info, not updating connected status. "
+                        + "Hotplug event:" + event);
+                return;
+            }
+            // If the HDMI OUT port is plugged or unplugged, update the mLocalPhysicalAddress
+            for (HdmiPortInfo port : ports) {
+                if (port.getId() == event.getPort()) {
+                    if (port.getType() == HdmiPortInfo.PORT_OUTPUT) {
+                        setLocalPhysicalAddress(
+                                event.isConnected()
+                                        ? port.getAddress()
+                                        : INVALID_PHYSICAL_ADDRESS);
+                    }
+                    break;
+                }
+            }
+        }
     }
 
     private static boolean hasDeviceType(int[] types, int type) {
@@ -1464,11 +1523,7 @@
      * 1.4b 8.7 Physical Address for more details on the address discovery proccess.
      */
     public int getPhysicalAddress() {
-        try {
-            return mService.getPhysicalAddress();
-        } catch (RemoteException e) {
-            return INVALID_PHYSICAL_ADDRESS;
-        }
+        return getLocalPhysicalAddress();
     }
 
     /**
@@ -1482,7 +1537,7 @@
      */
     public boolean isDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
         Objects.requireNonNull(targetDevice);
-        int physicalAddress = getPhysicalAddress();
+        int physicalAddress = getLocalPhysicalAddress();
         if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
             return false;
         }
@@ -1501,7 +1556,7 @@
     @Deprecated
     public boolean isRemoteDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
         Objects.requireNonNull(targetDevice);
-        int physicalAddress = getPhysicalAddress();
+        int physicalAddress = getLocalPhysicalAddress();
         if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
             return false;
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 05915d9..acfde9a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4005,7 +4005,8 @@
         }
     }
 
-    private void setLeAudioVolumeOnModeUpdate(int mode, int device) {
+    private void setLeAudioVolumeOnModeUpdate(int mode, int device, int streamType, int index,
+            int maxIndex) {
         switch (mode) {
             case AudioSystem.MODE_IN_COMMUNICATION:
             case AudioSystem.MODE_IN_CALL:
@@ -4023,16 +4024,15 @@
         // (like the outgoing call) the value of 'device' is not DEVICE_OUT_BLE_*
         // even when BLE is connected.
         if (!AudioSystem.isLeAudioDeviceType(device)) {
+            Log.w(TAG, "setLeAudioVolumeOnModeUpdate got unexpected device=" + device
+                    + ", forcing to device=" + AudioSystem.DEVICE_OUT_BLE_HEADSET);
             device = AudioSystem.DEVICE_OUT_BLE_HEADSET;
         }
 
-        final int streamType = getBluetoothContextualVolumeStream(mode);
-        final int index = mStreamStates[streamType].getIndex(device);
-        final int maxIndex = mStreamStates[streamType].getMaxIndex();
-
         if (DEBUG_VOL) {
-            Log.d(TAG, "setLeAudioVolumeOnModeUpdate postSetLeAudioVolumeIndex index="
-                    + index + " maxIndex=" + maxIndex + " streamType=" + streamType);
+            Log.d(TAG, "setLeAudioVolumeOnModeUpdate postSetLeAudioVolumeIndex device="
+                    + device + ", mode=" + mode + ", index=" + index + " maxIndex=" + maxIndex
+                    + " streamType=" + streamType);
         }
         mDeviceBroker.postSetLeAudioVolumeIndex(index, maxIndex, streamType);
         mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "setLeAudioVolumeOnModeUpdate");
@@ -5403,10 +5403,18 @@
                 mModeLogger.log(new PhoneStateEvent(requesterPackage, requesterPid,
                         requestedMode, pid, mode));
 
-                int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
-                int device = getDeviceForStream(streamType);
-                int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
-                setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true,
+                final int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
+                final int device = getDeviceForStream(streamType);
+                final int streamAlias = mStreamVolumeAlias[streamType];
+
+                if (DEBUG_MODE) {
+                    Log.v(TAG, "onUpdateAudioMode: streamType=" + streamType
+                            + ", streamAlias=" + streamAlias);
+                }
+
+                final int index = mStreamStates[streamAlias].getIndex(device);
+                final int maxIndex = mStreamStates[streamAlias].getMaxIndex();
+                setStreamVolumeInt(streamAlias, index, device, true,
                         requesterPackage, true /*hasModifyAudioSettings*/);
 
                 updateStreamVolumeAlias(true /*updateVolumes*/, requesterPackage);
@@ -5414,7 +5422,7 @@
                 // change of mode may require volume to be re-applied on some devices
                 updateAbsVolumeMultiModeDevices(previousMode, mode);
 
-                setLeAudioVolumeOnModeUpdate(mode, device);
+                setLeAudioVolumeOnModeUpdate(mode, device, streamAlias, index, maxIndex);
 
                 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
                 // connections not started by the application changing the mode when pid changes