Merge "Refactor handling sequences in HdmiControlService"
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 73726fa..c1b8bbc 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -48,4 +48,5 @@
     void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback);
     void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
     void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
+    void setControlEnabled(boolean enabled);
 }
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 8de6763..905214f 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -67,9 +67,7 @@
         }
         HdmiCecDeviceInfo device = mService.getDeviceInfo(activeAddress);
         if (device == null) {
-            // "New device action" initiated by <Active Source> does not require
-            // "Routing change action".
-            tv.addAndStartAction(new NewDeviceAction(tv, activeAddress, activePath, false));
+            tv.addAndStartAction(new NewDeviceAction(tv, activeAddress, activePath));
         }
 
         int currentActive = tv.getActiveSource();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index bf7e57b..87cabc6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -143,6 +143,8 @@
                 return handleGetCecVersion(message);
             case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
                 return handleReportPhysicalAddress(message);
+            case HdmiCec.MESSAGE_ROUTING_CHANGE:
+                return handleRoutingChange(message);
             case HdmiCec.MESSAGE_INITIATE_ARC:
                 return handleInitiateArc(message);
             case HdmiCec.MESSAGE_TERMINATE_ARC:
@@ -245,6 +247,10 @@
         return false;
     }
 
+    protected boolean handleRoutingChange(HdmiCecMessage message) {
+        return false;
+    }
+
     protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
         return false;
     }
@@ -471,41 +477,6 @@
         }
     }
 
-    boolean isHdmiControlEnabled() {
-        synchronized (mLock) {
-            return !mInputChangeEnabled;
-        }
-    }
-
-    /**
-     * Whether the given path is located in the tail of current active path.
-     *
-     * @param path to be tested
-     * @return true if the given path is located in the tail of current active path; otherwise,
-     *         false
-     */
-    // TODO: move this to local device tv.
-    boolean isTailOfActivePath(int path) {
-        synchronized (mLock) {
-            // If active routing path is internal source, return false.
-            if (mActiveRoutingPath == 0) {
-                return false;
-            }
-            for (int i = 12; i >= 0; i -= 4) {
-                int curActivePath = (mActiveRoutingPath >> i) & 0xF;
-                if (curActivePath == 0) {
-                    return true;
-                } else {
-                    int curPath = (path >> i) & 0xF;
-                    if (curPath != curActivePath) {
-                        return false;
-                    }
-                }
-            }
-            return false;
-        }
-    }
-
     @ServiceThreadOnly
     HdmiCecMessageCache getCecMessageCache() {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 862233c..7021dc5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -121,7 +121,7 @@
     private void handleSelectInternalSource(IHdmiControlCallback callback) {
         assertRunOnServiceThread();
         // Seq #18
-        if (isHdmiControlEnabled() && getActiveSource() != mAddress) {
+        if (mService.isControlEnabled() && getActiveSource() != mAddress) {
             updateActiveSource(mAddress, mService.getPhysicalAddress());
             // TODO: Check if this comes from <Text/Image View On> - if true, do nothing.
             HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
@@ -185,7 +185,7 @@
     void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
         assertRunOnServiceThread();
         // Seq #20
-        if (!isHdmiControlEnabled() || portId == getActivePortId()) {
+        if (!mService.isControlEnabled() || portId == getActivePortId()) {
             invokeCallback(callback, HdmiCec.RESULT_INCORRECT_MODE);
             return;
         }
@@ -243,8 +243,13 @@
     @ServiceThreadOnly
     protected boolean handleActiveSource(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        int activePath = HdmiUtils.twoBytesToInt(message.getParams());
-        ActiveSourceHandler.create(this, null).process(message.getSource(), activePath);
+        int address = message.getSource();
+        int path = HdmiUtils.twoBytesToInt(message.getParams());
+        if (getDeviceInfo(address) == null) {
+            handleNewDeviceAtTheTailOfActivePath(address, path);
+        } else {
+            ActiveSourceHandler.create(this, null).process(address, path);
+        }
         return true;
     }
 
@@ -286,10 +291,9 @@
     protected boolean handleRequestActiveSource(HdmiCecMessage message) {
         assertRunOnServiceThread();
         // Seq #19
-        int address = getDeviceInfo().getLogicalAddress();
-        if (address == getActiveSource()) {
+        if (mAddress == getActiveSource()) {
             mService.sendCecCommand(
-                    HdmiCecMessageBuilder.buildActiveSource(address, getActivePath()));
+                    HdmiCecMessageBuilder.buildActiveSource(mAddress, getActivePath()));
         }
         return true;
     }
@@ -320,15 +324,70 @@
             return true;
         }
 
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        int logicalAddress = message.getSource();
+        int path = HdmiUtils.twoBytesToInt(message.getParams());
+        int address = message.getSource();
+        if (!isInDeviceList(path, address)) {
+            handleNewDeviceAtTheTailOfActivePath(address, path);
+        }
+        addAndStartAction(new NewDeviceAction(this, address, path));
+        return true;
+    }
 
-        // If it is a new device and connected to the tail of active path,
-        // it's required to change routing path.
-        boolean requireRoutingChange = !isInDeviceList(physicalAddress, logicalAddress)
-                && isTailOfActivePath(physicalAddress);
-        addAndStartAction(new NewDeviceAction(this, message.getSource(), physicalAddress,
-                requireRoutingChange));
+    private void handleNewDeviceAtTheTailOfActivePath(int address, int path) {
+        // Seq #22
+        if (isTailOfActivePath(path, getActivePath())) {
+            removeAction(RoutingControlAction.class);
+            int newPath = mService.portIdToPath(getActivePortId());
+            mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(
+                    mAddress, getActivePath(), newPath));
+            addAndStartAction(new RoutingControlAction(this, getActivePortId(), null));
+        }
+    }
+
+    /**
+     * Whether the given path is located in the tail of current active path.
+     *
+     * @param path to be tested
+     * @param activePath current active path
+     * @return true if the given path is located in the tail of current active path; otherwise,
+     *         false
+     */
+    static boolean isTailOfActivePath(int path, int activePath) {
+        // If active routing path is internal source, return false.
+        if (activePath == 0) {
+            return false;
+        }
+        for (int i = 12; i >= 0; i -= 4) {
+            int curActivePath = (activePath >> i) & 0xF;
+            if (curActivePath == 0) {
+                return true;
+            } else {
+                int curPath = (path >> i) & 0xF;
+                if (curPath != curActivePath) {
+                    return false;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleRoutingChange(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        // Seq #21
+        byte[] params = message.getParams();
+        if (params.length != 4) {
+            Slog.w(TAG, "Wrong parameter: " + message);
+            return true;
+        }
+        int currentPath = HdmiUtils.twoBytesToInt(params);
+        if (HdmiUtils.isAffectingActiveRoutingPath(getActivePath(), currentPath)) {
+            int newPath = HdmiUtils.twoBytesToInt(params, 2);
+            setActivePath(newPath);
+            removeAction(RoutingControlAction.class);
+            addAndStartAction(new RoutingControlAction(this, newPath, null));
+        }
         return true;
     }
 
@@ -776,10 +835,43 @@
     final void removeCecDevice(int address) {
         assertRunOnServiceThread();
         HdmiCecDeviceInfo info = removeDeviceInfo(address);
+        handleRemoveActiveRoutingPath(info.getPhysicalAddress());
         mCecMessageCache.flushMessagesFrom(address);
         mService.invokeDeviceEventListeners(info, false);
     }
 
+    private void handleRemoveActiveRoutingPath(int path) {
+        // Seq #23
+        if (isTailOfActivePath(path, getActivePath())) {
+            removeAction(RoutingControlAction.class);
+            int newPath = mService.portIdToPath(getActivePortId());
+            mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(
+                    mAddress, getActivePath(), newPath));
+            addAndStartAction(new RoutingControlAction(this, getActivePortId(), null));
+        }
+    }
+
+    @ServiceThreadOnly
+    void routingAtEnableTime() {
+        assertRunOnServiceThread();
+        // Seq #24
+        if (getActivePortId() != HdmiConstants.INVALID_PORT_ID) {
+            // TODO: Check if TV was not powered on due to <Text/Image View On>,
+            //       TV is not in Preset Installation mode, not in initial setup mode, not
+            //       in Software updating mode, not in service mode, for following actions.
+            removeAction(RoutingControlAction.class);
+            int newPath = mService.portIdToPath(getActivePortId());
+            mService.sendCecCommand(
+                    HdmiCecMessageBuilder.buildRoutingChange(mAddress, getActivePath(), newPath));
+            addAndStartAction(new RoutingControlAction(this, getActivePortId(), null));
+        } else {
+            int activePath = mService.getPhysicalAddress();
+            setActivePath(activePath);
+            // TODO: Do following only when TV was not powered on due to <Text/Image View On>.
+            mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(mAddress, activePath));
+        }
+    }
+
     /**
      * Returns the {@link HdmiCecDeviceInfo} instance whose physical address matches
      * the given routing path. CEC devices use routing path for its physical address to
@@ -804,12 +896,12 @@
      * in a device info list. However, both are minimal condition and it could
      * be different device from the original one.
      *
-     * @param physicalAddress physical address of a device to be searched
      * @param logicalAddress logical address of a device to be searched
+     * @param physicalAddress physical address of a device to be searched
      * @return true if exist; otherwise false
      */
     @ServiceThreadOnly
-    boolean isInDeviceList(int physicalAddress, int logicalAddress) {
+    boolean isInDeviceList(int logicalAddress, int physicalAddress) {
         assertRunOnServiceThread();
         HdmiCecDeviceInfo device = getDeviceInfo(logicalAddress);
         if (device == null) {
@@ -820,7 +912,7 @@
 
     @Override
     @ServiceThreadOnly
-    void onHotplug(int portNo, boolean connected) {
+    void onHotplug(int portId, boolean connected) {
         assertRunOnServiceThread();
 
         // Tv device will have permanent HotplugDetectionAction.
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index ad95181..6397109 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -116,6 +116,11 @@
     private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords =
             new ArrayList<>();
 
+    // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol
+    // handling will be disabled and no request will be handled.
+    @GuardedBy("mLock")
+    private boolean mHdmiControlEnabled;
+
     // List of listeners registered by callers that want to get notified of
     // system audio mode changes.
     private final ArrayList<IHdmiSystemAudioModeChangeListener>
@@ -163,6 +168,7 @@
 
         // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and
         // start to monitor the preference value and invoke SystemAudioActionFromTv if needed.
+        mHdmiControlEnabled = true;
     }
 
     @ServiceThreadOnly
@@ -716,6 +722,29 @@
             enforceAccessPermission();
             HdmiControlService.this.removeSystemAudioModeChangeListener(listener);
         }
+
+        @Override
+        public void setControlEnabled(boolean enabled) {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                mHdmiControlEnabled = enabled;
+            }
+            // TODO: Stop the running actions when disabled, and start
+            //       address allocation/device discovery when enabled.
+            if (!enabled) {
+                return;
+            }
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiCecLocalDeviceTv tv = tv();
+                    if (tv == null) {
+                        return;
+                    }
+                    tv.routingAtEnableTime();
+                }
+            });
+        }
     }
 
     @ServiceThreadOnly
@@ -875,4 +904,10 @@
     AudioManager getAudioManager() {
         return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
     }
+
+    boolean isControlEnabled() {
+        synchronized (mLock) {
+            return mHdmiControlEnabled;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 9b7cc8d..51d26ef 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -104,6 +104,17 @@
     }
 
     /**
+     * Assemble two bytes into single integer value.
+     *
+     * @param data to be assembled
+     * @param offset offset to the data to convert in the array
+     * @return assembled value
+     */
+    static int twoBytesToInt(byte[] data, int offset) {
+        return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
+    }
+
+    /**
      * Assemble three bytes into single integer value.
      *
      * @param data to be assembled
@@ -121,4 +132,65 @@
         return list;
     }
 
+    /**
+     * See if the new path is affecting the active path.
+     *
+     * @param activePath current active path
+     * @param newPath new path
+     * @return true if the new path changes the current active path
+     */
+    static boolean isAffectingActiveRoutingPath(int activePath, int newPath) {
+        // The new path affects the current active path if the parent of the new path
+        // is an ancestor of the active path.
+        // (1.1.0.0, 2.0.0.0) -> true, new path alters the parent
+        // (1.1.0.0, 1.2.0.0) -> true, new path is a sibling
+        // (1.1.0.0, 1.2.1.0) -> false, new path is a descendant of a sibling
+        // (1.0.0.0, 3.2.0.0) -> false, in a completely different path
+
+        // Get the parent of the new path by clearing the least significant
+        // non-zero nibble.
+        for (int i = 0; i <= 12; i += 4) {
+            int nibble = (newPath >> i) & 0xF;
+            if (nibble != 0) {
+                int mask = 0xFFF0 << i;
+                newPath &= mask;
+                break;
+            }
+        }
+        if (newPath == 0x0000) {
+            return true;  // Top path always affects the active path
+        }
+        return isInActiveRoutingPath(activePath, newPath);
+    }
+
+    /**
+     * See if the new path is in the active path.
+     *
+     * @param activePath current active path
+     * @param newPath new path
+     * @return true if the new path in the active routing path
+     */
+    static boolean isInActiveRoutingPath(int activePath, int newPath) {
+        // Check each nibble of the currently active path and the new path till the position
+        // where the active nibble is not zero. For (activePath, newPath),
+        // (1.1.0.0, 1.0.0.0) -> true, new path is a parent
+        // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant
+        // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling
+        // (1.0.0.0, 2.0.0.0) -> false, in a completely different path
+        for (int i = 12; i >= 0; i -= 4) {
+            int nibbleActive = (activePath >> i) & 0xF;
+            if (nibbleActive == 0) {
+                break;
+            }
+            int nibbleNew = (newPath >> i) & 0xF;
+            if (nibbleNew == 0) {
+                break;
+            }
+            if (nibbleActive != nibbleNew) {
+                return false;
+            }
+        }
+        return true;
+    }
+
 }
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 4a49f09..f7e29e5 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -48,7 +48,6 @@
 
     private final int mDeviceLogicalAddress;
     private final int mDevicePhysicalAddress;
-    private final boolean mRequireRoutingChange;
 
     private int mVendorId;
     private String mDisplayName;
@@ -62,12 +61,11 @@
      * @param requireRoutingChange whether to initiate routing change or not
      */
     NewDeviceAction(HdmiCecLocalDevice source, int deviceLogicalAddress,
-            int devicePhysicalAddress, boolean requireRoutingChange) {
+            int devicePhysicalAddress) {
         super(source);
         mDeviceLogicalAddress = deviceLogicalAddress;
         mDevicePhysicalAddress = devicePhysicalAddress;
         mVendorId = HdmiCec.UNKNOWN_VENDOR_ID;
-        mRequireRoutingChange = requireRoutingChange;
     }
 
     @Override
@@ -85,10 +83,6 @@
             }
         }
 
-        if (mRequireRoutingChange) {
-            startRoutingChange();
-        }
-
         mState = STATE_WAITING_FOR_SET_OSD_NAME;
         if (mayProcessCommandIfCached(mDeviceLogicalAddress, HdmiCec.MESSAGE_SET_OSD_NAME)) {
             return true;
@@ -152,22 +146,6 @@
         return false;
     }
 
-    private void startRoutingChange() {
-        // Stop existing routing control.
-        removeAction(RoutingControlAction.class);
-
-        // Send routing change. The the address is a path of the active port.
-        int newPath = toTopMostPortPath(mDevicePhysicalAddress);
-        sendCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(),
-                localDevice().getActivePath(), newPath));
-        addAndStartAction(new RoutingControlAction(localDevice(),
-                localDevice().pathToPortId(newPath), null));
-    }
-
-    private static int toTopMostPortPath(int physicalAddress) {
-        return physicalAddress & HdmiConstants.ROUTING_PATH_TOP_MASK;
-    }
-
     private boolean mayProcessCommandIfCached(int destAddress, int opcode) {
         HdmiCecMessage message = getCecMessageCache().getMessage(destAddress, opcode);
         if (message != null) {
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index 0d657b2..0c3bc0c 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -86,7 +86,7 @@
             // If the routing path doesn't belong to the currently active one, we should
             // ignore it since it might have come from other routing change sequence.
             int routingPath = HdmiUtils.twoBytesToInt(params);
-            if (isInActiveRoutingPath(mCurrentRoutingPath, routingPath)) {
+            if (HdmiUtils.isInActiveRoutingPath(mCurrentRoutingPath, routingPath)) {
                 return true;
             }
             mCurrentRoutingPath = routingPath;
@@ -108,15 +108,11 @@
             if (isPowerStatusOnOrTransientToOn(devicePowerStatus)) {
                 sendSetStreamPath();
             } else {
-                // The whole action should be stopped here if the device is in standby mode.
-                // We don't attempt to wake it up by sending <Set Stream Path>.
+                tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath));
             }
-            invokeCallback(HdmiCec.RESULT_SUCCESS);
-            finish();
-          } else {
-              // TV is going into standby mode.
-              // TODO: Figure out what to do.
-          }
+        }
+        invokeCallback(HdmiCec.RESULT_SUCCESS);
+        finish();
      }
 
     private int getTvPowerStatus() {
@@ -133,29 +129,6 @@
                 mCurrentRoutingPath));
     }
 
-    private static boolean isInActiveRoutingPath(int activePath, int newPath) {
-        // Check each nibble of the currently active path and the new path till the position
-        // where the active nibble is not zero. For (activePath, newPath),
-        // (1.1.0.0, 1.0.0.0) -> true, new path is a parent
-        // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant
-        // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling
-        // (1.0.0.0, 2.0.0.0) -> false, in a completely different path
-        for (int i = 12; i >= 0; i -= 4) {
-            int nibbleActive = (activePath >> i) & 0xF;
-            if (nibbleActive == 0) {
-                break;
-            }
-            int nibbleNew = (newPath >> i) & 0xF;
-            if (nibbleNew == 0) {
-                break;
-            }
-            if (nibbleActive != nibbleNew) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     @Override
     public void handleTimerEvent(int timeoutState) {
         if (mState != timeoutState || mState == STATE_NONE) {
@@ -166,7 +139,7 @@
             case STATE_WAIT_FOR_ROUTING_INFORMATION:
                 HdmiCecDeviceInfo device = tv().getDeviceInfoByPath(mCurrentRoutingPath);
                 if (device == null) {
-                    maybeChangeActiveInput(tv().pathToPortId(mCurrentRoutingPath));
+                    tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath));
                 } else {
                     // TODO: Also check followings and then proceed:
                     //       if routing change was neither triggered by TV at CEC enable time, nor
@@ -184,9 +157,8 @@
             case STATE_WAIT_FOR_REPORT_POWER_STATUS:
                 int tvPowerStatus = getTvPowerStatus();
                 if (isPowerStatusOnOrTransientToOn(tvPowerStatus)) {
-                    if (!maybeChangeActiveInput(localDevice().pathToPortId(mCurrentRoutingPath))) {
-                        sendSetStreamPath();
-                    }
+                    tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath));
+                    sendSetStreamPath();
                 }
                 invokeCallback(HdmiCec.RESULT_SUCCESS);
                 finish();
@@ -194,18 +166,6 @@
         }
     }
 
-    // Called whenever an HDMI input of the TV shall become the active input.
-    private boolean maybeChangeActiveInput(int path) {
-        if (localDevice().getActivePortId() == localDevice().pathToPortId(path)) {
-            return false;
-        }
-        // TODO: Remember the currently active input
-        //       if PAP/PIP is active, move the focus to the right window, otherwise switch
-        //       the port.
-        //       Show the OSD input change banner.
-        return true;
-    }
-
     private void queryDevicePowerStatus(int address, SendMessageCallback callback) {
         sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address),
                 callback);
@@ -216,7 +176,8 @@
             mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
             addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS);
         } else {
-            maybeChangeActiveInput(localDevice().pathToPortId(mCurrentRoutingPath));
+            tv().updateActivePortId(tv().pathToPortId(mCurrentRoutingPath));
+            sendSetStreamPath();
         }
     }