Loading services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +103 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,18 @@ abstract class HdmiCecLocalDevice { return handleSystemAudioModeStatus(message); case HdmiCec.MESSAGE_REPORT_AUDIO_STATUS: return handleReportAudioStatus(message); case HdmiCec.MESSAGE_STANDBY: return handleStandby(message); case HdmiCec.MESSAGE_TEXT_VIEW_ON: return handleTextViewOn(message); case HdmiCec.MESSAGE_IMAGE_VIEW_ON: return handleImageViewOn(message); case HdmiCec.MESSAGE_USER_CONTROL_PRESSED: return handleUserControlPressed(message); case HdmiCec.MESSAGE_SET_STREAM_PATH: return handleSetStreamPath(message); case HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS: return handleGiveDevicePowerStatus(message); default: return false; } Loading Loading @@ -275,6 +287,67 @@ abstract class HdmiCecLocalDevice { return false; } @ServiceThreadOnly protected boolean handleStandby(HdmiCecMessage message) { assertRunOnServiceThread(); // Seq #12 if (mService.isControlEnabled() && !isInPresetInstallationMode() && mService.isPowerOnOrTransient()) { mService.standby(); return true; } return false; } @ServiceThreadOnly protected boolean handleUserControlPressed(HdmiCecMessage message) { assertRunOnServiceThread(); final int opCode = message.getOpcode(); final byte[] params = message.getParams(); if (mService.isPowerOnOrTransient() && isPowerOffOrToggleCommand(message)) { mService.standby(); return true; } else if (mService.isPowerStandbyOrTransient() && isPowerOnOrToggleCommand(message)) { mService.wakeUp(); return true; } return false; } private static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) { byte[] params = message.getParams(); return message.getOpcode() == HdmiCec.MESSAGE_USER_CONTROL_PRESSED && params.length == 1 && (params[0] == HdmiConstants.UI_COMMAND_POWER || params[0] == HdmiConstants.UI_COMMAND_POWER_ON_FUNCTION || params[0] == HdmiConstants.UI_COMMAND_POWER_TOGGLE_FUNCTION); } private static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) { byte[] params = message.getParams(); return message.getOpcode() == HdmiCec.MESSAGE_USER_CONTROL_PRESSED && params.length == 1 && (params[0] == HdmiConstants.UI_COMMAND_POWER || params[0] == HdmiConstants.UI_COMMAND_POWER_OFF_FUNCTION || params[0] == HdmiConstants.UI_COMMAND_POWER_TOGGLE_FUNCTION); } protected boolean handleTextViewOn(HdmiCecMessage message) { return false; } protected boolean handleImageViewOn(HdmiCecMessage message) { return false; } protected boolean handleSetStreamPath(HdmiCecMessage message) { return false; } protected boolean handleGiveDevicePowerStatus(HdmiCecMessage message) { mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPowerStatus( mAddress, message.getSource(), mService.getPowerStatus())); return true; } @ServiceThreadOnly final void handleAddressAllocated(int logicalAddress) { assertRunOnServiceThread(); Loading Loading @@ -323,6 +396,10 @@ abstract class HdmiCecLocalDevice { @ServiceThreadOnly void addAndStartAction(final FeatureAction action) { assertRunOnServiceThread(); if (mService.isPowerStandbyOrTransient()) { Slog.w(TAG, "Skip the action during Standby: " + action); return; } mActions.add(action); action.start(); } Loading Loading @@ -361,6 +438,7 @@ abstract class HdmiCecLocalDevice { void removeAction(final FeatureAction action) { assertRunOnServiceThread(); mActions.remove(action); checkIfPendingActionsCleared(); } // Remove all actions matched with the given Class type. Loading @@ -383,8 +461,14 @@ abstract class HdmiCecLocalDevice { mActions.remove(action); } } checkIfPendingActionsCleared(); } protected void checkIfPendingActionsCleared() { if (mActions.isEmpty()) { mService.onPendingActionsCleared(); } } protected void assertRunOnServiceThread() { if (Looper.myLooper() != mService.getServiceLooper()) { throw new IllegalStateException("Should run on service thread."); Loading Loading @@ -488,4 +572,23 @@ abstract class HdmiCecLocalDevice { assertRunOnServiceThread(); return mService.pathToPortId(newPath); } /** * Called when the system started transition to standby mode. * * @param initiatedByCec true if this power sequence is initiated * by the reception the CEC messages like <StandBy> */ protected void onTransitionToStandby(boolean initiatedByCec) { // If there are no outstanding actions, we'll go to STANDBY state. checkIfPendingActionsCleared(); } /** * Called when the system goes to standby mode. * * @param initiatedByCec true if this power sequence is initiated * by the reception the CEC messages like <StandBy> */ protected void onStandBy(boolean initiatedByCec) {} } services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +54 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecMessage; import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; Loading @@ -29,6 +30,8 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { private static final String TAG = "HdmiCecLocalDevicePlayback"; private boolean mIsActiveSource = false; HdmiCecLocalDevicePlayback(HdmiControlService service) { super(service, HdmiCec.DEVICE_PLAYBACK); } Loading Loading @@ -93,7 +96,57 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { @ServiceThreadOnly void onHotplug(int portId, boolean connected) { assertRunOnServiceThread(); // TODO: clear devices connected to the given port id. mCecMessageCache.flushAll(); mIsActiveSource = false; if (connected && mService.isPowerStandbyOrTransient()) { mService.wakeUp(); } } @ServiceThreadOnly void markActiveSource() { assertRunOnServiceThread(); mIsActiveSource = true; } @Override @ServiceThreadOnly protected boolean handleActiveSource(HdmiCecMessage message) { assertRunOnServiceThread(); int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); if (physicalAddress != mService.getPhysicalAddress()) { mIsActiveSource = false; if (mService.isPowerOnOrTransient()) { mService.standby(); } return true; } return false; } @Override @ServiceThreadOnly protected boolean handleSetStreamPath(HdmiCecMessage message) { assertRunOnServiceThread(); int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); if (physicalAddress == mService.getPhysicalAddress()) { if (mService.isPowerStandbyOrTransient()) { mService.wakeUp(); } return true; } return false; } @Override @ServiceThreadOnly protected void onTransitionToStandby(boolean initiatedByCec) { assertRunOnServiceThread(); if (!initiatedByCec && mIsActiveSource) { mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource( mAddress, mService.getPhysicalAddress())); } mIsActiveSource = false; checkIfPendingActionsCleared(); } } services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +58 −0 Original line number Diff line number Diff line Loading @@ -441,6 +441,26 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return true; } @Override @ServiceThreadOnly protected boolean handleTextViewOn(HdmiCecMessage message) { assertRunOnServiceThread(); if (mService.isPowerStandbyOrTransient()) { mService.wakeUp(); } // TODO: Connect to Hardware input manager to invoke TV App with the appropriate channel // that represents the source device. return true; } @Override @ServiceThreadOnly protected boolean handleImageViewOn(HdmiCecMessage message) { assertRunOnServiceThread(); // Currently, it's the same as <Text View On>. return handleTextViewOn(message); } @ServiceThreadOnly private void launchDeviceDiscovery() { assertRunOnServiceThread(); Loading Loading @@ -985,4 +1005,42 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { assertRunOnServiceThread(); mAutoDeviceOff = enabled; } @Override @ServiceThreadOnly protected void onTransitionToStandby(boolean initiatedByCec) { assertRunOnServiceThread(); // Remove any repeated working actions. // HotplugDetectionAction will be reinstated during the wake up process. // HdmiControlService.onWakeUp() -> initializeLocalDevices() -> // LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery(). removeAction(HotplugDetectionAction.class); checkIfPendingActionsCleared(); } @Override @ServiceThreadOnly protected void onStandBy(boolean initiatedByCec) { assertRunOnServiceThread(); // Seq #11 if (!mService.isControlEnabled()) { return; } if (!initiatedByCec) { mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby( mAddress, HdmiCec.ADDR_BROADCAST)); } } @Override @ServiceThreadOnly protected boolean handleStandby(HdmiCecMessage message) { assertRunOnServiceThread(); // Seq #12 // Tv accepts directly addressed <Standby> only. if (message.getDestination() == mAddress) { super.handleStandby(message); } return false; } } services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +38 −0 Original line number Diff line number Diff line Loading @@ -269,6 +269,18 @@ public class HdmiCecMessageBuilder { physicalAddressToParam(physicalAddress)); } /** * Build <Inactive Source> command. * * @param src source address of command * @param physicalAddress physical address of the device to become inactive * @return newly created {@link HdmiCecMessage} */ static HdmiCecMessage buildInactiveSource(int src, int physicalAddress) { return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_INACTIVE_SOURCE, physicalAddressToParam(physicalAddress)); } /** * Build <Set Stream Path> command. * Loading Loading @@ -312,6 +324,21 @@ public class HdmiCecMessageBuilder { return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS); } /** * Build <Report Power Status> command. * * @param src source address of command * @param dest destination address of command * @param powerStatus power status of the device * @return newly created {@link HdmiCecMessage} */ static HdmiCecMessage buildReportPowerStatus(int src, int dest, int powerStatus) { byte[] param = new byte[] { (byte) (powerStatus) }; return buildCommand(src, dest, HdmiCec.MESSAGE_REPORT_POWER_STATUS, param); } /** * Build <System Audio Mode Request> command. * Loading Loading @@ -388,6 +415,17 @@ public class HdmiCecMessageBuilder { return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS); } /** * Build <Standby> command. * * @param src source address of command * @param dest destination address of command * @return newly created {@link HdmiCecMessage} */ public static HdmiCecMessage buildStandby(int src, int dest) { return buildCommand(src, dest, HdmiCec.MESSAGE_STANDBY); } /***** Please ADD new buildXXX() methods above. ******/ /** Loading services/core/java/com/android/server/hdmi/HdmiConstants.java +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ final class HdmiConstants { static final int UI_COMMAND_MUTE = 0x43; static final int UI_COMMAND_MUTE_FUNCTION = 0x65; static final int UI_COMMAND_RESTORE_VOLUME_FUNCTION = 0x66; static final int UI_COMMAND_POWER_TOGGLE_FUNCTION = 0x6B; static final int UI_COMMAND_POWER_OFF_FUNCTION = 0x6C; static final int UI_COMMAND_POWER_ON_FUNCTION = 0x6D; // Bit mask used to get the routing path of the top level device. Loading Loading
services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +103 −0 Original line number Diff line number Diff line Loading @@ -155,6 +155,18 @@ abstract class HdmiCecLocalDevice { return handleSystemAudioModeStatus(message); case HdmiCec.MESSAGE_REPORT_AUDIO_STATUS: return handleReportAudioStatus(message); case HdmiCec.MESSAGE_STANDBY: return handleStandby(message); case HdmiCec.MESSAGE_TEXT_VIEW_ON: return handleTextViewOn(message); case HdmiCec.MESSAGE_IMAGE_VIEW_ON: return handleImageViewOn(message); case HdmiCec.MESSAGE_USER_CONTROL_PRESSED: return handleUserControlPressed(message); case HdmiCec.MESSAGE_SET_STREAM_PATH: return handleSetStreamPath(message); case HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS: return handleGiveDevicePowerStatus(message); default: return false; } Loading Loading @@ -275,6 +287,67 @@ abstract class HdmiCecLocalDevice { return false; } @ServiceThreadOnly protected boolean handleStandby(HdmiCecMessage message) { assertRunOnServiceThread(); // Seq #12 if (mService.isControlEnabled() && !isInPresetInstallationMode() && mService.isPowerOnOrTransient()) { mService.standby(); return true; } return false; } @ServiceThreadOnly protected boolean handleUserControlPressed(HdmiCecMessage message) { assertRunOnServiceThread(); final int opCode = message.getOpcode(); final byte[] params = message.getParams(); if (mService.isPowerOnOrTransient() && isPowerOffOrToggleCommand(message)) { mService.standby(); return true; } else if (mService.isPowerStandbyOrTransient() && isPowerOnOrToggleCommand(message)) { mService.wakeUp(); return true; } return false; } private static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) { byte[] params = message.getParams(); return message.getOpcode() == HdmiCec.MESSAGE_USER_CONTROL_PRESSED && params.length == 1 && (params[0] == HdmiConstants.UI_COMMAND_POWER || params[0] == HdmiConstants.UI_COMMAND_POWER_ON_FUNCTION || params[0] == HdmiConstants.UI_COMMAND_POWER_TOGGLE_FUNCTION); } private static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) { byte[] params = message.getParams(); return message.getOpcode() == HdmiCec.MESSAGE_USER_CONTROL_PRESSED && params.length == 1 && (params[0] == HdmiConstants.UI_COMMAND_POWER || params[0] == HdmiConstants.UI_COMMAND_POWER_OFF_FUNCTION || params[0] == HdmiConstants.UI_COMMAND_POWER_TOGGLE_FUNCTION); } protected boolean handleTextViewOn(HdmiCecMessage message) { return false; } protected boolean handleImageViewOn(HdmiCecMessage message) { return false; } protected boolean handleSetStreamPath(HdmiCecMessage message) { return false; } protected boolean handleGiveDevicePowerStatus(HdmiCecMessage message) { mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPowerStatus( mAddress, message.getSource(), mService.getPowerStatus())); return true; } @ServiceThreadOnly final void handleAddressAllocated(int logicalAddress) { assertRunOnServiceThread(); Loading Loading @@ -323,6 +396,10 @@ abstract class HdmiCecLocalDevice { @ServiceThreadOnly void addAndStartAction(final FeatureAction action) { assertRunOnServiceThread(); if (mService.isPowerStandbyOrTransient()) { Slog.w(TAG, "Skip the action during Standby: " + action); return; } mActions.add(action); action.start(); } Loading Loading @@ -361,6 +438,7 @@ abstract class HdmiCecLocalDevice { void removeAction(final FeatureAction action) { assertRunOnServiceThread(); mActions.remove(action); checkIfPendingActionsCleared(); } // Remove all actions matched with the given Class type. Loading @@ -383,8 +461,14 @@ abstract class HdmiCecLocalDevice { mActions.remove(action); } } checkIfPendingActionsCleared(); } protected void checkIfPendingActionsCleared() { if (mActions.isEmpty()) { mService.onPendingActionsCleared(); } } protected void assertRunOnServiceThread() { if (Looper.myLooper() != mService.getServiceLooper()) { throw new IllegalStateException("Should run on service thread."); Loading Loading @@ -488,4 +572,23 @@ abstract class HdmiCecLocalDevice { assertRunOnServiceThread(); return mService.pathToPortId(newPath); } /** * Called when the system started transition to standby mode. * * @param initiatedByCec true if this power sequence is initiated * by the reception the CEC messages like <StandBy> */ protected void onTransitionToStandby(boolean initiatedByCec) { // If there are no outstanding actions, we'll go to STANDBY state. checkIfPendingActionsCleared(); } /** * Called when the system goes to standby mode. * * @param initiatedByCec true if this power sequence is initiated * by the reception the CEC messages like <StandBy> */ protected void onStandBy(boolean initiatedByCec) {} }
services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +54 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecMessage; import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; Loading @@ -29,6 +30,8 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { private static final String TAG = "HdmiCecLocalDevicePlayback"; private boolean mIsActiveSource = false; HdmiCecLocalDevicePlayback(HdmiControlService service) { super(service, HdmiCec.DEVICE_PLAYBACK); } Loading Loading @@ -93,7 +96,57 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { @ServiceThreadOnly void onHotplug(int portId, boolean connected) { assertRunOnServiceThread(); // TODO: clear devices connected to the given port id. mCecMessageCache.flushAll(); mIsActiveSource = false; if (connected && mService.isPowerStandbyOrTransient()) { mService.wakeUp(); } } @ServiceThreadOnly void markActiveSource() { assertRunOnServiceThread(); mIsActiveSource = true; } @Override @ServiceThreadOnly protected boolean handleActiveSource(HdmiCecMessage message) { assertRunOnServiceThread(); int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); if (physicalAddress != mService.getPhysicalAddress()) { mIsActiveSource = false; if (mService.isPowerOnOrTransient()) { mService.standby(); } return true; } return false; } @Override @ServiceThreadOnly protected boolean handleSetStreamPath(HdmiCecMessage message) { assertRunOnServiceThread(); int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); if (physicalAddress == mService.getPhysicalAddress()) { if (mService.isPowerStandbyOrTransient()) { mService.wakeUp(); } return true; } return false; } @Override @ServiceThreadOnly protected void onTransitionToStandby(boolean initiatedByCec) { assertRunOnServiceThread(); if (!initiatedByCec && mIsActiveSource) { mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource( mAddress, mService.getPhysicalAddress())); } mIsActiveSource = false; checkIfPendingActionsCleared(); } }
services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +58 −0 Original line number Diff line number Diff line Loading @@ -441,6 +441,26 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return true; } @Override @ServiceThreadOnly protected boolean handleTextViewOn(HdmiCecMessage message) { assertRunOnServiceThread(); if (mService.isPowerStandbyOrTransient()) { mService.wakeUp(); } // TODO: Connect to Hardware input manager to invoke TV App with the appropriate channel // that represents the source device. return true; } @Override @ServiceThreadOnly protected boolean handleImageViewOn(HdmiCecMessage message) { assertRunOnServiceThread(); // Currently, it's the same as <Text View On>. return handleTextViewOn(message); } @ServiceThreadOnly private void launchDeviceDiscovery() { assertRunOnServiceThread(); Loading Loading @@ -985,4 +1005,42 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { assertRunOnServiceThread(); mAutoDeviceOff = enabled; } @Override @ServiceThreadOnly protected void onTransitionToStandby(boolean initiatedByCec) { assertRunOnServiceThread(); // Remove any repeated working actions. // HotplugDetectionAction will be reinstated during the wake up process. // HdmiControlService.onWakeUp() -> initializeLocalDevices() -> // LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery(). removeAction(HotplugDetectionAction.class); checkIfPendingActionsCleared(); } @Override @ServiceThreadOnly protected void onStandBy(boolean initiatedByCec) { assertRunOnServiceThread(); // Seq #11 if (!mService.isControlEnabled()) { return; } if (!initiatedByCec) { mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby( mAddress, HdmiCec.ADDR_BROADCAST)); } } @Override @ServiceThreadOnly protected boolean handleStandby(HdmiCecMessage message) { assertRunOnServiceThread(); // Seq #12 // Tv accepts directly addressed <Standby> only. if (message.getDestination() == mAddress) { super.handleStandby(message); } return false; } }
services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +38 −0 Original line number Diff line number Diff line Loading @@ -269,6 +269,18 @@ public class HdmiCecMessageBuilder { physicalAddressToParam(physicalAddress)); } /** * Build <Inactive Source> command. * * @param src source address of command * @param physicalAddress physical address of the device to become inactive * @return newly created {@link HdmiCecMessage} */ static HdmiCecMessage buildInactiveSource(int src, int physicalAddress) { return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_INACTIVE_SOURCE, physicalAddressToParam(physicalAddress)); } /** * Build <Set Stream Path> command. * Loading Loading @@ -312,6 +324,21 @@ public class HdmiCecMessageBuilder { return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS); } /** * Build <Report Power Status> command. * * @param src source address of command * @param dest destination address of command * @param powerStatus power status of the device * @return newly created {@link HdmiCecMessage} */ static HdmiCecMessage buildReportPowerStatus(int src, int dest, int powerStatus) { byte[] param = new byte[] { (byte) (powerStatus) }; return buildCommand(src, dest, HdmiCec.MESSAGE_REPORT_POWER_STATUS, param); } /** * Build <System Audio Mode Request> command. * Loading Loading @@ -388,6 +415,17 @@ public class HdmiCecMessageBuilder { return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS); } /** * Build <Standby> command. * * @param src source address of command * @param dest destination address of command * @return newly created {@link HdmiCecMessage} */ public static HdmiCecMessage buildStandby(int src, int dest) { return buildCommand(src, dest, HdmiCec.MESSAGE_STANDBY); } /***** Please ADD new buildXXX() methods above. ******/ /** Loading
services/core/java/com/android/server/hdmi/HdmiConstants.java +2 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,8 @@ final class HdmiConstants { static final int UI_COMMAND_MUTE = 0x43; static final int UI_COMMAND_MUTE_FUNCTION = 0x65; static final int UI_COMMAND_RESTORE_VOLUME_FUNCTION = 0x66; static final int UI_COMMAND_POWER_TOGGLE_FUNCTION = 0x6B; static final int UI_COMMAND_POWER_OFF_FUNCTION = 0x6C; static final int UI_COMMAND_POWER_ON_FUNCTION = 0x6D; // Bit mask used to get the routing path of the top level device. Loading