1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.hdmi; 18 19 import android.util.SparseArray; 20 21 /** 22 * This class handles the incoming messages when HdmiCecService is in the standby mode. 23 */ 24 public final class HdmiCecStandbyModeHandler { 25 26 private interface CecMessageHandler { 27 boolean handle(HdmiCecMessage message); 28 } 29 30 private static final class Bystander implements CecMessageHandler { 31 @Override 32 public boolean handle(HdmiCecMessage message) { 33 return true; 34 } 35 } 36 37 private static final class Bypasser implements CecMessageHandler { 38 @Override 39 public boolean handle(HdmiCecMessage message) { 40 return false; 41 } 42 } 43 44 private final class Aborter implements CecMessageHandler { 45 private final int mReason; 46 public Aborter(int reason) { 47 mReason = reason; 48 } 49 @Override 50 public boolean handle(HdmiCecMessage message) { 51 mService.maySendFeatureAbortCommand(message, mReason); 52 return true; 53 } 54 } 55 56 private final class AutoOnHandler implements CecMessageHandler { 57 @Override 58 public boolean handle(HdmiCecMessage message) { 59 if (!mTv.getAutoWakeup()) { 60 mAborterRefused.handle(message); 61 return true; 62 } 63 return false; 64 } 65 } 66 67 private final class UserControlProcessedHandler implements CecMessageHandler { 68 @Override 69 public boolean handle(HdmiCecMessage message) { 70 // The power status here is always standby. 71 if (HdmiCecLocalDevice.isPowerOnOrToggleCommand(message)) { 72 return false; 73 } else if (HdmiCecLocalDevice.isPowerOffOrToggleCommand(message)) { 74 return true; 75 } 76 return mAborterIncorrectMode.handle(message); 77 } 78 } 79 80 private final HdmiControlService mService; 81 private final HdmiCecLocalDeviceTv mTv; 82 83 private final SparseArray<CecMessageHandler> mCecMessageHandlers = new SparseArray<>(); 84 private final CecMessageHandler mDefaultHandler = new Aborter( 85 Constants.ABORT_UNRECOGNIZED_OPCODE); 86 private final CecMessageHandler mAborterIncorrectMode = new Aborter( 87 Constants.ABORT_NOT_IN_CORRECT_MODE); 88 private final CecMessageHandler mAborterRefused = new Aborter(Constants.ABORT_REFUSED); 89 private final CecMessageHandler mAutoOnHandler = new AutoOnHandler(); 90 private final CecMessageHandler mBypasser = new Bypasser(); 91 private final CecMessageHandler mBystander = new Bystander(); 92 private final UserControlProcessedHandler 93 mUserControlProcessedHandler = new UserControlProcessedHandler(); 94 95 public HdmiCecStandbyModeHandler(HdmiControlService service, HdmiCecLocalDeviceTv tv) { 96 mService = service; 97 mTv = tv; 98 99 addHandler(Constants.MESSAGE_IMAGE_VIEW_ON, mAutoOnHandler); 100 addHandler(Constants.MESSAGE_TEXT_VIEW_ON, mAutoOnHandler); 101 102 addHandler(Constants.MESSAGE_ACTIVE_SOURCE, mBystander); 103 addHandler(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, mBystander); 104 addHandler(Constants.MESSAGE_ROUTING_CHANGE, mBystander); 105 addHandler(Constants.MESSAGE_ROUTING_INFORMATION, mBystander); 106 addHandler(Constants.MESSAGE_SET_STREAM_PATH, mBystander); 107 addHandler(Constants.MESSAGE_STANDBY, mBystander); 108 addHandler(Constants.MESSAGE_SET_MENU_LANGUAGE, mBystander); 109 addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBystander); 110 addHandler(Constants.MESSAGE_USER_CONTROL_RELEASED, mBystander); 111 addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBystander); 112 addHandler(Constants.MESSAGE_FEATURE_ABORT, mBystander); 113 addHandler(Constants.MESSAGE_INACTIVE_SOURCE, mBystander); 114 addHandler(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, mBystander); 115 addHandler(Constants.MESSAGE_REPORT_AUDIO_STATUS, mBystander); 116 117 // If TV supports the following messages during power-on, ignore them and do nothing, 118 // else reply with <Feature Abort>["Unrecognized Opcode"] 119 // <Deck Status>, <Tuner Device Status>, <Tuner Cleared Status>, <Timer Status> 120 addHandler(Constants.MESSAGE_RECORD_STATUS, mBystander); 121 122 // If TV supports the following messages during power-on, reply with <Feature Abort>["Not 123 // in correct mode to respond"], else reply with <Feature Abort>["Unrecognized Opcode"] 124 // <Give Tuner Device Status>, <Select Digital Service>, <Tuner Step Decrement>, 125 // <Tuner Stem Increment>, <Menu Status>. 126 addHandler(Constants.MESSAGE_RECORD_TV_SCREEN, mAborterIncorrectMode); 127 addHandler(Constants.MESSAGE_INITIATE_ARC, mAborterIncorrectMode); 128 addHandler(Constants.MESSAGE_TERMINATE_ARC, mAborterIncorrectMode); 129 130 addHandler(Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS, mBypasser); 131 addHandler(Constants.MESSAGE_GET_MENU_LANGUAGE, mBypasser); 132 addHandler(Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS, mBypasser); 133 addHandler(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, mBypasser); 134 addHandler(Constants.MESSAGE_GIVE_OSD_NAME, mBypasser); 135 addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser); 136 137 addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler); 138 139 addHandler(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS, mBypasser); 140 addHandler(Constants.MESSAGE_ABORT, mBypasser); 141 addHandler(Constants.MESSAGE_GET_CEC_VERSION, mBypasser); 142 143 addHandler(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, mAborterIncorrectMode); 144 addHandler(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, mAborterIncorrectMode); 145 } 146 147 private void addHandler(int opcode, CecMessageHandler handler) { 148 mCecMessageHandlers.put(opcode, handler); 149 } 150 151 /** 152 * Handles the CEC message in the standby mode. 153 * 154 * @param message {@link HdmiCecMessage} to be processed 155 * @return true if the message is handled in the handler, false means that the message is need 156 * to be dispatched to the local device. 157 */ 158 boolean handleCommand(HdmiCecMessage message) { 159 CecMessageHandler handler = mCecMessageHandlers.get(message.getOpcode()); 160 if (handler != null) { 161 return handler.handle(message); 162 } 163 return mDefaultHandler.handle(message); 164 } 165 } 166