Merge "CEC: Make HDMI CEC volume control configurable" into rvc-dev
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 65a8e15..6bc962b 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -650,6 +650,68 @@
}
/**
+ * 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 a8fed2b..3582a92 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -80,6 +80,8 @@
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 ac1998a..fbd6cba 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9614,6 +9614,43 @@
*/
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 2141b81..7cd2f3b 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 @@
@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 03f6df0..0dd7fb8 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -296,6 +296,7 @@
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 a358707..3ff6ec1 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.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 @@
// 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 @@
} 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 @@
|| 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 @@
@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 e5a08d3..611b8c6 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 @@
@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 @@
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 a702ce5..0ac4f9e 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 @@
@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 @@
}
void setAudioStatus(boolean mute, int volume) {
- if (!isSystemAudioActivated()) {
+ if (!isSystemAudioActivated() || !mService.isHdmiCecVolumeControlEnabled()) {
return;
}
synchronized (mLock) {
@@ -1009,7 +1012,7 @@
// 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 @@
@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 d9e3025..53f9ebc 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 @@
@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 @@
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 @@
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 @@
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 @@
}
void setAudioStatus(boolean mute, int volume) {
- if (!isTvDeviceEnabled() || !tv().isSystemAudioActivated()) {
+ if (!isTvDeviceEnabled()
+ || !tv().isSystemAudioActivated()
+ || !isHdmiCecVolumeControlEnabled()) {
return;
}
AudioManager audioManager = getAudioManager();
@@ -2187,6 +2199,24 @@
}
@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 @@
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 @@
}
}
+ 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 @@
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 a587029..28887fd 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_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.runners.JUnit4;
import java.util.ArrayList;
+
@SmallTest
@RunWith(JUnit4.class)
/** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */
@@ -167,6 +169,8 @@
}
};
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+
mMyLooper = mTestLooper.getLooper();
mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
@@ -717,4 +721,112 @@
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 f72d622..b8394e3 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 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 @@
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 039b904..e0bada31 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 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 @@
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 fa19814..7af7a23 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 @@
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();
+ }
}