diff options
3 files changed, 66 insertions, 13 deletions
diff --git a/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java b/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java index 922a2c14c4cc..d3ecff0f188a 100644 --- a/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java +++ b/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java @@ -88,24 +88,22 @@ final class DelayedMessageBuffer { * Process messages from a given logical device. Called by * {@link NewDeviceAction} actions when they finish adding the device * information. - * <p><Active Source> is not processed in this method but processed - * separately via {@link #processActiveSource()}. + * <p><Active Source> is processed only when the TV input is ready. + * If not, {@link #processActiveSource()} will be invoked later to handle it. * * @param address logical address of CEC device which the messages to process * are associated with */ void processMessagesForDevice(int address) { - HdmiLogger.debug("Processing message for address:" + address); + HdmiLogger.debug("Checking message for address:" + address); for (Iterator<HdmiCecMessage> iter = mBuffer.iterator(); iter.hasNext(); ) { HdmiCecMessage message = iter.next(); - if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE) { - continue; - } - if (message.getSource() == address) { - mDevice.onMessage(message); - HdmiLogger.debug("Processing message:" + message); - iter.remove(); - } + if (message.getSource() != address) continue; + if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE + && !mDevice.isInputReady(HdmiDeviceInfo.idForCecDevice(address))) continue; + mDevice.onMessage(message); + HdmiLogger.debug("Processing message:" + message); + iter.remove(); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 4f8b9fbc71f5..1b478885e9cb 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -191,6 +191,17 @@ abstract class HdmiCecLocalDevice { protected abstract void setPreferredAddress(int addr); /** + * Returns true if the TV input associated with the CEC device is ready + * to accept further processing such as input switching. This is used + * to buffer certain CEC commands and process it later if the input is not + * ready yet. For other types of local devices(non-TV), this method returns + * true by default to let the commands be processed right away. + */ + protected boolean isInputReady(int deviceId) { + return true; + } + + /** * Dispatch incoming message. * * @param message incoming message diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 90dbd1765200..a8941619dc2d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -63,6 +63,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.HashMap; /** * Represent a logical device of type TV residing in Android system. @@ -143,12 +144,44 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { public void onInputAdded(String inputId) { TvInputInfo tvInfo = mService.getTvInputManager().getTvInputInfo(inputId); HdmiDeviceInfo info = tvInfo.getHdmiDeviceInfo(); - if (info != null && info.isCecDevice()) { - mDelayedMessageBuffer.processActiveSource(info.getLogicalAddress()); + if (info == null) return; + addTvInput(inputId, info.getId()); + if (info.isCecDevice()) { + processDelayedActiveSource(info.getLogicalAddress()); } } + + @Override + public void onInputRemoved(String inputId) { + removeTvInput(inputId); + } }; + // Keeps the mapping (TV input ID, HDMI device ID) to keep track of the TV inputs ready to + // accept input switching request from HDMI devices. Requests for which the corresponding + // input ID is not yet registered by TV input framework need to be buffered for delayed + // processing. + private final HashMap<String, Integer> mTvInputs = new HashMap<>(); + + @ServiceThreadOnly + private void addTvInput(String inputId, int deviceId) { + assertRunOnServiceThread(); + mTvInputs.put(inputId, deviceId); + } + + @ServiceThreadOnly + private void removeTvInput(String inputId) { + assertRunOnServiceThread(); + mTvInputs.remove(inputId); + } + + @Override + @ServiceThreadOnly + protected boolean isInputReady(int deviceId) { + assertRunOnServiceThread(); + return mTvInputs.containsValue(deviceId); + } + HdmiCecLocalDeviceTv(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_TV); mPrevPortId = Constants.INVALID_PORT_ID; @@ -168,6 +201,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand( mAddress, mService.getVendorId())); mCecSwitches.add(mService.getPhysicalAddress()); // TV is a CEC switch too. + mTvInputs.clear(); mSkipRoutingControl = (reason == HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE); launchRoutingControl(reason != HdmiControlService.INITIATED_BY_ENABLE_CEC && reason != HdmiControlService.INITIATED_BY_BOOT_UP); @@ -447,8 +481,12 @@ 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); mDelayedMessageBuffer.add(message); } + } else if (!isInputReady(info.getId())) { + HdmiLogger.debug("Input not ready for device: %X; buffering the command", info.getId()); + mDelayedMessageBuffer.add(message); } else { ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress); ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType()); @@ -1776,6 +1814,12 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mDelayedMessageBuffer.processMessagesForDevice(address); } + @ServiceThreadOnly + void processDelayedActiveSource(int address) { + assertRunOnServiceThread(); + mDelayedMessageBuffer.processActiveSource(address); + } + @Override protected void dump(final IndentingPrintWriter pw) { super.dump(pw); |