CEC: Handle <Active Source> arriving before TvInputCallback.onAddInput
Resolves a timing-related bug that fails to process the command <Active Source> at TV boot up. Checks if TV input required for the command is ready to accept the request. If not, makes sure the command is buffered, and processed later when the input is ready. Bug: 18896770 Change-Id: Id17e5e8468519b17daf61c962dd718ccc56fb0ea
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user