| /* | |
| * 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) { | |
| mService.maySendFeatureAbortCommand(message, mReason); | |
| 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); | |
| } | |
| } |