diff options
| author | 2014-06-12 18:03:04 +0900 | |
|---|---|---|
| committer | 2014-06-16 13:33:07 +0900 | |
| commit | 60cffce420db4c3395f86d3b9bb36003adf26f5d (patch) | |
| tree | fa900dee8a625da43b95b022c50076319c1f01cb | |
| parent | 401e3de791c0e2a4348361fbd560da9530156e22 (diff) | |
Refine new device action.
There are many ways to initiate new device action
1. When receives <Report Physcial Address>
2. When receives <Active Source> from unregistered device.
If new device is audio system, it should start
ARC and system audio initiation action.
Along with this consolidate device remove actions.
Change-Id: I189afd8bec7270d6a1734a28632593b71932d9e8
10 files changed, 313 insertions, 86 deletions
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java index 32bcb691feb4..bcd08ebfb94a 100644 --- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java +++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java @@ -67,7 +67,10 @@ final class ActiveSourceHandler { } HdmiCecDeviceInfo device = mService.getDeviceInfo(deviceLogicalAddress); if (device == null) { - // TODO: Start new device action (Device Discovery) sequence 5. + // "New device action" initiated by <Active Source> does not require + // "Routing change action". + mService.addAndStartAction(new NewDeviceAction(mService, mSourceAddress, + deviceLogicalAddress, routingPath, false)); } if (!mService.isInPresetInstallationMode()) { diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java index d36fc2c1f06e..f7392e92b63a 100644 --- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java @@ -55,9 +55,6 @@ final class DeviceDiscoveryAction extends FeatureAction { private static final int DEVICE_POLLING_RETRY = 1; - // TODO: Move this to common place - private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF; - /** * Interface used to report result of device discovery. */ @@ -75,7 +72,7 @@ final class DeviceDiscoveryAction extends FeatureAction { private static final class DeviceInfo { private final int mLogicalAddress; - private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS; + private int mPhysicalAddress = HdmiConstants.INVALID_PHYSICAL_ADDRESS; private int mVendorId = HdmiCec.UNKNOWN_VENDOR_ID; private String mDisplayName = ""; private int mDeviceType = HdmiCec.DEVICE_INACTIVE; diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java index f170de04b7f4..a8696a156d7d 100644 --- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java @@ -220,4 +220,8 @@ final class DeviceSelectAction extends FeatureAction { Slog.e(TAG, "Callback failed:" + e); } } + + int getTargetAddress() { + return mTarget.getLogicalAddress(); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 7a08f99f70a1..7a2a6cc2b7bc 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -76,7 +76,7 @@ abstract class HdmiCecLocalDevice { return onMessage(message); } - protected boolean onMessage(HdmiCecMessage message) { + protected final boolean onMessage(HdmiCecMessage message) { switch (message.getOpcode()) { case HdmiCec.MESSAGE_GET_MENU_LANGUAGE: return handleGetMenuLanguage(message); @@ -88,6 +88,8 @@ abstract class HdmiCecLocalDevice { return handleGiveDeviceVendorId(); case HdmiCec.MESSAGE_GET_CEC_VERSION: return handleGetCecVersion(message); + case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS: + return handleReportPhysicalAddress(message); default: return false; } @@ -143,6 +145,10 @@ abstract class HdmiCecLocalDevice { return false; } + protected boolean handleReportPhysicalAddress(HdmiCecMessage message) { + return false; + } + final void handleAddressAllocated(int logicalAddress) { mAddress = mPreferredAddress = logicalAddress; onAddressAllocated(logicalAddress); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index aa1769e4e389..625b2560d48a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -16,13 +16,15 @@ package com.android.server.hdmi; -import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; +import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; +import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; + import java.util.Collections; import java.util.List; import java.util.Locale; @@ -46,20 +48,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand( mAddress, mService.getVendorId())); - mService.launchDeviceDiscovery(mAddress); + launchDeviceDiscovery(); // TODO: Start routing control action, device discovery action. } - @Override - protected boolean onMessage(HdmiCecMessage message) { - switch (message.getOpcode()) { - case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS: - return handleReportPhysicalAddress(message); - default: - return super.onMessage(message); - } - } - /** * Performs the action 'device select', or 'one touch play' initiated by TV. * @@ -98,7 +90,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return true; } - private boolean handleReportPhysicalAddress(HdmiCecMessage message) { + @Override + protected boolean handleReportPhysicalAddress(HdmiCecMessage message) { // Ignore if [Device Discovery Action] is going on. if (mService.hasAction(DeviceDiscoveryAction.class)) { Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> " @@ -107,9 +100,15 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); - mService.addAndStartAction(new NewDeviceAction(mService, - mAddress, message.getSource(), physicalAddress)); + int logicalAddress = message.getSource(); + // If it is a new device and connected to the tail of active path, + // it's required to change routing path. + boolean requireRoutingChange = !mService.isInDeviceList(physicalAddress, logicalAddress) + && mService.isTailOfActivePath(physicalAddress); + mService.addAndStartAction(new NewDeviceAction(mService, + mAddress, message.getSource(), physicalAddress, + requireRoutingChange)); return true; } @@ -137,4 +136,29 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { HdmiConstants.ABORT_REFUSED)); return true; } + + private void launchDeviceDiscovery() { + mService.clearAllDeviceInfo(); + // TODO: Move the following callback to HdmiLocalDeviceTv. + DeviceDiscoveryAction action = new DeviceDiscoveryAction(mService, mAddress, + new DeviceDiscoveryCallback() { + @Override + public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) { + for (HdmiCecDeviceInfo info : deviceInfos) { + mService.addCecDevice(info); + } + + // Since we removed all devices when it's start and + // device discovery action does not poll local devices, + // we should put device info of local device manually here + for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { + mService.addCecDevice(device.getDeviceInfo()); + } + + mService.addAndStartAction(new HotplugDetectionAction(mService, + mAddress)); + } + }); + mService.addAndStartAction(action); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiConstants.java b/services/core/java/com/android/server/hdmi/HdmiConstants.java index 8f319ea9c02c..2ab87d602a2e 100644 --- a/services/core/java/com/android/server/hdmi/HdmiConstants.java +++ b/services/core/java/com/android/server/hdmi/HdmiConstants.java @@ -75,5 +75,8 @@ final class HdmiConstants { */ static final int FLAG_HDMI_OPTION_SYSTEM_CEC_CONTROL = 3; + static final int INVALID_PORT_ID = -1; + static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF; + private HdmiConstants() { /* cannot be instantiated */ } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index ea375f6c2d47..bccfa364cfb3 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -21,6 +21,7 @@ import android.content.Context; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; +import android.hardware.hdmi.HdmiHotplugEvent; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.hdmi.IHdmiControlService; @@ -37,7 +38,6 @@ import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.server.SystemService; -import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; import java.util.ArrayList; @@ -296,7 +296,7 @@ public final class HdmiControlService extends SystemService { HdmiPortInfo portInfo = getPortInfo(portId); if (portInfo == null) { Slog.e(TAG, "Cannot find the port info: " + portId); - return 0xFFFF; // Use HdmiConstants.INVALID_PHYSICAL_ADDRESS; + return HdmiConstants.INVALID_PHYSICAL_ADDRESS; } return portInfo.getAddress(); } @@ -314,7 +314,7 @@ public final class HdmiControlService extends SystemService { return info.getId(); } } - return -1; // Use HdmiConstants.INVALID_PORT_ID; + return HdmiConstants.INVALID_PORT_ID; } /** @@ -446,7 +446,12 @@ public final class HdmiControlService extends SystemService { void setSystemAudioMode(boolean on) { synchronized (mLock) { - mSystemAudioMode = on; + if (on != mSystemAudioMode) { + mSystemAudioMode = on; + // TODO: Need to set the preference for SystemAudioMode. + // TODO: Need to handle the notification of changing the mode and + // to identify the notification should be handled in the service or TvSettings. + } } } @@ -456,6 +461,19 @@ public final class HdmiControlService extends SystemService { } } + /** + * Whether a device of the specified physical address is connected to ARC enabled port. + */ + boolean isConnectedToArcPort(int physicalAddress) { + for (HdmiPortInfo portInfo : mPortInfo) { + if (hasSameTopPort(portInfo.getAddress(), physicalAddress) + && portInfo.isArcSupported()) { + return true; + } + } + return false; + } + // See if we have an action of a given type in progress. <T extends FeatureAction> boolean hasAction(final Class<T> clazz) { for (FeatureAction action : mActions) { @@ -466,6 +484,17 @@ public final class HdmiControlService extends SystemService { return false; } + // Returns all actions matched with given class type. + <T extends FeatureAction> List<T> getActions(final Class<T> clazz) { + ArrayList<T> actions = new ArrayList<>(); + for (FeatureAction action : mActions) { + if (action.getClass().equals(clazz)) { + actions.add((T) action); + } + } + return actions; + } + /** * Remove the given {@link FeatureAction} object from the action queue. * @@ -530,6 +559,15 @@ public final class HdmiControlService extends SystemService { } /** + * Returns whether ARC is enabled or not. + */ + boolean getArcStatus() { + synchronized (mLock) { + return mArcStatusEnabled; + } + } + + /** * Transmit a CEC command to CEC bus. * * @param command CEC command to send out @@ -573,12 +611,23 @@ public final class HdmiControlService extends SystemService { return dispatchMessageToLocalDevice(message); } + private boolean dispatchMessageToAction(HdmiCecMessage message) { + for (FeatureAction action : mActions) { + if (action.processCommand(message)) { + return true; + } + } + return false; + } + private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { if (device.dispatchMessage(message)) { return true; } } + + Slog.w(TAG, "Unhandled cec command:" + message); return false; } @@ -589,7 +638,18 @@ public final class HdmiControlService extends SystemService { * @param connected whether to be plugged in or not */ void onHotplug(int portNo, boolean connected) { - // TODO: Start "RequestArcInitiationAction" if ARC port. + assertRunOnServiceThread(); + // TODO: delegate onHotplug event to each local device. + + // Tv device will have permanent HotplugDetectionAction. + List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class); + if (!hotplugActions.isEmpty()) { + // Note that hotplug action is single action running on a machine. + // "pollAllDevicesNow" cleans up timer and start poll action immediately. + hotplugActions.get(0).pollAllDevicesNow(); + } + + announceHotplugEvent(portNo, connected); } /** @@ -617,35 +677,32 @@ public final class HdmiControlService extends SystemService { return strategy | iterationStrategy; } + void clearAllDeviceInfo() { + assertRunOnServiceThread(); + mCecController.clearDeviceInfoList(); + } + + List<HdmiCecLocalDevice> getAllLocalDevices() { + assertRunOnServiceThread(); + return mCecController.getLocalDeviceList(); + } + /** - * Launch device discovery sequence. It starts with clearing the existing device info list. - * Note that it assumes that logical address of all local devices is already allocated. + * Whether a device of the specified physical address and logical address exists + * in a device info list. However, both are minimal condition and it could + * be different device from the original one. * - * @param sourceAddress a logical address of tv + * @param physicalAddress physical address of a device to be searched + * @param logicalAddress logical address of a device to be searched + * @return true if exist; otherwise false */ - void launchDeviceDiscovery(final int sourceAddress) { - // At first, clear all existing device infos. - mCecController.clearDeviceInfoList(); - // TODO: flush cec message cache when CEC is turned off. - - DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, sourceAddress, - new DeviceDiscoveryCallback() { - @Override - public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) { - for (HdmiCecDeviceInfo info : deviceInfos) { - addCecDevice(info); - } - - // Add device info of all local devices. - for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { - addCecDevice(device.getDeviceInfo()); - } - - addAndStartAction(new HotplugDetectionAction(HdmiControlService.this, - sourceAddress)); - } - }); - addAndStartAction(action); + boolean isInDeviceList(int physicalAddress, int logicalAddress) { + assertRunOnServiceThread(); + HdmiCecDeviceInfo device = mCecController.getDeviceInfo(logicalAddress); + if (device == null) { + return false; + } + return device.getPhysicalAddress() == physicalAddress; } private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { @@ -675,16 +732,6 @@ public final class HdmiControlService extends SystemService { addAndStartAction(action); } - private boolean dispatchMessageToAction(HdmiCecMessage message) { - for (FeatureAction action : mActions) { - if (action.processCommand(message)) { - return true; - } - } - Slog.w(TAG, "Unsupported cec command:" + message); - return false; - } - private void handleSetSystemAudioMode(HdmiCecMessage message) { if (dispatchMessageToAction(message) || !isMessageForSystemAudio(message)) { return; @@ -730,10 +777,6 @@ public final class HdmiControlService extends SystemService { } } - void addCecDevice(HdmiCecDeviceInfo info) { - mCecController.addDeviceInfo(info); - } - private void enforceAccessPermission() { getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); } @@ -768,7 +811,6 @@ public final class HdmiControlService extends SystemService { }); } - @Override public void oneTouchPlay(final IHdmiControlCallback callback) { enforceAccessPermission(); @@ -911,6 +953,17 @@ public final class HdmiControlService extends SystemService { } /** + * Called when a device is newly added or a new device is detected. + * + * @param info device info of a new device. + */ + void addCecDevice(HdmiCecDeviceInfo info) { + mCecController.addDeviceInfo(info); + + // TODO: announce new device detection. + } + + /** * Called when a device is removed or removal of device is detected. * * @param address a logical address of a device to be removed @@ -918,9 +971,61 @@ public final class HdmiControlService extends SystemService { void removeCecDevice(int address) { mCecController.removeDeviceInfo(address); mCecMessageCache.flushMessagesFrom(address); + + // TODO: announce a device removal. + } + + private void announceHotplugEvent(int portNo, boolean connected) { + HdmiHotplugEvent event = new HdmiHotplugEvent(portNo, connected); + synchronized (mLock) { + for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { + invokeHotplugEventListener(listener, event); + } + } + } + + private void invokeHotplugEventListener(IHdmiHotplugEventListener listener, + HdmiHotplugEvent event) { + try { + listener.onReceived(event); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); + } } HdmiCecMessageCache getCecMessageCache() { return mCecMessageCache; } + + private static boolean hasSameTopPort(int path1, int path2) { + return (path1 & HdmiConstants.ROUTING_PATH_TOP_MASK) + == (path2 & HdmiConstants.ROUTING_PATH_TOP_MASK); + } + + /** + * 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) { + // 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; + } } diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java index c7a813d128ab..ae20eda99e9e 100644 --- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java +++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java @@ -90,6 +90,20 @@ final class HotplugDetectionAction extends FeatureAction { } } + /** + * Start device polling immediately. + */ + void pollAllDevicesNow() { + // Clear existing timer to avoid overlapped execution + mActionTimer.clearTimerMessage(); + + mTimeoutCount = 0; + mState = STATE_WAIT_FOR_NEXT_POLLING; + pollAllDevices(); + + addTimer(mState, POLLING_INTERVAL_MS); + } + // This method is called every 5 seconds. private void pollDevices() { // All device check called every 15 seconds. @@ -180,15 +194,56 @@ final class HotplugDetectionAction extends FeatureAction { } private void addDevice(int addedAddress) { - // TODO: implement this. + // Send <Give Physical Address>. + sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(mSourceAddress, addedAddress)); } private void removeDevice(int removedAddress) { + // TODO: move the following logic to local device once move many logic to + // local device. + mayChangeRoutingPath(removedAddress); + mayCancelDeviceSelect(removedAddress); + mayCancelOneTouchRecord(removedAddress); + mayDisableSystemAudioAndARC(removedAddress); + mService.removeCecDevice(removedAddress); - // TODO: implements following steps. - // 1. Launch routing control sequence - // 2. Stop one touch play sequence if removed device is the device to be selected. - // 3. If audio system, start system audio off and arc off - // 4. Inform device remove to others + } + + private void mayChangeRoutingPath(int address) { + // TODO: if removed address is current active source, it should change active source + // path new one. we can keep previous selection or can choose default input, + // such as internal tuner. Consider send intent to app so that app + // can handle it. + } + + private void mayCancelDeviceSelect(int address) { + List<DeviceSelectAction> actions = mService.getActions(DeviceSelectAction.class); + if (actions.isEmpty()) { + return; + } + + // Should ave only one Device Select Action + DeviceSelectAction action = actions.get(0); + if (action.getTargetAddress() == address) { + mService.removeAction(DeviceSelectAction.class); + } + } + + private void mayCancelOneTouchRecord(int address) { + // TODO: implement this. + } + + private void mayDisableSystemAudioAndARC(int address) { + if (HdmiCec.getTypeFromAddress(address) != HdmiCec.DEVICE_AUDIO_SYSTEM) { + return; + } + + // Turn off system audio mode. + mService.setSystemAudioMode(false); + if (mService.getArcStatus()) { + mService.addAndStartAction( + new RequestArcTerminationAction(mService, mSourceAddress, address)); + } + } } diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java index c284d10c4ba7..2cae507797b4 100644 --- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java +++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java @@ -48,6 +48,7 @@ final class NewDeviceAction extends FeatureAction { private final int mDeviceLogicalAddress; private final int mDevicePhysicalAddress; + private final boolean mRequireRoutingChange; private int mVendorId; private String mDisplayName; @@ -59,17 +60,36 @@ final class NewDeviceAction extends FeatureAction { * @param sourceAddress logical address to be used as source address * @param deviceLogicalAddress logical address of the device in interest * @param devicePhysicalAddress physical address of the device in interest + * @param requireRoutingChange whether to initiate routing change or not */ NewDeviceAction(HdmiControlService service, int sourceAddress, int deviceLogicalAddress, - int devicePhysicalAddress) { + int devicePhysicalAddress, boolean requireRoutingChange) { super(service, sourceAddress); mDeviceLogicalAddress = deviceLogicalAddress; mDevicePhysicalAddress = devicePhysicalAddress; mVendorId = HdmiCec.UNKNOWN_VENDOR_ID; + mRequireRoutingChange = requireRoutingChange; } @Override public boolean start() { + if (HdmiCec.getTypeFromAddress(mSourceAddress) == HdmiCec.DEVICE_AUDIO_SYSTEM) { + if (mService.getAvrDeviceInfo() == null) { + // TODO: Start system audio initiation action + } + + // If new device is connected through ARC enabled port, + // initiates ARC channel establishment. + if (mService.isConnectedToArcPort(mDevicePhysicalAddress)) { + mService.addAndStartAction(new RequestArcInitiationAction(mService, mSourceAddress, + mDeviceLogicalAddress)); + } + } + + if (mRequireRoutingChange) { + startRoutingChange(); + } + mState = STATE_WAITING_FOR_SET_OSD_NAME; if (mayProcessCommandIfCached(mDeviceLogicalAddress, HdmiCec.MESSAGE_SET_OSD_NAME)) { return true; @@ -133,6 +153,22 @@ final class NewDeviceAction extends FeatureAction { return false; } + private void startRoutingChange() { + // Stop existing routing control. + mService.removeAction(RoutingControlAction.class); + + // Send routing change. The the address is a path of the active port. + int newPath = toTopMostPortPath(mDevicePhysicalAddress); + sendCommand(HdmiCecMessageBuilder.buildRoutingChange(mSourceAddress, + mService.getActivePath(), newPath)); + mService.addAndStartAction(new RoutingControlAction(mService, mSourceAddress, + mService.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 = mService.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 65615a48543b..19974ea6d418 100644 --- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java +++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java @@ -16,12 +16,11 @@ package com.android.server.hdmi; -import java.util.concurrent.TimeUnit; - -import android.hardware.hdmi.IHdmiControlCallback; +import android.annotation.Nullable; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; +import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; @@ -59,7 +58,7 @@ public class RoutingControlAction extends FeatureAction { // Time out in milliseconds used for <Report Power Status> private static final int TIMEOUT_REPORT_POWER_STATUS_MS = 1000; - private final IHdmiControlCallback mCallback; + @Nullable private final IHdmiControlCallback mCallback; // The latest routing path. Updated by each <Routing Information> from CEC switches. private int mCurrentRoutingPath; @@ -167,7 +166,7 @@ public class RoutingControlAction extends FeatureAction { case STATE_WAIT_FOR_ROUTING_INFORMATION: HdmiCecDeviceInfo device = mService.getDeviceInfoByPath(mCurrentRoutingPath); if (device == null) { - maybeChangeActiveInput(mCurrentRoutingPath); + maybeChangeActiveInput(mService.pathToPortId(mCurrentRoutingPath)); } else { // TODO: Also check followings and then proceed: // if routing change was neither triggered by TV at CEC enable time, nor @@ -185,7 +184,7 @@ public class RoutingControlAction extends FeatureAction { case STATE_WAIT_FOR_REPORT_POWER_STATUS: int tvPowerStatus = getTvPowerStatus(); if (isPowerStatusOnOrTransientToOn(tvPowerStatus)) { - if (!maybeChangeActiveInput(mCurrentRoutingPath)) { + if (!maybeChangeActiveInput(mService.pathToPortId(mCurrentRoutingPath))) { sendSetStreamPath(); } } @@ -217,15 +216,10 @@ public class RoutingControlAction extends FeatureAction { mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS); } else { - maybeChangeActiveInput(mCurrentRoutingPath); + maybeChangeActiveInput(mService.pathToPortId(mCurrentRoutingPath)); } } - // Given the HDMI port id, return the port address. - private int portToPath(int portId) { - return mService.getPortInfo(portId).getAddress(); - } - private void invokeCallback(int result) { if (mCallback == null) { return; |