FileDocCategorySizeDatePackage
RoutingControlAction.javaAPI DocAndroid 5.1 API8626Thu Mar 12 22:22:42 GMT 2015com.android.server.hdmi

RoutingControlAction

public final class RoutingControlAction extends HdmiCecFeatureAction
Feature action for routing control. Exchanges routing-related commands with other devices to determine the new active source.

This action is initiated by various cases:

  • Manual TV input switching
  • Routing change of a CEC switch other than TV
  • New CEC device at the tail of the active routing path
  • Removed CEC device from the active routing path
  • Routing at CEC enable time

Fields Summary
private static final String
TAG
private static final int
STATE_WAIT_FOR_ROUTING_INFORMATION
private static final int
STATE_WAIT_FOR_REPORT_POWER_STATUS
private static final int
TIMEOUT_ROUTING_INFORMATION_MS
private static final int
TIMEOUT_REPORT_POWER_STATUS_MS
private final boolean
mQueryDevicePowerStatus
private final boolean
mNotifyInputChange
private final android.hardware.hdmi.IHdmiControlCallback
mCallback
private int
mCurrentRoutingPath
Constructors Summary
RoutingControlAction(HdmiCecLocalDevice localDevice, int path, boolean queryDevicePowerStatus, android.hardware.hdmi.IHdmiControlCallback callback)


         
              
        super(localDevice);
        mCallback = callback;
        mCurrentRoutingPath = path;
        mQueryDevicePowerStatus = queryDevicePowerStatus;
        // Callback is non-null when routing control action is brought up by binder API. Use
        // this as an indicator for the input change notification. These API calls will get
        // the result through this callback, not through notification. Any other events that
        // trigger the routing control is external, for which notifcation is used.
        mNotifyInputChange = (callback == null);
    
Methods Summary
private voidfinishWithCallback(int result)

        invokeCallback(result);
        finish();
    
private intgetTvPowerStatus()

        return tv().getPowerStatus();
    
private voidhandlDevicePowerStatusAckResult(boolean acked)

        if (acked) {
            mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
            addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS);
        } else {
            tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
            sendSetStreamPath();
            finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
        }
    
private voidhandleReportPowerStatus(int devicePowerStatus)

        if (isPowerOnOrTransient(getTvPowerStatus())) {
            tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
            if (isPowerOnOrTransient(devicePowerStatus)) {
                sendSetStreamPath();
            }
        }
        finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
    
public voidhandleTimerEvent(int timeoutState)

        if (mState != timeoutState || mState == STATE_NONE) {
            Slog.w("CEC", "Timer in a wrong state. Ignored.");
            return;
        }
        switch (timeoutState) {
            case STATE_WAIT_FOR_ROUTING_INFORMATION:
                HdmiDeviceInfo device = tv().getDeviceInfoByPath(mCurrentRoutingPath);
                if (device != null && mQueryDevicePowerStatus) {
                    int deviceLogicalAddress = device.getLogicalAddress();
                    queryDevicePowerStatus(deviceLogicalAddress, new SendMessageCallback() {
                        @Override
                        public void onSendCompleted(int error) {
                            handlDevicePowerStatusAckResult(
                                    error == HdmiControlManager.RESULT_SUCCESS);
                        }
                    });
                } else {
                    tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
                    finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
                }
                return;
            case STATE_WAIT_FOR_REPORT_POWER_STATUS:
                if (isPowerOnOrTransient(getTvPowerStatus())) {
                    tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
                    sendSetStreamPath();
                }
                finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
                return;
        }
    
private voidinvokeCallback(int result)

        if (mCallback == null) {
            return;
        }
        try {
            mCallback.onComplete(result);
        } catch (RemoteException e) {
            // Do nothing.
        }
    
private static booleanisPowerOnOrTransient(int status)

        return status == HdmiControlManager.POWER_STATUS_ON
                || status == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON;
    
public booleanprocessCommand(HdmiCecMessage cmd)

        int opcode = cmd.getOpcode();
        byte[] params = cmd.getParams();
        if (mState == STATE_WAIT_FOR_ROUTING_INFORMATION
                && opcode == Constants.MESSAGE_ROUTING_INFORMATION) {
            // Keep updating the physicalAddress as we receive <Routing Information>.
            // If the routing path doesn't belong to the currently active one, we should
            // ignore it since it might have come from other routing change sequence.
            int routingPath = HdmiUtils.twoBytesToInt(params);
            if (!HdmiUtils.isInActiveRoutingPath(mCurrentRoutingPath, routingPath)) {
                return true;
            }
            mCurrentRoutingPath = routingPath;
            // Stop possible previous routing change sequence if in progress.
            removeActionExcept(RoutingControlAction.class, this);
            addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS);
            return true;
        } else if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS
                  && opcode == Constants.MESSAGE_REPORT_POWER_STATUS) {
            handleReportPowerStatus(cmd.getParams()[0]);
            return true;
        }
        return false;
    
private voidqueryDevicePowerStatus(int address, com.android.server.hdmi.HdmiControlService.SendMessageCallback callback)

        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address),
                callback);
    
private voidsendSetStreamPath()

        sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(getSourceAddress(),
                mCurrentRoutingPath));
    
public booleanstart()

        mState = STATE_WAIT_FOR_ROUTING_INFORMATION;
        addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS);
        return true;