From cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53b Mon Sep 17 00:00:00 2001 From: Jinsuk Kim Date: Mon, 19 Jan 2015 12:39:06 +0900 Subject: [PATCH] CEC: Add logic to return to internal source This CL introduces a logic that, upon receiving from the active source or a corresponding MHL subcommand, lets the service return to one of internal inputs. Introduced to handle it is a new type for HdmiDevice (INACTIVE) that will be passed to input change listeners. The callback is expected to transform to other mechanism such as intent, to let TV app to decide which input to switch to, which will be one of non-HDMI input that was viewed previously. Bug: 19008579 Change-Id: I1922f4cd20e9220411061bb9d9fbe5fbc5676d48 --- .../android/hardware/hdmi/HdmiDeviceInfo.java | 47 ++++++++++++++++++- .../server/hdmi/HdmiCecLocalDeviceTv.java | 9 +++- .../server/hdmi/HdmiControlService.java | 24 +++++----- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java index c4c7f2d77a8a4..48ea9a63e2d61 100644 --- a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java +++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java @@ -77,10 +77,19 @@ public class HdmiDeviceInfo implements Parcelable { /** Invalid port ID */ public static final int PORT_INVALID = -1; + /** Invalid device ID */ + public static final int ID_INVALID = 0xFFFF; + + /** Device info used to indicate an inactivated device. */ + public static final HdmiDeviceInfo INACTIVE_DEVICE = new HdmiDeviceInfo(); + private static final int HDMI_DEVICE_TYPE_CEC = 0; private static final int HDMI_DEVICE_TYPE_MHL = 1; private static final int HDMI_DEVICE_TYPE_HARDWARE = 2; + // Type used to indicate the device that has relinquished its active source status. + private static final int HDMI_DEVICE_TYPE_INACTIVE = 100; + // Offset used for id value. MHL devices, for instance, will be assigned the value from // ID_OFFSET_MHL. private static final int ID_OFFSET_CEC = 0x0; @@ -130,6 +139,8 @@ public class HdmiDeviceInfo implements Parcelable { return new HdmiDeviceInfo(physicalAddress, portId, adopterId, deviceId); case HDMI_DEVICE_TYPE_HARDWARE: return new HdmiDeviceInfo(physicalAddress, portId); + case HDMI_DEVICE_TYPE_INACTIVE: + return HdmiDeviceInfo.INACTIVE_DEVICE; default: return null; } @@ -208,7 +219,6 @@ public class HdmiDeviceInfo implements Parcelable { mDeviceId = -1; mAdopterId = -1; - } /** @@ -236,6 +246,28 @@ public class HdmiDeviceInfo implements Parcelable { mAdopterId = deviceId; } + /** + * Constructor. Used to initialize the instance representing an inactivated device. + * Can be passed input change listener to indicate the active source yielded + * its status, hence the listener should take an appropriate action such as + * switching to other input. + */ + public HdmiDeviceInfo() { + mHdmiDeviceType = HDMI_DEVICE_TYPE_INACTIVE; + mPhysicalAddress = PATH_INVALID; + mId = ID_INVALID; + + mLogicalAddress = -1; + mDeviceType = DEVICE_INACTIVE; + mPortId = PORT_INVALID; + mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN; + mDisplayName = "Inactive"; + mVendorId = 0; + + mDeviceId = -1; + mAdopterId = -1; + } + /** * Returns the id of the device. */ @@ -363,6 +395,14 @@ public class HdmiDeviceInfo implements Parcelable { return mHdmiDeviceType == HDMI_DEVICE_TYPE_MHL; } + /** + * Return {@code true} if the device represents an inactivated device that relinquishes + * its status as active source by <Active Source> (HDMI-CEC) or Content-off (MHL). + */ + public boolean isInactivated() { + return mHdmiDeviceType == HDMI_DEVICE_TYPE_INACTIVE; + } + /** * Returns display (OSD) name of the device. */ @@ -411,6 +451,8 @@ public class HdmiDeviceInfo implements Parcelable { dest.writeInt(mDeviceId); dest.writeInt(mAdopterId); break; + case HDMI_DEVICE_TYPE_INACTIVE: + // flow through default: // no-op } @@ -438,6 +480,9 @@ public class HdmiDeviceInfo implements Parcelable { case HDMI_DEVICE_TYPE_HARDWARE: s.append("Hardware: "); break; + case HDMI_DEVICE_TYPE_INACTIVE: + s.append("Inactivated: "); + break; default: return ""; } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 4673b8cae5f1a..43ef457b35bea 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -476,7 +476,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress); if (info == null) { if (!handleNewDeviceAtTheTailOfActivePath(physicalAddress)) { - HdmiLogger.debug("Device info not found: %X; buffering the command", logicalAddress); + HdmiLogger.debug("Device info %X not found; buffering the command", logicalAddress); mDelayedMessageBuffer.add(message); } } else if (!isInputReady(info.getId())) { @@ -517,6 +517,12 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { doManualPortSwitching(portId, null); setPrevPortId(Constants.INVALID_PORT_ID); + } else { + // No HDMI port to switch to was found. Notify the input change listers to + // switch to the lastly shown internal input. + mActiveSource.invalidate(); + setActivePath(Constants.INVALID_PHYSICAL_ADDRESS); + mService.invokeInputChangeListener(HdmiDeviceInfo.INACTIVE_DEVICE); } return true; } @@ -1826,6 +1832,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { pw.println("mAutoDeviceOff: " + mAutoDeviceOff); pw.println("mAutoWakeup: " + mAutoWakeup); pw.println("mSkipRoutingControl: " + mSkipRoutingControl); + pw.println("mPrevPortId: " + mPrevPortId); pw.println("CEC devices:"); pw.increaseIndent(); for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index fa8ab594a9883..9f78c61fa9f0d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -2252,16 +2252,17 @@ public final class HdmiControlService extends SystemService { assertRunOnServiceThread(); if (tv() == null) return; final int lastInput = contentOn ? tv().getActivePortId() : Constants.INVALID_PORT_ID; - tv().doManualPortSwitching(portId, new IHdmiControlCallback.Stub() { - @Override - public void onComplete(int result) throws RemoteException { - // Keep the last input to switch back later when RAP[ContentOff] is received. - // This effectively sets the port to invalid one if the switching is for - // RAP[ContentOff]. - setLastInputForMhl(lastInput); - } - }); - + if (portId != Constants.INVALID_PORT_ID) { + tv().doManualPortSwitching(portId, new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) throws RemoteException { + // Keep the last input to switch back later when RAP[ContentOff] is received. + // This effectively sets the port to invalid one if the switching is for + // RAP[ContentOff]. + setLastInputForMhl(lastInput); + } + }); + } // MHL device is always directly connected to the port. Update the active port ID to avoid // unnecessary post-routing control task. tv().setActivePortId(portId); @@ -2271,7 +2272,8 @@ public final class HdmiControlService extends SystemService { // may not be the MHL-enabled one. In this case the device info to be passed to // input change listener should be the one describing the corresponding HDMI port. HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); - HdmiDeviceInfo info = (device != null) ? device.getInfo() : mPortDeviceMap.get(portId); + HdmiDeviceInfo info = (device != null) ? device.getInfo() + : mPortDeviceMap.get(portId, HdmiDeviceInfo.INACTIVE_DEVICE); invokeInputChangeListener(info); }