Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5aa75ca authored by Yuncheol Heo's avatar Yuncheol Heo Committed by Android (Google) Code Review
Browse files

Merge "Add the CEC message handler for the standby mode." into lmp-dev

parents 36bf310f 25c20298
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -162,7 +162,7 @@ final class Constants {
    // Constants related to operands of HDMI CEC commands.
    // Constants related to operands of HDMI CEC commands.
    // Refer to CEC Table 29 in HDMI Spec v1.4b.
    // Refer to CEC Table 29 in HDMI Spec v1.4b.
    // [Abort Reason]
    // [Abort Reason]
    static final int ABORT_UNRECOGNIZED_MODE = 0;
    static final int ABORT_UNRECOGNIZED_OPCODE = 0;
    static final int ABORT_NOT_IN_CORRECT_MODE = 1;
    static final int ABORT_NOT_IN_CORRECT_MODE = 1;
    static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
    static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
    static final int ABORT_INVALID_OPERAND = 3;
    static final int ABORT_INVALID_OPERAND = 3;
+8 −7
Original line number Original line Diff line number Diff line
@@ -172,7 +172,7 @@ abstract class HdmiCecLocalDevice {
     * @return true if consumed a message; otherwise, return false.
     * @return true if consumed a message; otherwise, return false.
     */
     */
    @ServiceThreadOnly
    @ServiceThreadOnly
    final boolean dispatchMessage(HdmiCecMessage message) {
    boolean dispatchMessage(HdmiCecMessage message) {
        assertRunOnServiceThread();
        assertRunOnServiceThread();
        int dest = message.getDestination();
        int dest = message.getDestination();
        if (dest != mAddress && dest != Constants.ADDR_BROADCAST) {
        if (dest != mAddress && dest != Constants.ADDR_BROADCAST) {
@@ -309,7 +309,7 @@ abstract class HdmiCecLocalDevice {
        mService.sendCecCommand(
        mService.sendCecCommand(
                HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
                HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
                        message.getSource(), Constants.MESSAGE_GET_MENU_LANGUAGE,
                        message.getSource(), Constants.MESSAGE_GET_MENU_LANGUAGE,
                        Constants.ABORT_UNRECOGNIZED_MODE));
                        Constants.ABORT_UNRECOGNIZED_OPCODE));
        return true;
        return true;
    }
    }


@@ -381,7 +381,7 @@ abstract class HdmiCecLocalDevice {
        return false;
        return false;
    }
    }


    private static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) {
    static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) {
        byte[] params = message.getParams();
        byte[] params = message.getParams();
        return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
        return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
                && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
                && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
@@ -389,7 +389,7 @@ abstract class HdmiCecLocalDevice {
                        || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
                        || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
    }
    }


    private static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) {
    static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) {
        byte[] params = message.getParams();
        byte[] params = message.getParams();
        return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
        return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
                && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
                && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
@@ -431,7 +431,7 @@ abstract class HdmiCecLocalDevice {
            Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>");
            Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>");
            mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
            mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
                    message.getSource(), Constants.MESSAGE_VENDOR_COMMAND_WITH_ID,
                    message.getSource(), Constants.MESSAGE_VENDOR_COMMAND_WITH_ID,
                    Constants.ABORT_UNRECOGNIZED_MODE));
                    Constants.ABORT_UNRECOGNIZED_OPCODE));
        } else {
        } else {
            Slog.v(TAG, "Wrong broadcast vendor command. Ignoring");
            Slog.v(TAG, "Wrong broadcast vendor command. Ignoring");
        }
        }
@@ -444,9 +444,10 @@ abstract class HdmiCecLocalDevice {
    }
    }


    protected boolean handleRecordTvScreen(HdmiCecMessage message) {
    protected boolean handleRecordTvScreen(HdmiCecMessage message) {
        // The default behavior of <Record TV Screen> is replying <Feature Abort> with "Refused".
        // The default behavior of <Record TV Screen> is replying <Feature Abort> with
        // "Cannot provide source".
        mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
        mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
                message.getSource(), message.getOpcode(), Constants.ABORT_REFUSED));
                message.getSource(), message.getOpcode(), Constants.ABORT_CANNOT_PROVIDE_SOURCE));
        return true;
        return true;
    }
    }


+19 −2
Original line number Original line Diff line number Diff line
@@ -100,12 +100,15 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    // If true, TV wakes itself up when receiving <Text/Image View On>.
    // If true, TV wakes itself up when receiving <Text/Image View On>.
    private boolean mAutoWakeup;
    private boolean mAutoWakeup;


    private final HdmiCecStandbyModeHandler mStandbyHandler;

    HdmiCecLocalDeviceTv(HdmiControlService service) {
    HdmiCecLocalDeviceTv(HdmiControlService service) {
        super(service, HdmiCecDeviceInfo.DEVICE_TV);
        super(service, HdmiCecDeviceInfo.DEVICE_TV);
        mPrevPortId = Constants.INVALID_PORT_ID;
        mPrevPortId = Constants.INVALID_PORT_ID;
        mAutoDeviceOff = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
        mAutoDeviceOff = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
                true);
                true);
        mAutoWakeup = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, true);
        mAutoWakeup = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, true);
        mStandbyHandler = new HdmiCecStandbyModeHandler(service, this);
    }
    }


    @Override
    @Override
@@ -135,6 +138,16 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        SystemProperties.set(Constants.PROPERTY_PREFERRED_ADDRESS_TV, String.valueOf(addr));
        SystemProperties.set(Constants.PROPERTY_PREFERRED_ADDRESS_TV, String.valueOf(addr));
    }
    }


    @Override
    @ServiceThreadOnly
    boolean dispatchMessage(HdmiCecMessage message) {
        assertRunOnServiceThread();
        if (mService.isPowerStandby() && mStandbyHandler.handleCommand(message)) {
            return true;
        }
        return super.onMessage(message);
    }

    /**
    /**
     * Performs the action 'device select', or 'one touch play' initiated by TV.
     * Performs the action 'device select', or 'one touch play' initiated by TV.
     *
     *
@@ -787,8 +800,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    }
    }


    private boolean isSystemAudioOn() {
    private boolean isSystemAudioOn() {


        synchronized (mLock) {
        synchronized (mLock) {
            return mSystemAudioActivated;
            return mSystemAudioActivated;
        }
        }
@@ -1183,6 +1194,12 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, enabled);
        mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, enabled);
    }
    }


    @ServiceThreadOnly
    boolean getAutoWakeup() {
        assertRunOnServiceThread();
        return mAutoWakeup;
    }

    @Override
    @Override
    @ServiceThreadOnly
    @ServiceThreadOnly
    protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
    protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
+174 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.hdmi;

import android.util.SparseArray;

/**
 * This class handles the incoming messages when HdmiCecService is in the standby mode.
 */
public final class HdmiCecStandbyModeHandler {

    private interface CecMessageHandler {
        boolean handle(HdmiCecMessage message);
    }

    private static final class Bystander implements CecMessageHandler {
        @Override
        public boolean handle(HdmiCecMessage message) {
            return true;
        }
    }

    private static final class Bypasser implements CecMessageHandler {
        @Override
        public boolean handle(HdmiCecMessage message) {
            return false;
        }
    }

    private final class Aborter implements CecMessageHandler {
        private final int mReason;
        public Aborter(int reason) {
            mReason = reason;
        }
        @Override
        public boolean handle(HdmiCecMessage message) {
            int src = message.getSource();
            int dest = message.getDestination();
            if (src == Constants.ADDR_BROADCAST || dest == Constants.ADDR_BROADCAST) {
                // Do not send <Feature Abort> on the message from the unassigned device
                // or the broadcasted message.
                return true;
            }
            HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand(
                    dest, src, message.getOpcode(), mReason);
            mService.sendCecCommand(cecMessage);
            return true;
        }
    }

    private final class AutoOnHandler implements CecMessageHandler {
        @Override
        public boolean handle(HdmiCecMessage message) {
            if (!mTv.getAutoWakeup()) {
                mAborterRefused.handle(message);
                return true;
            }
            return false;
        }
    }

    private final class UserControlProcessedHandler implements CecMessageHandler {
        @Override
        public boolean handle(HdmiCecMessage message) {
            // The power status here is always standby.
            if (HdmiCecLocalDevice.isPowerOnOrToggleCommand(message)) {
                return false;
            } else if (HdmiCecLocalDevice.isPowerOffOrToggleCommand(message)) {
                return true;
            }
            return mAborterIncorrectMode.handle(message);
        }
    }

    private final HdmiControlService mService;
    private final HdmiCecLocalDeviceTv mTv;

    private final SparseArray<CecMessageHandler> mCecMessageHandlers = new SparseArray<>();
    private final CecMessageHandler mDefaultHandler = new Aborter(
            Constants.ABORT_UNRECOGNIZED_OPCODE);
    private final CecMessageHandler mAborterIncorrectMode = new Aborter(
            Constants.ABORT_NOT_IN_CORRECT_MODE);
    private final CecMessageHandler mAborterRefused = new Aborter(Constants.ABORT_REFUSED);
    private final CecMessageHandler mAutoOnHandler = new AutoOnHandler();
    private final CecMessageHandler mBypasser = new Bypasser();
    private final CecMessageHandler mBystander = new Bystander();
    private final UserControlProcessedHandler
            mUserControlProcessedHandler = new UserControlProcessedHandler();

    public HdmiCecStandbyModeHandler(HdmiControlService service, HdmiCecLocalDeviceTv tv) {
        mService = service;
        mTv = tv;

        addHandler(Constants.MESSAGE_IMAGE_VIEW_ON, mAutoOnHandler);
        addHandler(Constants.MESSAGE_TEXT_VIEW_ON, mAutoOnHandler);

        addHandler(Constants.MESSAGE_ACTIVE_SOURCE, mBystander);
        addHandler(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, mBystander);
        addHandler(Constants.MESSAGE_ROUTING_CHANGE, mBystander);
        addHandler(Constants.MESSAGE_ROUTING_INFORMATION, mBystander);
        addHandler(Constants.MESSAGE_SET_STREAM_PATH, mBystander);
        addHandler(Constants.MESSAGE_STANDBY, mBystander);
        addHandler(Constants.MESSAGE_SET_MENU_LANGUAGE, mBystander);
        addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBystander);
        addHandler(Constants.MESSAGE_USER_CONTROL_RELEASED, mBystander);
        addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBystander);
        addHandler(Constants.MESSAGE_FEATURE_ABORT, mBystander);
        addHandler(Constants.MESSAGE_INACTIVE_SOURCE, mBystander);
        addHandler(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, mBystander);
        addHandler(Constants.MESSAGE_REPORT_AUDIO_STATUS, mBystander);

        // If TV supports the following messages during power-on, ignore them and do nothing,
        // else reply with <Feature Abort>["Unrecognized Opcode"]
        // <Deck Status>, <Tuner Device Status>, <Tuner Cleared Status>, <Timer Status>
        addHandler(Constants.MESSAGE_RECORD_STATUS, mBystander);

        // If TV supports the following messages during power-on, reply with <Feature Abort>["Not
        // in correct mode to respond"], else reply with <Feature Abort>["Unrecognized Opcode"]
        // <Give Tuner Device Status>, <Select Digital Service>, <Tuner Step Decrement>,
        // <Tuner Stem Increment>, <Menu Status>.
        addHandler(Constants.MESSAGE_RECORD_TV_SCREEN, mAborterIncorrectMode);
        addHandler(Constants.MESSAGE_INITIATE_ARC, mAborterIncorrectMode);
        addHandler(Constants.MESSAGE_TERMINATE_ARC, mAborterIncorrectMode);

        addHandler(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS, mBypasser);
        addHandler(Constants.MESSAGE_GET_MENU_LANGUAGE, mBypasser);
        addHandler(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS, mBypasser);
        addHandler(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, mBypasser);
        addHandler(Constants.MESSAGE_GIVE_OSD_NAME, mBypasser);
        addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser);

        addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler);

        addHandler(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS, mBypasser);
        addHandler(Constants.MESSAGE_ABORT, mBypasser);
        addHandler(Constants.MESSAGE_GET_CEC_VERSION, mBypasser);

        addHandler(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, mAborterIncorrectMode);
        addHandler(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, mAborterIncorrectMode);
    }

    private void addHandler(int opcode, CecMessageHandler handler) {
        mCecMessageHandlers.put(opcode, handler);
    }

    /**
     * Handles the CEC message in the standby mode.
     *
     * @param message {@link HdmiCecMessage} to be processed
     * @return true if the message is handled in the handler, false means that the message is need
     *         to be dispatched to the local device.
     */
    boolean handleCommand(HdmiCecMessage message) {
        CecMessageHandler handler = mCecMessageHandlers.get(message.getOpcode());
        if (handler != null) {
            return handler.handle(message);
        }
        return mDefaultHandler.handle(message);
    }
}
+12 −0
Original line number Original line Diff line number Diff line
@@ -260,6 +260,16 @@ public final class HdmiControlService extends SystemService {
        }
        }
    }
    }


    /**
     * Called when the initialization of local devices is complete.
     */
    private void onInitializeCecComplete() {
        if (isTvDevice()) {
            mCecController.setOption(HdmiTvClient.OPTION_CEC_AUTO_WAKEUP,
                    tv().getAutoWakeup() ? HdmiTvClient.ENABLED : HdmiTvClient.DISABLED);
        }
    }

    boolean readBooleanSetting(String key, boolean defVal) {
    boolean readBooleanSetting(String key, boolean defVal) {
        ContentResolver cr = getContext().getContentResolver();
        ContentResolver cr = getContext().getContentResolver();
        return Global.getInt(cr, key, defVal ? Constants.TRUE : Constants.FALSE) == Constants.TRUE;
        return Global.getInt(cr, key, defVal ? Constants.TRUE : Constants.FALSE) == Constants.TRUE;
@@ -322,6 +332,7 @@ public final class HdmiControlService extends SystemService {
            HdmiCecLocalDevice device = devices.valueAt(i);
            HdmiCecLocalDevice device = devices.valueAt(i);
            device.handleAddressAllocated(address, fromBootup);
            device.handleAddressAllocated(address, fromBootup);
        }
        }
        onInitializeCecComplete();
    }
    }


    // Initialize HDMI port information. Combine the information from CEC and MHL HAL and
    // Initialize HDMI port information. Combine the information from CEC and MHL HAL and
@@ -996,6 +1007,7 @@ public final class HdmiControlService extends SystemService {
            }
            }
            switch (key) {
            switch (key) {
                case HdmiTvClient.OPTION_CEC_AUTO_WAKEUP:
                case HdmiTvClient.OPTION_CEC_AUTO_WAKEUP:
                    tv().setAutoWakeup(value == HdmiTvClient.ENABLED);
                    mCecController.setOption(key, value);
                    mCecController.setOption(key, value);
                    break;
                    break;
                case HdmiTvClient.OPTION_CEC_AUTO_DEVICE_OFF:
                case HdmiTvClient.OPTION_CEC_AUTO_DEVICE_OFF: