diff options
3 files changed, 86 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 6697a5315390..7a08f99f70a1 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -139,6 +139,10 @@ abstract class HdmiCecLocalDevice { return true; } + protected boolean handleVendorSpecificCommand(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 6394fe722f47..aa1769e4e389 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -23,6 +23,8 @@ import android.hardware.hdmi.HdmiCecMessage; import android.os.RemoteException; import android.util.Slog; +import java.util.Collections; +import java.util.List; import java.util.Locale; /** @@ -72,7 +74,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } mService.removeAction(DeviceSelectAction.class); mService.addAndStartAction(new DeviceSelectAction(mService, mAddress, - mService.getPhysicalAddress(), targetDevice, callback)); + mService.getPhysicalAddress(), targetDevice, callback)); } private static void invokeCallback(IHdmiControlCallback callback, int result) { @@ -110,4 +112,29 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return true; } + + @Override + protected boolean handleVendorSpecificCommand(HdmiCecMessage message) { + List<VendorSpecificAction> actions = Collections.emptyList(); + // TODO: Call mService.getActions(VendorSpecificAction.class) to get all the actions. + + // We assume that there can be multiple vendor-specific command actions running + // at the same time. Pass the message to each action to see if one of them needs it. + for (VendorSpecificAction action : actions) { + if (action.processCommand(message)) { + return true; + } + } + // Handle the message here if it is not already consumed by one of the running actions. + // Respond with a appropriate vendor-specific command or <Feature Abort>, or create another + // vendor-specific action: + // + // mService.addAndStartAction(new VendorSpecificAction(mService, mAddress)); + // + // For now, simply reply with <Feature Abort> and mark it consumed by returning true. + mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand( + message.getDestination(), message.getSource(), message.getOpcode(), + HdmiConstants.ABORT_REFUSED)); + return true; + } } diff --git a/services/core/java/com/android/server/hdmi/VendorSpecificAction.java b/services/core/java/com/android/server/hdmi/VendorSpecificAction.java new file mode 100644 index 000000000000..9d457020fecc --- /dev/null +++ b/services/core/java/com/android/server/hdmi/VendorSpecificAction.java @@ -0,0 +1,54 @@ +package com.android.server.hdmi; + +import android.hardware.hdmi.HdmiCecMessage; + +/** + * Handles vendor-specific commands that require a sequence of command exchange, + * or need to manage some states to complete the processing. + */ +public class VendorSpecificAction extends FeatureAction { + + // Sample state this action can be in. + private static final int STATE_1 = 1; + private static final int STATE_2 = 2; + + VendorSpecificAction(HdmiControlService service, int sourceAddress) { + super(service, sourceAddress); + // Modify the constructor if additional arguments are necessary. + } + + @Override + boolean start() { + // Do initialization step and update the state accordingly here. + mState = STATE_1; + addTimer(STATE_1, TIMEOUT_MS); + return true; + } + + @Override + boolean processCommand(HdmiCecMessage cmd) { + // Returns true if the command was consumed. Otherwise return false for other + // actions in progress can be given its turn to process it. + return false; + } + + @Override + void handleTimerEvent(int state) { + // Ignore the timer event if the current state and the state this event should be + // handled in are different. Could be an outdated event which should have been cleared by + // calling {@code mActionTimer.clearTimerMessage()}. + if (mState != state) { + return; + } + + switch (state) { + case STATE_1: + mState = STATE_2; + addTimer(STATE_2, TIMEOUT_MS); + break; + case STATE_2: + finish(); + break; + } + } +} |