Loading services/core/java/com/android/server/hdmi/Constants.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +8 −7 Original line number Original line Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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; } } Loading Loading @@ -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 Loading @@ -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 Loading Loading @@ -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"); } } Loading @@ -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; } } Loading services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +19 −2 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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. * * Loading Loading @@ -787,8 +800,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } private boolean isSystemAudioOn() { private boolean isSystemAudioOn() { synchronized (mLock) { synchronized (mLock) { return mSystemAudioActivated; return mSystemAudioActivated; } } Loading Loading @@ -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) { Loading services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java 0 → 100644 +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); } } services/core/java/com/android/server/hdmi/HdmiControlService.java +12 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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: Loading Loading
services/core/java/com/android/server/hdmi/Constants.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading
services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +8 −7 Original line number Original line Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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; } } Loading Loading @@ -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 Loading @@ -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 Loading Loading @@ -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"); } } Loading @@ -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; } } Loading
services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +19 −2 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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. * * Loading Loading @@ -787,8 +800,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } private boolean isSystemAudioOn() { private boolean isSystemAudioOn() { synchronized (mLock) { synchronized (mLock) { return mSystemAudioActivated; return mSystemAudioActivated; } } Loading Loading @@ -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) { Loading
services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java 0 → 100644 +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); } }
services/core/java/com/android/server/hdmi/HdmiControlService.java +12 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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: Loading