Merge "Add the CEC message handler for the standby mode." into lmp-dev
This commit is contained in:
@ -162,7 +162,7 @@ final class Constants {
|
||||
// Constants related to operands of HDMI CEC commands.
|
||||
// Refer to CEC Table 29 in HDMI Spec v1.4b.
|
||||
// [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_CANNOT_PROVIDE_SOURCE = 2;
|
||||
static final int ABORT_INVALID_OPERAND = 3;
|
||||
|
@ -172,7 +172,7 @@ abstract class HdmiCecLocalDevice {
|
||||
* @return true if consumed a message; otherwise, return false.
|
||||
*/
|
||||
@ServiceThreadOnly
|
||||
final boolean dispatchMessage(HdmiCecMessage message) {
|
||||
boolean dispatchMessage(HdmiCecMessage message) {
|
||||
assertRunOnServiceThread();
|
||||
int dest = message.getDestination();
|
||||
if (dest != mAddress && dest != Constants.ADDR_BROADCAST) {
|
||||
@ -309,7 +309,7 @@ abstract class HdmiCecLocalDevice {
|
||||
mService.sendCecCommand(
|
||||
HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
|
||||
message.getSource(), Constants.MESSAGE_GET_MENU_LANGUAGE,
|
||||
Constants.ABORT_UNRECOGNIZED_MODE));
|
||||
Constants.ABORT_UNRECOGNIZED_OPCODE));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -381,7 +381,7 @@ abstract class HdmiCecLocalDevice {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) {
|
||||
static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) {
|
||||
byte[] params = message.getParams();
|
||||
return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
|
||||
&& (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
|
||||
@ -389,7 +389,7 @@ abstract class HdmiCecLocalDevice {
|
||||
|| params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
|
||||
}
|
||||
|
||||
private static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) {
|
||||
static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) {
|
||||
byte[] params = message.getParams();
|
||||
return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
|
||||
&& (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER
|
||||
@ -431,7 +431,7 @@ abstract class HdmiCecLocalDevice {
|
||||
Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>");
|
||||
mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
|
||||
message.getSource(), Constants.MESSAGE_VENDOR_COMMAND_WITH_ID,
|
||||
Constants.ABORT_UNRECOGNIZED_MODE));
|
||||
Constants.ABORT_UNRECOGNIZED_OPCODE));
|
||||
} else {
|
||||
Slog.v(TAG, "Wrong broadcast vendor command. Ignoring");
|
||||
}
|
||||
@ -444,9 +444,10 @@ abstract class HdmiCecLocalDevice {
|
||||
}
|
||||
|
||||
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,
|
||||
message.getSource(), message.getOpcode(), Constants.ABORT_REFUSED));
|
||||
message.getSource(), message.getOpcode(), Constants.ABORT_CANNOT_PROVIDE_SOURCE));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -100,12 +100,15 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
|
||||
// If true, TV wakes itself up when receiving <Text/Image View On>.
|
||||
private boolean mAutoWakeup;
|
||||
|
||||
private final HdmiCecStandbyModeHandler mStandbyHandler;
|
||||
|
||||
HdmiCecLocalDeviceTv(HdmiControlService service) {
|
||||
super(service, HdmiCecDeviceInfo.DEVICE_TV);
|
||||
mPrevPortId = Constants.INVALID_PORT_ID;
|
||||
mAutoDeviceOff = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
|
||||
true);
|
||||
mAutoWakeup = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, true);
|
||||
mStandbyHandler = new HdmiCecStandbyModeHandler(service, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,6 +138,16 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
|
||||
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.
|
||||
*
|
||||
@ -787,8 +800,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
|
||||
}
|
||||
|
||||
private boolean isSystemAudioOn() {
|
||||
|
||||
|
||||
synchronized (mLock) {
|
||||
return mSystemAudioActivated;
|
||||
}
|
||||
@ -1183,6 +1194,12 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
|
||||
mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, enabled);
|
||||
}
|
||||
|
||||
@ServiceThreadOnly
|
||||
boolean getAutoWakeup() {
|
||||
assertRunOnServiceThread();
|
||||
return mAutoWakeup;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ServiceThreadOnly
|
||||
protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
|
||||
|
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -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) {
|
||||
ContentResolver cr = getContext().getContentResolver();
|
||||
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);
|
||||
device.handleAddressAllocated(address, fromBootup);
|
||||
}
|
||||
onInitializeCecComplete();
|
||||
}
|
||||
|
||||
// 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) {
|
||||
case HdmiTvClient.OPTION_CEC_AUTO_WAKEUP:
|
||||
tv().setAutoWakeup(value == HdmiTvClient.ENABLED);
|
||||
mCecController.setOption(key, value);
|
||||
break;
|
||||
case HdmiTvClient.OPTION_CEC_AUTO_DEVICE_OFF:
|
||||
|
Reference in New Issue
Block a user