From 4fd720ad1b72240269a9891c0739239620199118 Mon Sep 17 00:00:00 2001 From: Michal Olech Date: Tue, 12 May 2020 14:47:14 +0200 Subject: [PATCH] [CEC] on Routing Control Wake up the playback device and optionally send on Routing Control messages Before the change: No response to or After the change: Device wakes up (and optionally sends ) after receiving or with its physical address For better configurability, a "playback_device_action_on_routing_control" system property is introduced which controls what should be the behaviour of the device. Bug: 153950818 Test: flashed a playback device and inspected CEC messages Change-Id: I5ef3d624f5189dac91d3fd0211e16f00e7a6b77b --- .../com/android/server/hdmi/Constants.java | 17 +++ .../hdmi/HdmiCecLocalDevicePlayback.java | 49 +++++++ .../server/hdmi/HdmiCecLocalDeviceSource.java | 3 +- .../hdmi/HdmiCecLocalDevicePlaybackTest.java | 127 ++++++++++++++++++ 4 files changed, 195 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java index ac3a65310d316..694f0d6fce405 100644 --- a/services/core/java/com/android/server/hdmi/Constants.java +++ b/services/core/java/com/android/server/hdmi/Constants.java @@ -483,6 +483,23 @@ final class Constants { static final String PROPERTY_STRIP_AUDIO_TV_NO_SYSTEM_AUDIO = "persist.sys.hdmi.property_strip_audio_tv_no_system_audio"; + /** + * Determines playback device action upon receiving routing control messages. + *
    + *
  • none No action taken. + *
  • wake_up_only PowerManager.wakeUp() is called. + *
  • wake_up_and_send_active_source Same as above and + * additionally is sent. + *
+ */ + static final String PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL = + "ro.hdmi.cec.source.playback_device_action_on_routing_control"; + + static final String PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE = "none"; + static final String PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_ONLY = "wake_up_only"; + static final String PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_AND_SEND_ACTIVE_SOURCE = + "wake_up_and_send_active_source"; + static final int RECORDING_TYPE_DIGITAL_RF = 1; static final int RECORDING_TYPE_ANALOGUE_RF = 2; static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 67861c28b37e5..6f9ba182a7110 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -63,6 +63,10 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { // TODO(amyjojo): adding system constants for input ports to TIF mapping. private int mLocalActivePath = 0; + // Determines what action should be taken upon receiving Routing Control messages. + @VisibleForTesting + protected String mPlaybackDeviceActionOnRoutingControl; + HdmiCecLocalDevicePlayback(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_PLAYBACK); @@ -71,6 +75,10 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { // The option is false by default. Update settings db as well to have the right // initial setting on UI. mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, mAutoTvOff); + + mPlaybackDeviceActionOnRoutingControl = SystemProperties.get( + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL, + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE); } @Override @@ -333,6 +341,47 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { return true; } + @Override + @ServiceThreadOnly + protected boolean handleRoutingChange(HdmiCecMessage message) { + assertRunOnServiceThread(); + int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams(), 2); + handleRoutingChangeAndInformation(physicalAddress, message); + return true; + } + + @Override + @ServiceThreadOnly + protected boolean handleRoutingInformation(HdmiCecMessage message) { + assertRunOnServiceThread(); + int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); + handleRoutingChangeAndInformation(physicalAddress, message); + return true; + } + + @Override + protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) { + if (physicalAddress != mService.getPhysicalAddress()) { + return; // Do nothing. + } + switch (mPlaybackDeviceActionOnRoutingControl) { + case Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_AND_SEND_ACTIVE_SOURCE: + setAndBroadcastActiveSource(message, physicalAddress); + break; + case Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_ONLY: + mService.wakeUp(); + break; + case Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE: + break; + default: + Slog.w(TAG, "Invalid property '" + + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL + + "' value: " + + mPlaybackDeviceActionOnRoutingControl); + break; + } + } + @Override protected int findKeyReceiverAddress() { return Constants.ADDR_TV; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java index ae008b4bfa7af..5fe0be950974a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java @@ -199,7 +199,8 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice { // do nothing } - // Source device with Switch functionality should implement this method. + // Only source devices that react to routing control messages should implement + // this method (e.g. a TV with built in switch). // TODO(): decide which type will handle the routing when multi device type is supported protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) { // do nothing diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java index b76211895ab0b..f842849240088 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -15,6 +15,7 @@ */ package com.android.server.hdmi; +import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1; import static com.android.server.hdmi.Constants.ADDR_TV; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; @@ -109,6 +110,132 @@ public class HdmiCecLocalDevicePlaybackTest { mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress); } + @Test + public void handleRoutingChange_None() { + mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl = + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE; + + mWokenUp = false; + + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, + mPlaybackPhysicalAddress); + + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + mPlaybackPhysicalAddress); + + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); + mTestLooper.dispatchAll(); + assertThat(mWokenUp).isFalse(); + assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse(); + } + + @Test + public void handleRoutingInformation_None() { + mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl = + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE; + + mWokenUp = false; + + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, + mPlaybackPhysicalAddress); + + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + mPlaybackPhysicalAddress); + + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); + mTestLooper.dispatchAll(); + assertThat(mWokenUp).isFalse(); + assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse(); + } + + @Test + public void handleRoutingChange_WakeUpOnly() { + mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl = + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_ONLY; + + mWokenUp = false; + + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, + mPlaybackPhysicalAddress); + + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + mPlaybackPhysicalAddress); + + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); + mTestLooper.dispatchAll(); + assertThat(mWokenUp).isTrue(); + assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse(); + } + + @Test + public void handleRoutingInformation_WakeUpOnly() { + mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl = + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_ONLY; + + mWokenUp = false; + + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, + mPlaybackPhysicalAddress); + + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + mPlaybackPhysicalAddress); + + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); + mTestLooper.dispatchAll(); + assertThat(mWokenUp).isTrue(); + assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse(); + } + + @Test + public void handleRoutingChange_WakeUpAndSendActiveSource() { + mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl = + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_AND_SEND_ACTIVE_SOURCE; + + mWokenUp = false; + + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, + mPlaybackPhysicalAddress); + + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + mPlaybackPhysicalAddress); + + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); + mTestLooper.dispatchAll(); + assertThat(mWokenUp).isTrue(); + assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + } + + @Test + public void handleRoutingInformation_WakeUpAndSendActiveSource() { + mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl = + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_AND_SEND_ACTIVE_SOURCE; + + mWokenUp = false; + + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, + mPlaybackPhysicalAddress); + + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + mPlaybackPhysicalAddress); + + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); + mTestLooper.dispatchAll(); + assertThat(mWokenUp).isTrue(); + assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + } + // Playback device does not handle routing control related feature right now @Ignore("b/120845532") @Test