From cce6307cb819b2eadf3d3dc8c328bee3c3ae4136 Mon Sep 17 00:00:00 2001 From: Nathalie Le Clair Date: Wed, 14 Oct 2020 09:07:35 +0200 Subject: [PATCH] Playback device to turn on connected audio system when waking up Bug: 167344870 Test: atest HdmiCecLocalDevicePlaybackTest Change-Id: Ia305114762a5f356347459e3da2e3d65d860d7af --- core/java/android/provider/Settings.java | 18 +++-- .../server/hdmi/OneTouchPlayAction.java | 33 +++++++-- .../HdmiCecLocalDeviceAudioSystemTest.java | 39 +++++++++++ .../hdmi/HdmiCecLocalDevicePlaybackTest.java | 70 +++++++++++++++++++ 4 files changed, 147 insertions(+), 13 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a4c8114159d38..7fdd0c54fcfda 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9914,13 +9914,19 @@ public final class Settings { "hdmi_control_auto_device_off_enabled"; /** - * Property to decide which devices the playback device can send a message to upon - * going to sleep. Supported values are: + * Property to decide which devices the playback device can send a message to + * upon going to sleep. It additionally controls whether a playback device attempts to turn + * on the connected Audio system when waking up. Supported values are: *
    - *
  • {@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_TO_TV} to TV only.
  • - *
  • {@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_BROADCAST} to all devices in the - * network.
  • - *
  • {@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_NONE} no message sent.
  • + *
  • {@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_TO_TV} Upon going to sleep, device + * sends {@code } to TV only. Upon waking up, device does not turn on the Audio + * system via {@code }.
  • + *
  • {@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_BROADCAST} Upon going to sleep, + * device sends {@code } to all devices in the network. Upon waking up, device + * attempts to turn on the Audio system via {@code }.
  • + *
  • {@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_NONE} Upon going to sleep, device + * does not send any {@code } message. Upon waking up, device does not turn on the + * Audio system via {@code }.
  • *
* * @hide diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java index e78a86c21453c..53f9a109d08d3 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java @@ -19,6 +19,7 @@ import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback; import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; +import android.provider.Settings.Global; import android.util.Slog; import java.util.ArrayList; @@ -54,6 +55,8 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { private int mPowerStatusCounter = 0; + private HdmiCecLocalDeviceSource mSource; + // Factory method. Ensures arguments are valid. static OneTouchPlayAction create(HdmiCecLocalDeviceSource source, int targetAddress, IHdmiControlCallback callback) { @@ -74,27 +77,33 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { @Override boolean start() { + // Because only source device can create this action, it's safe to cast. + mSource = source(); sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress)); broadcastActiveSource(); + // If the device is not an audio system itself, request the connected audio system to + // turn on. + if (shouldTurnOnConnectedAudioSystem()) { + sendCommand(HdmiCecMessageBuilder.buildSystemAudioModeRequest(getSourceAddress(), + Constants.ADDR_AUDIO_SYSTEM, getSourcePath(), true)); + } queryDevicePowerStatus(); addTimer(mState, HdmiConfig.TIMEOUT_MS); return true; } private void broadcastActiveSource() { - // Because only source device can create this action, it's safe to cast. - HdmiCecLocalDeviceSource source = source(); - source.mService.setAndBroadcastActiveSourceFromOneDeviceType( + mSource.mService.setAndBroadcastActiveSourceFromOneDeviceType( mTargetAddress, getSourcePath(), "OneTouchPlayAction#broadcastActiveSource()"); // When OneTouchPlay is called, client side should be responsible to send out the intent // of which internal source, for example YouTube, it would like to switch to. // Here we only update the active port and the active source records in the local // device as well as claiming Active Source. - if (source.mService.audioSystem() != null) { - source = source.mService.audioSystem(); + if (mSource.mService.audioSystem() != null) { + mSource = mSource.mService.audioSystem(); } - source.setRoutingPort(Constants.CEC_SWITCH_HOME); - source.setLocalActivePort(Constants.CEC_SWITCH_HOME); + mSource.setRoutingPort(Constants.CEC_SWITCH_HOME); + mSource.setLocalActivePort(Constants.CEC_SWITCH_HOME); } private void queryDevicePowerStatus() { @@ -151,4 +160,14 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { Slog.e(TAG, "Callback failed:" + e); } } + + private boolean shouldTurnOnConnectedAudioSystem() { + HdmiControlService service = mSource.mService; + if (service.isAudioSystemDevice()) { + return false; + } + String sendStandbyOnSleep = service.readStringSetting( + Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP, ""); + return sendStandbyOnSleep.equals(HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST); + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java index c436cc846564b..433f6e7938e29 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -29,6 +29,7 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; +import android.hardware.hdmi.IHdmiControlCallback; import android.media.AudioManager; import android.os.Handler; import android.os.IPowerManager; @@ -834,4 +835,42 @@ public class HdmiCecLocalDeviceAudioSystemTest { assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse(); assertThat(mHdmiCecLocalDeviceAudioSystem.isActiveSource()).isFalse(); } + + @Test + @Ignore("b/151150320") + public void oneTouchPlay() { + mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) { + } + }); + mTestLooper.dispatchAll(); + + HdmiCecMessage textViewOn_fromPlayback = HdmiCecMessageBuilder.buildTextViewOn( + mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), ADDR_TV); + HdmiCecMessage activeSource_fromPlayback = HdmiCecMessageBuilder.buildActiveSource( + mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), + SELF_PHYSICAL_ADDRESS); + HdmiCecMessage systemAudioModeRequest_fromPlayback = + HdmiCecMessageBuilder.buildSystemAudioModeRequest( + mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(), + ADDR_AUDIO_SYSTEM, SELF_PHYSICAL_ADDRESS, true); + HdmiCecMessage textViewOn_fromAudioSystem = HdmiCecMessageBuilder.buildTextViewOn( + mHdmiCecLocalDeviceAudioSystem.getDeviceInfo().getLogicalAddress(), ADDR_TV); + HdmiCecMessage activeSource_fromAudioSystem = HdmiCecMessageBuilder.buildActiveSource( + mHdmiCecLocalDeviceAudioSystem.getDeviceInfo().getLogicalAddress(), + SELF_PHYSICAL_ADDRESS); + HdmiCecMessage systemAudioModeRequest_fromAudioSystem = + HdmiCecMessageBuilder.buildSystemAudioModeRequest( + mHdmiCecLocalDeviceAudioSystem.getDeviceInfo().getLogicalAddress(), + ADDR_AUDIO_SYSTEM, SELF_PHYSICAL_ADDRESS, true); + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn_fromPlayback); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource_fromPlayback); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain( + systemAudioModeRequest_fromPlayback); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn_fromAudioSystem); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource_fromAudioSystem); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain( + systemAudioModeRequest_fromAudioSystem); + } } 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 1c04d98327c95..440befcb33684 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -26,6 +26,7 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPortInfo; +import android.hardware.hdmi.IHdmiControlCallback; import android.os.Handler; import android.os.IPowerManager; import android.os.IThermalService; @@ -974,4 +975,73 @@ public class HdmiCecLocalDevicePlaybackTest { assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse(); assertThat(mStandby).isFalse(); } + + @Test + public void oneTouchPlay_SendStandbyOnSleepToTv() { + mHdmiCecLocalDevicePlayback.mService.writeStringSetting( + Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV); + mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) { + } + }); + mTestLooper.dispatchAll(); + + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress, + ADDR_TV); + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + mPlaybackLogicalAddress, mPlaybackPhysicalAddress); + HdmiCecMessage systemAudioModeRequest = HdmiCecMessageBuilder.buildSystemAudioModeRequest( + mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, mPlaybackPhysicalAddress, true); + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(systemAudioModeRequest); + } + + @Test + public void oneTouchPlay_SendStandbyOnSleepBroadcast() { + mHdmiCecLocalDevicePlayback.mService.writeStringSetting( + Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST); + mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) { + } + }); + mTestLooper.dispatchAll(); + + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress, + ADDR_TV); + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + mPlaybackLogicalAddress, mPlaybackPhysicalAddress); + HdmiCecMessage systemAudioModeRequest = HdmiCecMessageBuilder.buildSystemAudioModeRequest( + mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, mPlaybackPhysicalAddress, true); + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).contains(systemAudioModeRequest); + } + + @Test + public void oneTouchPlay_SendStandbyOnSleepNone() { + mHdmiCecLocalDevicePlayback.mService.writeStringSetting( + Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE); + mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) { + } + }); + mTestLooper.dispatchAll(); + + HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress, + ADDR_TV); + HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( + mPlaybackLogicalAddress, mPlaybackPhysicalAddress); + HdmiCecMessage systemAudioModeRequest = HdmiCecMessageBuilder.buildSystemAudioModeRequest( + mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, mPlaybackPhysicalAddress, true); + assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn); + assertThat(mNativeWrapper.getResultMessages()).contains(activeSource); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(systemAudioModeRequest); + } }