Merge "HDMI: Improve behavior of TVs ignoring standby from non-active source" into main
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 81c30dd..4b85217 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -116,11 +116,11 @@
     private boolean mWasActiveSourceSetToConnectedDevice = false;
 
     @VisibleForTesting
-    protected boolean getWasActiveSourceSetToConnectedDevice() {
+    protected boolean getWasActivePathSetToConnectedDevice() {
         return mWasActiveSourceSetToConnectedDevice;
     }
 
-    protected void setWasActiveSourceSetToConnectedDevice(
+    protected void setWasActivePathSetToConnectedDevice(
             boolean wasActiveSourceSetToConnectedDevice) {
         mWasActiveSourceSetToConnectedDevice = wasActiveSourceSetToConnectedDevice;
     }
@@ -404,6 +404,15 @@
         }
     }
 
+    @Override
+    void setActivePath(int path) {
+        super.setActivePath(path);
+        if (path != Constants.INVALID_PHYSICAL_ADDRESS
+                && path != Constants.TV_PHYSICAL_ADDRESS) {
+            setWasActivePathSetToConnectedDevice(true);
+        }
+    }
+
     @ServiceThreadOnly
     void updateActiveInput(int path, boolean notifyInputChange) {
         assertRunOnServiceThread();
@@ -512,7 +521,6 @@
                 || info.getDeviceType() == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
             mService.getHdmiCecNetwork().updateDevicePowerStatus(logicalAddress,
                     HdmiControlManager.POWER_STATUS_ON);
-            setWasActiveSourceSetToConnectedDevice(true);
             ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
             ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType());
         } else {
@@ -528,16 +536,16 @@
     protected int handleStandby(HdmiCecMessage message) {
         assertRunOnServiceThread();
 
-        // If a device has previously asserted the active source status, ignore <Standby> from
-        // non-active source.
-        if (getWasActiveSourceSetToConnectedDevice()
+        // If the TV has previously changed the active path, ignore <Standby> from non-active
+        // source.
+        if (getWasActivePathSetToConnectedDevice()
                 && getActiveSource().logicalAddress != message.getSource()) {
             Slog.d(TAG, "<Standby> was not sent by the current active source, ignoring."
                     + " Current active source has logical address "
                     + getActiveSource().logicalAddress);
             return Constants.HANDLED;
         }
-        setWasActiveSourceSetToConnectedDevice(false);
+        setWasActivePathSetToConnectedDevice(false);
         return super.handleStandby(message);
     }
 
@@ -1509,7 +1517,7 @@
             invokeStandbyCompletedCallback(callback);
             return;
         }
-        setWasActiveSourceSetToConnectedDevice(false);
+        setWasActivePathSetToConnectedDevice(false);
         boolean sendStandbyOnSleep =
                 mService.getHdmiCecConfig().getIntValue(
                     HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP)
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index 0c4fb26..d48957b 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -44,7 +44,8 @@
     static final int STATE_WAIT_FOR_ROUTING_INFORMATION = 1;
 
     // Time out in millseconds used for <Routing Information>
-    private static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000;
+    @VisibleForTesting
+    static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000;
 
     // If set to true, call {@link HdmiControlService#invokeInputChangeListener()} when
     // the routing control/active source change happens. The listener should be called if
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index a7e8a00..a5f1fcd 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -29,6 +29,7 @@
 import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
 import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON;
 import static com.android.server.hdmi.RequestActiveSourceAction.TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS;
+import static com.android.server.hdmi.RoutingControlAction.TIMEOUT_ROUTING_INFORMATION_MS;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -77,6 +78,7 @@
 public class HdmiCecLocalDeviceTvTest {
     private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
     private static final int PORT_1 = 1;
+    private static final int PORT_2 = 2;
 
     private static final String[] SADS_NOT_TO_QUERY = new String[]{
             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1,
@@ -215,7 +217,7 @@
                 .setEarcSupported(false)
                 .build();
         hdmiPortInfos[1] =
-                new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, 0x2000)
+                new HdmiPortInfo.Builder(PORT_2, HdmiPortInfo.PORT_INPUT, 0x2000)
                         .setCecSupported(true)
                         .setMhlSupported(false)
                         .setArcSupported(true)
@@ -2021,7 +2023,7 @@
                 ADDR_TV);
         mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+        assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
                 .isFalse();
         mPowerManager.setInteractive(true);
         mTestLooper.dispatchAll();
@@ -2031,14 +2033,14 @@
                 "HdmiCecLocalDeviceTvTest");
         mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+        assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
                 .isTrue();
         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
 
         assertThat(mPowerManager.isInteractive()).isFalse();
-        assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+        assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
                 .isFalse();
     }
 
@@ -2051,7 +2053,7 @@
         mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
         mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+        assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
                 .isFalse();
         mPowerManager.setInteractive(true);
 
@@ -2060,7 +2062,7 @@
                 "HdmiCecLocalDeviceTvTest");
         mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+        assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
                 .isTrue();
         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
                 .isEqualTo(Constants.HANDLED);
@@ -2076,22 +2078,51 @@
         mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
         mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+        assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
                 .isFalse();
         mPowerManager.setInteractive(true);
 
-        assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+        assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
                 .isFalse();
         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
                 .isEqualTo(Constants.HANDLED);
         mTestLooper.dispatchAll();
 
         assertThat(mPowerManager.isInteractive()).isFalse();
-        assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+        assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
                 .isFalse();
     }
 
     @Test
+    public void handleStandby_fromNonActiveSource_previousActivePathSetToNonCecDevice_Standby() {
+        HdmiCecLocalDeviceTv hdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
+        hdmiCecLocalDeviceTv.setDeviceInfo(mHdmiCecLocalDeviceTv.getDeviceInfo());
+        mTestLooper.dispatchAll();
+
+        assertThat(hdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
+                .isFalse();
+        mPowerManager.setInteractive(true);
+        hdmiCecLocalDeviceTv.doManualPortSwitching(PORT_2, null);
+        mTestLooper.dispatchAll();
+
+        // Timeout the action RoutingControlAction such that the active path would be updated.
+        mTestLooper.moveTimeForward(TIMEOUT_ROUTING_INFORMATION_MS);
+        mTestLooper.dispatchAll();
+
+        assertThat(hdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
+                .isTrue();
+        HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+                ADDR_PLAYBACK_1, ADDR_TV);
+        assertThat(hdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
+                .isEqualTo(Constants.HANDLED);
+        mTestLooper.dispatchAll();
+
+        assertThat(mPowerManager.isInteractive()).isTrue();
+        assertThat(hdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
+                .isTrue();
+    }
+
+    @Test
     public void handleReportPhysicalAddress_DeviceDiscoveryActionInProgress_noNewDeviceAction() {
         mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
         mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
@@ -2189,7 +2220,7 @@
 
         @Override
         protected int handleActiveSource(HdmiCecMessage message) {
-            setWasActiveSourceSetToConnectedDevice(true);
+            setWasActivePathSetToConnectedDevice(true);
             return super.handleActiveSource(message);
         }
     }