diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2020-04-27 12:26:23 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-04-27 12:26:23 +0000 |
commit | 77576fe964760d1bc381cb0dc0081dd4f599bfcc (patch) | |
tree | 04778b5dcfff7f61e89e1869454f0e7ec212e0bf | |
parent | 48a2ffac38a5b962620f118525f34aac9f46889d (diff) | |
parent | da665a67f1a60895c9df3ae9a88b9209a5aa08b7 (diff) |
Merge "CEC: Make HDMI CEC volume control configurable" into rvc-dev
13 files changed, 452 insertions, 6 deletions
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index 65a8e15ba340..6bc962b67576 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -650,6 +650,68 @@ public final class HdmiControlManager { } /** + * Controls whether volume control commands via HDMI CEC are enabled. + * + * <p>When disabled: + * <ul> + * <li>the device will not send any HDMI CEC audio messages + * <li>received HDMI CEC audio messages are responded to with {@code <Feature Abort>} + * </ul> + * + * <p>Effects on different device types: + * <table> + * <tr><th>HDMI CEC device type</th><th>enabled</th><th>disabled</th></tr> + * <tr> + * <td>TV (type: 0)</td> + * <td>Per CEC specification.</td> + * <td>TV changes system volume. TV no longer reacts to incoming volume changes via + * {@code <User Control Pressed>}. TV no longer handles {@code <Report Audio Status>} + * .</td> + * </tr> + * <tr> + * <td>Playback device (type: 4)</td> + * <td>Device sends volume commands to TV/Audio system via {@code <User Control + * Pressed>}</td><td>Device does not send volume commands via {@code <User Control + * Pressed>}.</td> + * </tr> + * <tr> + * <td>Audio device (type: 5)</td> + * <td>Full "System Audio Control" capabilities.</td> + * <td>Audio device no longer reacts to incoming {@code <User Control Pressed>} + * volume commands. Audio device no longer reports volume changes via {@code <Report + * Audio Status>}.</td> + * </tr> + * </table> + * + * <p> Due to the resulting behavior, usage on TV and Audio devices is discouraged. + * + * @param isHdmiCecVolumeControlEnabled target state of HDMI CEC volume control. + * @see Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED + * @hide + */ + @RequiresPermission(android.Manifest.permission.HDMI_CEC) + public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) { + try { + mService.setHdmiCecVolumeControlEnabled(isHdmiCecVolumeControlEnabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns whether volume changes via HDMI CEC are enabled. + * @hide + */ + @RequiresPermission(android.Manifest.permission.HDMI_CEC) + public boolean isHdmiCecVolumeControlEnabled() { + try { + return mService.isHdmiCecVolumeControlEnabled(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Gets whether the system is in system audio mode. * * @hide diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl index a8fed2b03cfc..3582a927ff46 100644 --- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl +++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl @@ -80,6 +80,8 @@ interface IHdmiControlService { void sendMhlVendorCommand(int portId, int offset, int length, in byte[] data); void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener); void setStandbyMode(boolean isStandbyModeOn); + void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled); + boolean isHdmiCecVolumeControlEnabled(); void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute); void setSystemAudioModeOnForAudioOnlySource(); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ac1998a04016..fbd6cbae47d9 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9614,6 +9614,43 @@ public final class Settings { */ public static final String HDMI_CONTROL_ENABLED = "hdmi_control_enabled"; + /** + * Controls whether volume control commands via HDMI CEC are enabled. (0 = false, 1 = + * true). + * + * <p>Effects on different device types: + * <table> + * <tr><th>HDMI CEC device type</th><th>0: disabled</th><th>1: enabled</th></tr> + * <tr> + * <td>TV (type: 0)</td> + * <td>Per CEC specification.</td> + * <td>TV changes system volume. TV no longer reacts to incoming volume changes + * via {@code <User Control Pressed>}. TV no longer handles {@code <Report Audio + * Status>}.</td> + * </tr> + * <tr> + * <td>Playback device (type: 4)</td> + * <td>Device sends volume commands to TV/Audio system via {@code <User Control + * Pressed>}</td> + * <td>Device does not send volume commands via {@code <User Control Pressed>}.</td> + * </tr> + * <tr> + * <td>Audio device (type: 5)</td> + * <td>Full "System Audio Control" capabilities.</td> + * <td>Audio device no longer reacts to incoming {@code <User Control Pressed>} + * volume commands. Audio device no longer reports volume changes via {@code + * <Report Audio Status>}.</td> + * </tr> + * </table> + * + * <p> Due to the resulting behavior, usage on TV and Audio devices is discouraged. + * + * @hide + * @see android.hardware.hdmi.HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean) + */ + public static final String HDMI_CONTROL_VOLUME_CONTROL_ENABLED = + "hdmi_control_volume_control_enabled"; + /** * Whether HDMI System Audio Control feature is enabled. If enabled, TV will try to turn on * system audio mode if there's a connected CEC-enabled AV Receiver. Then audio stream will diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java index 2141b815fb3b..7cd2f3b4c2ab 100644 --- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java +++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java @@ -354,6 +354,15 @@ public class HdmiAudioSystemClientTest { @Override public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) { } + + @Override + public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) { + } + + @Override + public boolean isHdmiCecVolumeControlEnabled() { + return true; + } } } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 03f6df0d5d2d..0dd7fb80379d 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -296,6 +296,7 @@ public class SettingsBackupTest { Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, Settings.Global.HDMI_CONTROL_ENABLED, + Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, Settings.Global.HIDDEN_API_POLICY, diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index a358707a4346..3ff6ec1afa41 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -32,6 +32,7 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.server.hdmi.Constants.LocalActivePort; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; @@ -144,7 +145,8 @@ abstract class HdmiCecLocalDevice { // A collection of FeatureAction. // Note that access to this collection should happen in service thread. - private final ArrayList<HdmiCecFeatureAction> mActions = new ArrayList<>(); + @VisibleForTesting + final ArrayList<HdmiCecFeatureAction> mActions = new ArrayList<>(); private final Handler mHandler = new Handler() { @@ -544,6 +546,8 @@ abstract class HdmiCecLocalDevice { } else if (mService.isPowerStandbyOrTransient() && isPowerOnOrToggleCommand(message)) { mService.wakeUp(); return true; + } else if (!mService.isHdmiCecVolumeControlEnabled() && isVolumeOrMuteCommand(message)) { + return false; } final long downTime = SystemClock.uptimeMillis(); @@ -618,6 +622,16 @@ abstract class HdmiCecLocalDevice { || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION); } + static boolean isVolumeOrMuteCommand(HdmiCecMessage message) { + byte[] params = message.getParams(); + return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED + && (params[0] == HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN + || params[0] == HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP + || params[0] == HdmiCecKeycode.CEC_KEYCODE_MUTE + || params[0] == HdmiCecKeycode.CEC_KEYCODE_MUTE_FUNCTION + || params[0] == HdmiCecKeycode.CEC_KEYCODE_RESTORE_VOLUME_FUNCTION); + } + protected boolean handleTextViewOn(HdmiCecMessage message) { return false; } @@ -1038,6 +1052,9 @@ abstract class HdmiCecLocalDevice { @ServiceThreadOnly protected void sendVolumeKeyEvent(int keyCode, boolean isPressed) { assertRunOnServiceThread(); + if (!mService.isHdmiCecVolumeControlEnabled()) { + return; + } if (!HdmiCecKeycode.isVolumeKeycode(keyCode)) { Slog.w(TAG, "Not a volume key: " + keyCode); return; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index e5a08d3e79aa..611b8c69077d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -575,7 +575,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { @ServiceThreadOnly protected boolean handleGiveAudioStatus(HdmiCecMessage message) { assertRunOnServiceThread(); - if (isSystemAudioControlFeatureEnabled()) { + if (isSystemAudioControlFeatureEnabled() && mService.isHdmiCecVolumeControlEnabled()) { reportAudioStatus(message.getSource()); } else { mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); @@ -930,6 +930,9 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { void reportAudioStatus(int source) { assertRunOnServiceThread(); + if (!mService.isHdmiCecVolumeControlEnabled()) { + return; + } int volume = mService.getAudioManager().getStreamVolume(AudioManager.STREAM_MUSIC); boolean mute = mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index a702ce517f40..0ac4f9ee4c6d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -678,6 +678,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly protected boolean handleReportAudioStatus(HdmiCecMessage message) { assertRunOnServiceThread(); + if (!mService.isHdmiCecVolumeControlEnabled()) { + return false; + } boolean mute = HdmiUtils.isAudioStatusMute(message); int volume = HdmiUtils.getAudioStatusVolume(message); @@ -987,7 +990,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } void setAudioStatus(boolean mute, int volume) { - if (!isSystemAudioActivated()) { + if (!isSystemAudioActivated() || !mService.isHdmiCecVolumeControlEnabled()) { return; } synchronized (mLock) { @@ -1009,7 +1012,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // On initialization process, getAvrDeviceInfo() may return null and cause exception return; } - if (delta == 0 || !isSystemAudioActivated()) { + if (delta == 0 || !isSystemAudioActivated() || !mService.isHdmiCecVolumeControlEnabled()) { return; } @@ -1038,7 +1041,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly void changeMute(boolean mute) { assertRunOnServiceThread(); - if (getAvrDeviceInfo() == null) { + if (getAvrDeviceInfo() == null || !mService.isHdmiCecVolumeControlEnabled()) { // On initialization process, getAvrDeviceInfo() may return null and cause exception return; } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index d9e30250ba2d..53f9ebcbd8dd 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -177,6 +177,10 @@ public class HdmiControlService extends SystemService { @GuardedBy("mLock") protected final ActiveSource mActiveSource = new ActiveSource(); + // Whether HDMI CEC volume control is enabled or not. + @GuardedBy("mLock") + private boolean mHdmiCecVolumeControlEnabled; + // Whether System Audio Mode is activated or not. @GuardedBy("mLock") private boolean mSystemAudioActivated = false; @@ -497,6 +501,8 @@ public class HdmiControlService extends SystemService { mPowerStatus = getInitialPowerStatus(); mProhibitMode = false; mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); + mHdmiCecVolumeControlEnabled = readBooleanSetting( + Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true); mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); if (mCecController == null) { @@ -646,6 +652,7 @@ public class HdmiControlService extends SystemService { ContentResolver resolver = getContext().getContentResolver(); String[] settings = new String[] { Global.HDMI_CONTROL_ENABLED, + Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, @@ -674,6 +681,9 @@ public class HdmiControlService extends SystemService { case Global.HDMI_CONTROL_ENABLED: setControlEnabled(enabled); break; + case Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED: + setHdmiCecVolumeControlEnabled(enabled); + break; case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: if (isTvDeviceEnabled()) { tv().setAutoWakeup(enabled); @@ -1273,7 +1283,9 @@ public class HdmiControlService extends SystemService { } void setAudioStatus(boolean mute, int volume) { - if (!isTvDeviceEnabled() || !tv().isSystemAudioActivated()) { + if (!isTvDeviceEnabled() + || !tv().isSystemAudioActivated() + || !isHdmiCecVolumeControlEnabled()) { return; } AudioManager audioManager = getAudioManager(); @@ -2187,6 +2199,24 @@ public class HdmiControlService extends SystemService { } @Override + public boolean isHdmiCecVolumeControlEnabled() { + enforceAccessPermission(); + return HdmiControlService.this.isHdmiCecVolumeControlEnabled(); + } + + @Override + public void setHdmiCecVolumeControlEnabled(final boolean isHdmiCecVolumeControlEnabled) { + enforceAccessPermission(); + runOnServiceThread(new Runnable() { + @Override + public void run() { + HdmiControlService.this.setHdmiCecVolumeControlEnabled( + isHdmiCecVolumeControlEnabled); + } + }); + } + + @Override public void reportAudioStatus(final int deviceType, final int volume, final int maxVolume, final boolean isMute) { enforceAccessPermission(); @@ -2250,6 +2280,7 @@ public class HdmiControlService extends SystemService { pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled); pw.println("mSystemAudioActivated: " + isSystemAudioActivated()); + pw.println("mHdmiCecVolumeControlEnabled " + mHdmiCecVolumeControlEnabled); pw.decreaseIndent(); pw.println("mMhlController: "); @@ -2982,6 +3013,29 @@ public class HdmiControlService extends SystemService { } } + void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) { + assertRunOnServiceThread(); + synchronized (mLock) { + mHdmiCecVolumeControlEnabled = isHdmiCecVolumeControlEnabled; + + boolean storedValue = readBooleanSetting(Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, + true); + if (storedValue != isHdmiCecVolumeControlEnabled) { + HdmiLogger.debug("Changing HDMI CEC volume control feature state: %s", + isHdmiCecVolumeControlEnabled); + writeBooleanSetting(Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, + isHdmiCecVolumeControlEnabled); + } + } + } + + boolean isHdmiCecVolumeControlEnabled() { + assertRunOnServiceThread(); + synchronized (mLock) { + return mHdmiCecVolumeControlEnabled; + } + } + boolean isProhibitMode() { synchronized (mLock) { return mProhibitMode; @@ -3022,8 +3076,12 @@ public class HdmiControlService extends SystemService { if (enabled) { enableHdmiControlService(); + setHdmiCecVolumeControlEnabled( + readBooleanSetting(Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true)); return; } + + setHdmiCecVolumeControlEnabled(false); // Call the vendor handler before the service is disabled. invokeVendorCommandListenersOnControlStateChanged(false, HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING); 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 a587029914a7..28887fdab00d 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -24,6 +24,7 @@ import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1; import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2; import static com.android.server.hdmi.Constants.ADDR_TUNER_1; import static com.android.server.hdmi.Constants.ADDR_TV; +import static com.android.server.hdmi.Constants.MESSAGE_GIVE_AUDIO_STATUS; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF; @@ -47,6 +48,7 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.ArrayList; + @SmallTest @RunWith(JUnit4.class) /** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */ @@ -167,6 +169,8 @@ public class HdmiCecLocalDeviceAudioSystemTest { } }; + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mMyLooper = mTestLooper.getLooper(); mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService); mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) { @@ -717,4 +721,112 @@ public class HdmiCecLocalDeviceAudioSystemTest { mHdmiCecLocalDeviceAudioSystem.onHotplug(0, false); assertThat(mWokenUp).isFalse(); } + + @Test + public void giveAudioStatus_volumeEnabled() { + mMusicVolume = 50; + mMusicMaxVolume = 100; + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); + + int volume = mHdmiControlService.getAudioManager() + .getStreamVolume(AudioManager.STREAM_MUSIC); + boolean mute = mHdmiControlService.getAudioManager() + .isStreamMute(AudioManager.STREAM_MUSIC); + int maxVolume = mHdmiControlService.getAudioManager() + .getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume); + HdmiCecMessage expected = HdmiCecMessageBuilder.buildReportAudioStatus(ADDR_AUDIO_SYSTEM, + ADDR_TV, scaledVolume, mute); + HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, ADDR_TV, MESSAGE_GIVE_AUDIO_STATUS, Constants.ABORT_REFUSED); + + HdmiCecMessage giveAudioStatus = HdmiCecMessageBuilder.buildGiveAudioStatus(ADDR_TV, + ADDR_AUDIO_SYSTEM); + mNativeWrapper.clearResultMessages(); + boolean handled = mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(giveAudioStatus); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).contains(expected); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbort); + assertThat(handled).isTrue(); + } + + @Test + public void giveAudioStatus_volumeDisabled() { + mMusicVolume = 50; + mMusicMaxVolume = 100; + mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); + + int volume = mHdmiControlService.getAudioManager() + .getStreamVolume(AudioManager.STREAM_MUSIC); + boolean mute = mHdmiControlService.getAudioManager() + .isStreamMute(AudioManager.STREAM_MUSIC); + int maxVolume = mHdmiControlService.getAudioManager() + .getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume); + HdmiCecMessage unexpected = HdmiCecMessageBuilder.buildReportAudioStatus(ADDR_AUDIO_SYSTEM, + ADDR_TV, scaledVolume, mute); + HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, ADDR_TV, MESSAGE_GIVE_AUDIO_STATUS, Constants.ABORT_REFUSED); + + HdmiCecMessage giveAudioStatus = HdmiCecMessageBuilder.buildGiveAudioStatus(ADDR_TV, + ADDR_AUDIO_SYSTEM); + mNativeWrapper.clearResultMessages(); + boolean handled = mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(giveAudioStatus); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(unexpected); + assertThat(handled).isTrue(); + } + + @Test + public void reportAudioStatus_volumeEnabled() { + mMusicVolume = 50; + mMusicMaxVolume = 100; + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); + + int volume = mHdmiControlService.getAudioManager() + .getStreamVolume(AudioManager.STREAM_MUSIC); + boolean mute = mHdmiControlService.getAudioManager() + .isStreamMute(AudioManager.STREAM_MUSIC); + int maxVolume = mHdmiControlService.getAudioManager() + .getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume); + HdmiCecMessage expected = HdmiCecMessageBuilder.buildReportAudioStatus(ADDR_AUDIO_SYSTEM, + ADDR_TV, scaledVolume, mute); + + mNativeWrapper.clearResultMessages(); + mHdmiCecLocalDeviceAudioSystem.reportAudioStatus(ADDR_TV); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).contains(expected); + } + + @Test + public void reportAudioStatus_volumeDisabled() { + mMusicVolume = 50; + mMusicMaxVolume = 100; + mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); + + int volume = mHdmiControlService.getAudioManager() + .getStreamVolume(AudioManager.STREAM_MUSIC); + boolean mute = mHdmiControlService.getAudioManager() + .isStreamMute(AudioManager.STREAM_MUSIC); + int maxVolume = mHdmiControlService.getAudioManager() + .getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume); + HdmiCecMessage unexpected = HdmiCecMessageBuilder.buildReportAudioStatus(ADDR_AUDIO_SYSTEM, + ADDR_TV, scaledVolume, mute); + + mNativeWrapper.clearResultMessages(); + mHdmiCecLocalDeviceAudioSystem.reportAudioStatus(ADDR_TV); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(unexpected); + } } 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 f72d622c00c3..b8394e3c1643 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat; import android.os.Looper; import android.os.test.TestLooper; +import android.view.KeyEvent; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -153,4 +154,75 @@ public class HdmiCecLocalDevicePlaybackTest { mHdmiCecLocalDevicePlayback.onHotplug(0, false); assertThat(mWokenUp).isFalse(); } + + @Test + @Ignore("b/151147315") + public void sendVolumeKeyEvent_up_volumeEnabled() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false); + + assertThat(hasSendKeyAction()).isTrue(); + } + + @Test + @Ignore("b/151147315") + public void sendVolumeKeyEvent_down_volumeEnabled() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, true); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false); + + assertThat(hasSendKeyAction()).isTrue(); + } + + @Test + @Ignore("b/151147315") + public void sendVolumeKeyEvent_mute_volumeEnabled() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, true); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false); + + assertThat(hasSendKeyAction()).isTrue(); + } + + @Test + @Ignore("b/151147315") + public void sendVolumeKeyEvent_up_volumeDisabled() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false); + + assertThat(hasSendKeyAction()).isFalse(); + } + + @Test + @Ignore("b/151147315") + public void sendVolumeKeyEvent_down_volumeDisabled() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, true); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false); + + assertThat(hasSendKeyAction()).isFalse(); + } + + @Test + @Ignore("b/151147315") + public void sendVolumeKeyEvent_mute_volumeDisabled() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, true); + mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false); + + assertThat(hasSendKeyAction()).isFalse(); + } + + private boolean hasSendKeyAction() { + boolean match = false; + for (HdmiCecFeatureAction action : mHdmiCecLocalDevicePlayback.mActions) { + if (action instanceof SendKeyAction) { + match = true; + break; + } + } + return match; + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java index 039b90429395..e0bada3138e0 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java @@ -19,6 +19,7 @@ import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV; import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM; import static com.android.server.hdmi.Constants.ADDR_BROADCAST; +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.Constants.ADDR_UNREGISTERED; import static com.android.server.hdmi.Constants.MESSAGE_DEVICE_VENDOR_ID; @@ -185,4 +186,64 @@ public class HdmiCecLocalDeviceTest { HdmiCecMessageBuilder.buildStandby(ADDR_TV, ADDR_AUDIO_SYSTEM)); assertTrue(mStandbyMessageReceived); } + + @Test + public void handleUserControlPressed_volumeUp() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + boolean result = mHdmiLocalDevice.handleUserControlPressed( + HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, + HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP)); + + assertTrue(result); + } + + @Test + public void handleUserControlPressed_volumeDown() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + boolean result = mHdmiLocalDevice.handleUserControlPressed( + HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, + HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN)); + + assertTrue(result); + } + + @Test + public void handleUserControlPressed_volumeMute() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + boolean result = mHdmiLocalDevice.handleUserControlPressed( + HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, + HdmiCecKeycode.CEC_KEYCODE_MUTE)); + + assertTrue(result); + } + + @Test + public void handleUserControlPressed_volumeUp_disabled() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + boolean result = mHdmiLocalDevice.handleUserControlPressed( + HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, + HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP)); + + assertFalse(result); + } + + @Test + public void handleUserControlPressed_volumeDown_disabled() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + boolean result = mHdmiLocalDevice.handleUserControlPressed( + HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, + HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN)); + + assertFalse(result); + } + + @Test + public void handleUserControlPressed_volumeMute_disabled() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + boolean result = mHdmiLocalDevice.handleUserControlPressed( + HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, + HdmiCecKeycode.CEC_KEYCODE_MUTE)); + + assertFalse(result); + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index fa19814f401f..7af7a23b1ef6 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -252,4 +252,13 @@ public class HdmiControlServiceTest { assertThat(mHdmiControlService.getPowerStatus()).isEqualTo( HdmiControlManager.POWER_STATUS_STANDBY); } + + @Test + public void setAndGetCecVolumeControlEnabled_isApi() { + mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isFalse(); + + mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isTrue(); + } } |