Merge "CEC: Handle <Active Source> arriving before TvInputCallback.onAddInput" into lmp-mr1-dev

This commit is contained in:
Jinsuk Kim
2015-01-08 04:08:52 +00:00
committed by Android (Google) Code Review
3 changed files with 66 additions and 13 deletions

View File

@@ -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>&lt;Active Source&gt; is not processed in this method but processed
* separately via {@link #processActiveSource()}.
* <p>&lt;Active Source&gt; 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();
}
}

View File

@@ -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.
*

View File

@@ -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);