From 39d2938341352ba3f5765a26dee8e2ff2a2f24bf Mon Sep 17 00:00:00 2001 From: Yan Han Date: Wed, 10 May 2023 11:57:15 +0200 Subject: [PATCH 1/5] Fix system server crash on receiving This crash occurs when enabling absolute volume behavior, when we receive with an out-of-bounds volume level. This is parsed as a negative error code, which causes HdmiControlService to attempt to construct a VolumeInfo with a negative volume. This throws an IllegalArgumentException. To fix this, we ignore messages with out-of-bounds volume levels. To help prevent future issues, we also enforce that the AudioStatus object can only represent volume levels in the [0, 100] range. Bug: 281821462 Test: atest TvToAudioSystemAvcTest PlaybackDeviceToTvAvcTest PlaybackDeviceToAudioSystemAvcTest Change-Id: I31dc0fd58da511262d829a10f7f03a4f0c99c05d --- .../hdmi/AbsoluteVolumeAudioStatusAction.java | 7 ++++++ .../com/android/server/hdmi/AudioStatus.java | 4 +++- .../hdmi/BaseAbsoluteVolumeControlTest.java | 23 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java index d7563e085e614..c56517e0aaa1b 100644 --- a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java +++ b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java @@ -74,6 +74,13 @@ final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction { boolean mute = HdmiUtils.isAudioStatusMute(cmd); int volume = HdmiUtils.getAudioStatusVolume(cmd); + + // If the volume is out of range, report it as handled and ignore the message. + // According to the spec, such values are either reserved or indicate an unknown volume. + if (volume == Constants.UNKNOWN_VOLUME) { + return true; + } + AudioStatus audioStatus = new AudioStatus(volume, mute); if (mState == STATE_WAIT_FOR_INITIAL_AUDIO_STATUS) { localDevice().getService().enableAbsoluteVolumeControl(audioStatus); diff --git a/services/core/java/com/android/server/hdmi/AudioStatus.java b/services/core/java/com/android/server/hdmi/AudioStatus.java index a884ffb93a6dc..6242c45e82627 100644 --- a/services/core/java/com/android/server/hdmi/AudioStatus.java +++ b/services/core/java/com/android/server/hdmi/AudioStatus.java @@ -23,6 +23,8 @@ import java.util.Objects; /** * Immutable representation of the information in the [Audio Status] operand: * volume status (0 <= N <= 100) and mute status (muted or unmuted). + * The volume level is limited to the range [0, 100] upon construction. + * This object cannot represent an audio status where the volume is unknown, or out of bounds. */ public class AudioStatus { public static final int MAX_VOLUME = 100; @@ -32,7 +34,7 @@ public class AudioStatus { boolean mMute; public AudioStatus(int volume, boolean mute) { - mVolume = volume; + mVolume = Math.max(Math.min(volume, MAX_VOLUME), MIN_VOLUME); mMute = mute; } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java index 9f295b8f42c2f..5440e0d507dfb 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java @@ -437,6 +437,21 @@ public abstract class BaseAbsoluteVolumeControlTest { verifyAbsoluteVolumeEnabled(); } + @Test + public void giveAudioStatusSent_reportAudioStatusVolumeOutOfBounds_avcNotEnabled() { + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); + enableSystemAudioModeIfNeeded(); + receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); + + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + receiveReportAudioStatus(127, false); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + } + @Test public void avcEnabled_cecVolumeDisabled_absoluteVolumeDisabled() { enableAbsoluteVolumeControl(); @@ -512,6 +527,14 @@ public abstract class BaseAbsoluteVolumeControlTest { eq(AudioManager.ADJUST_UNMUTE), anyInt()); clearInvocations(mAudioManager); + // Volume not within range [0, 100]: sets neither volume nor mute + receiveReportAudioStatus(127, true); + verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(), + anyInt()); + verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(), + anyInt()); + clearInvocations(mAudioManager); + // If AudioService causes us to send , the System Audio device's // volume changes. Afterward, a duplicate of an earlier should // still cause us to call setStreamVolume() From 091b2e2e908c728ad948094c68ff1248b2332519 Mon Sep 17 00:00:00 2001 From: Yan Han Date: Tue, 18 Apr 2023 12:19:48 +0200 Subject: [PATCH 2/5] Rename "Absolute Volume Control" to "absolute volume behavior" Currently, the CEC framework uses "Absolute Volume Control" to refer to the state where both of the following are true: 1. The System Audio device supports the message (that is, it supports the CEC "Absolute Volume Control" feature) 2. The HDMI audio output device in AudioService uses "absolute volume behavior" This state is currently named for (1); this CL changes it to be named for (2). This is because we plan to reuse the code path for enabling this state for a new state, where (1) is not true: the System Audio device need not support /"Absolute Volume Control". In this new case, (2) will still be true, as the audio output device will use a variant of absolute volume behavior - adjust-only absolute volume behavior. Bug: 240663266 Test: make Change-Id: I679d5c1e74a1bfd8dcfe9246410ccb3089a5c5ac --- .../hdmi/AbsoluteVolumeAudioStatusAction.java | 12 +- .../server/hdmi/HdmiCecLocalDevice.java | 10 +- .../android/server/hdmi/HdmiCecNetwork.java | 8 +- .../server/hdmi/HdmiControlService.java | 115 +++++++++--------- .../android/server/hdmi/SendKeyAction.java | 4 +- .../SetAudioVolumeLevelDiscoveryAction.java | 4 +- ...va => BaseAbsoluteVolumeBehaviorTest.java} | 70 +++++------ ...> PlaybackDeviceToAudioSystemAvbTest.java} | 10 +- ...st.java => PlaybackDeviceToTvAvbTest.java} | 10 +- ...etAudioVolumeLevelDiscoveryActionTest.java | 12 +- ...cTest.java => TvToAudioSystemAvbTest.java} | 4 +- 11 files changed, 130 insertions(+), 129 deletions(-) rename services/tests/servicestests/src/com/android/server/hdmi/{BaseAbsoluteVolumeControlTest.java => BaseAbsoluteVolumeBehaviorTest.java} (92%) rename services/tests/servicestests/src/com/android/server/hdmi/{PlaybackDeviceToAudioSystemAvcTest.java => PlaybackDeviceToAudioSystemAvbTest.java} (90%) rename services/tests/servicestests/src/com/android/server/hdmi/{PlaybackDeviceToTvAvcTest.java => PlaybackDeviceToTvAvbTest.java} (90%) rename services/tests/servicestests/src/com/android/server/hdmi/{TvToAudioSystemAvcTest.java => TvToAudioSystemAvbTest.java} (91%) diff --git a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java index c56517e0aaa1b..113384f375bdb 100644 --- a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java +++ b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java @@ -18,10 +18,10 @@ package com.android.server.hdmi; /** * Action to query and track the audio status of the System Audio device when enabling or using - * Absolute Volume Control. Must be removed when AVC is disabled. Performs two main functions: - * 1. When enabling AVC: queries the starting audio status of the System Audio device and + * absolute volume behavior. Must be removed when AVB is disabled. Performs two main functions: + * 1. When enabling AVB: queries the starting audio status of the System Audio device and * enables the feature upon receiving a response. - * 2. While AVC is enabled: monitors messages from the System Audio device and + * 2. While AVB is enabled: monitors messages from the System Audio device and * notifies AudioService if the audio status changes. */ final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction { @@ -83,14 +83,14 @@ final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction { AudioStatus audioStatus = new AudioStatus(volume, mute); if (mState == STATE_WAIT_FOR_INITIAL_AUDIO_STATUS) { - localDevice().getService().enableAbsoluteVolumeControl(audioStatus); + localDevice().getService().enableAbsoluteVolumeBehavior(audioStatus); mState = STATE_MONITOR_AUDIO_STATUS; } else if (mState == STATE_MONITOR_AUDIO_STATUS) { if (audioStatus.getVolume() != mLastAudioStatus.getVolume()) { - localDevice().getService().notifyAvcVolumeChange(audioStatus.getVolume()); + localDevice().getService().notifyAvbVolumeChange(audioStatus.getVolume()); } if (audioStatus.getMute() != mLastAudioStatus.getMute()) { - localDevice().getService().notifyAvcMuteChange(audioStatus.getMute()); + localDevice().getService().notifyAvbMuteChange(audioStatus.getMute()); } } mLastAudioStatus = audioStatus; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 35c70fbce8ad8..8b2942489c7f0 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -1012,17 +1012,17 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice { action.start(); } - void addAvcAudioStatusAction(int targetAddress) { + void addAvbAudioStatusAction(int targetAddress) { if (!hasAction(AbsoluteVolumeAudioStatusAction.class)) { addAndStartAction(new AbsoluteVolumeAudioStatusAction(this, targetAddress)); } } - void removeAvcAudioStatusAction() { + void removeAvbAudioStatusAction() { removeAction(AbsoluteVolumeAudioStatusAction.class); } - void updateAvcVolume(int volumeIndex) { + void updateAvbVolume(int volumeIndex) { for (AbsoluteVolumeAudioStatusAction action : getActions(AbsoluteVolumeAudioStatusAction.class)) { action.updateVolume(volumeIndex); @@ -1035,7 +1035,7 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice { * and send (to see if it gets a in response). */ @ServiceThreadOnly - void queryAvcSupport(int targetAddress) { + void querySetAudioVolumeLevelSupport(int targetAddress) { assertRunOnServiceThread(); // Send if using CEC 2.0 or above. @@ -1054,7 +1054,7 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice { @Override public void onComplete(int result) { if (result == HdmiControlManager.RESULT_SUCCESS) { - getService().checkAndUpdateAbsoluteVolumeControlState(); + getService().checkAndUpdateAbsoluteVolumeBehavior(); } } })); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java index 18a69c8e9d81b..7045e65a89368 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java @@ -259,7 +259,7 @@ public class HdmiCecNetwork { // The addition of a local device should not notify listeners return; } - mHdmiControlService.checkAndUpdateAbsoluteVolumeControlState(); + mHdmiControlService.checkAndUpdateAbsoluteVolumeBehavior(); if (info.getPhysicalAddress() == HdmiDeviceInfo.PATH_INVALID) { // Don't notify listeners of devices that haven't reported their physical address yet return; @@ -384,7 +384,7 @@ public class HdmiCecNetwork { final void removeCecDevice(HdmiCecLocalDevice localDevice, int address) { assertRunOnServiceThread(); HdmiDeviceInfo info = removeDeviceInfo(HdmiDeviceInfo.idForCecDevice(address)); - mHdmiControlService.checkAndUpdateAbsoluteVolumeControlState(); + mHdmiControlService.checkAndUpdateAbsoluteVolumeBehavior(); localDevice.mCecMessageCache.flushMessagesFrom(address); if (info.getPhysicalAddress() == HdmiDeviceInfo.PATH_INVALID) { // Don't notify listeners of devices that haven't reported their physical address yet @@ -592,7 +592,7 @@ public class HdmiCecNetwork { updateCecDevice(newDeviceInfo); - mHdmiControlService.checkAndUpdateAbsoluteVolumeControlState(); + mHdmiControlService.checkAndUpdateAbsoluteVolumeBehavior(); } @ServiceThreadOnly @@ -625,7 +625,7 @@ public class HdmiCecNetwork { .build(); updateCecDevice(newDeviceInfo); - mHdmiControlService.checkAndUpdateAbsoluteVolumeControlState(); + mHdmiControlService.checkAndUpdateAbsoluteVolumeBehavior(); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 9cd5272b356b7..e8e9b379e74b7 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -231,8 +231,8 @@ public class HdmiControlService extends SystemService { new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_EARC, ""); - // Audio output devices used for Absolute Volume Control - private static final List AVC_AUDIO_OUTPUT_DEVICES = + // Audio output devices used for absolute volume behavior + private static final List AVB_AUDIO_OUTPUT_DEVICES = Collections.unmodifiableList(Arrays.asList(AUDIO_OUTPUT_DEVICE_HDMI, AUDIO_OUTPUT_DEVICE_HDMI_ARC, AUDIO_OUTPUT_DEVICE_HDMI_EARC)); @@ -265,7 +265,7 @@ public class HdmiControlService extends SystemService { @HdmiControlManager.VolumeControl private int mHdmiCecVolumeControl; - // Caches the volume behaviors of all audio output devices in AVC_AUDIO_OUTPUT_DEVICES. + // Caches the volume behaviors of all audio output devices in AVB_AUDIO_OUTPUT_DEVICES. @GuardedBy("mLock") private Map mAudioDeviceVolumeBehaviors = new HashMap<>(); @@ -2751,7 +2751,7 @@ public class HdmiControlService extends SystemService { pw.println("mPowerStatus: " + mPowerStatusController.getPowerStatus()); pw.println("mIsCecAvailable: " + mIsCecAvailable); pw.println("mCecVersion: " + mCecVersion); - pw.println("mIsAbsoluteVolumeControlEnabled: " + isAbsoluteVolumeControlEnabled()); + pw.println("mIsAbsoluteVolumeBehaviorEnabled: " + isAbsoluteVolumeBehaviorEnabled()); // System settings pw.println("System_settings:"); @@ -2919,7 +2919,7 @@ public class HdmiControlService extends SystemService { @HdmiControlManager.VolumeControl int hdmiCecVolumeControl) { mHdmiCecVolumeControl = hdmiCecVolumeControl; announceHdmiCecVolumeControlFeatureChange(hdmiCecVolumeControl); - runOnServiceThread(this::checkAndUpdateAbsoluteVolumeControlState); + runOnServiceThread(this::checkAndUpdateAbsoluteVolumeBehavior); } // Get the source address to send out commands to devices connected to the current device @@ -3882,7 +3882,7 @@ public class HdmiControlService extends SystemService { synchronized (mLock) { mSystemAudioActivated = on; } - runOnServiceThread(this::checkAndUpdateAbsoluteVolumeControlState); + runOnServiceThread(this::checkAndUpdateAbsoluteVolumeBehavior); } @ServiceThreadOnly @@ -3993,7 +3993,7 @@ public class HdmiControlService extends SystemService { deviceIsActiveSource, caller); } - runOnServiceThread(this::checkAndUpdateAbsoluteVolumeControlState); + runOnServiceThread(this::checkAndUpdateAbsoluteVolumeBehavior); } // This method should only be called when the device can be the active source @@ -4189,17 +4189,17 @@ public class HdmiControlService extends SystemService { /** * Listener for changes to the volume behavior of an audio output device. Caches the - * volume behavior of devices used for Absolute Volume Control. + * volume behavior of devices used for absolute volume behavior. */ @VisibleForTesting @ServiceThreadOnly void onDeviceVolumeBehaviorChanged(AudioDeviceAttributes device, int volumeBehavior) { assertRunOnServiceThread(); - if (AVC_AUDIO_OUTPUT_DEVICES.contains(device)) { + if (AVB_AUDIO_OUTPUT_DEVICES.contains(device)) { synchronized (mLock) { mAudioDeviceVolumeBehaviors.put(device, volumeBehavior); } - checkAndUpdateAbsoluteVolumeControlState(); + checkAndUpdateAbsoluteVolumeBehavior(); } } @@ -4209,7 +4209,7 @@ public class HdmiControlService extends SystemService { */ @AudioManager.DeviceVolumeBehavior private int getDeviceVolumeBehavior(AudioDeviceAttributes device) { - if (AVC_AUDIO_OUTPUT_DEVICES.contains(device)) { + if (AVB_AUDIO_OUTPUT_DEVICES.contains(device)) { synchronized (mLock) { if (mAudioDeviceVolumeBehaviors.containsKey(device)) { return mAudioDeviceVolumeBehaviors.get(device); @@ -4220,22 +4220,22 @@ public class HdmiControlService extends SystemService { } /** - * Returns whether Absolute Volume Control is enabled or not. This is determined by the + * Returns whether absolute volume behavior is enabled or not. This is determined by the * volume behavior of the relevant HDMI audio output device(s) for this device's type. */ - public boolean isAbsoluteVolumeControlEnabled() { + public boolean isAbsoluteVolumeBehaviorEnabled() { if (!isTvDevice() && !isPlaybackDevice()) { return false; } - AudioDeviceAttributes avcAudioOutputDevice = getAvcAudioOutputDevice(); - if (avcAudioOutputDevice == null) { + AudioDeviceAttributes avbAudioOutputDevice = getAvbAudioOutputDevice(); + if (avbAudioOutputDevice == null) { return false; } - return getDeviceVolumeBehavior(avcAudioOutputDevice) + return getDeviceVolumeBehavior(avbAudioOutputDevice) == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE; } - private AudioDeviceAttributes getAvcAudioOutputDevice() { + private AudioDeviceAttributes getAvbAudioOutputDevice() { if (isTvDevice()) { return tv().getSystemAudioOutputDevice(); } else if (isPlaybackDevice()) { @@ -4246,30 +4246,30 @@ public class HdmiControlService extends SystemService { } /** - * Checks the conditions for Absolute Volume Control (AVC), and enables or disables the feature - * if necessary. AVC is enabled precisely when a specific audio output device + * Checks the conditions for Absolute Volume Behavior (AVB), and enables or disables the feature + * if necessary. AVB is enabled precisely when a specific audio output device * (HDMI for playback devices, and HDMI_ARC or HDMI_EARC for TVs) is using absolute volume * behavior. * - * AVC must be enabled on a Playback device or TV precisely when it is playing + * AVB must be enabled on a Playback device or TV precisely when it is playing * audio on an external device (the System Audio device) that supports the feature. * This reduces to these conditions: * * 1. If the System Audio Device is an Audio System: System Audio Mode is active * 2. Our HDMI audio output device is using full volume behavior * 3. CEC volume is enabled - * 4. The System Audio device supports AVC (i.e. it supports ) + * 4. The System Audio device supports AVB (i.e. it supports ) * - * If not all of these conditions are met, this method disables AVC if necessary. + * If not all of these conditions are met, this method disables AVB if necessary. * * If all of these conditions are met, this method starts an action to query the System Audio - * device's audio status, which enables AVC upon obtaining the audio status. + * device's audio status, which enables AVB upon obtaining the audio status. */ @ServiceThreadOnly - void checkAndUpdateAbsoluteVolumeControlState() { + void checkAndUpdateAbsoluteVolumeBehavior() { assertRunOnServiceThread(); - // Can't enable or disable AVC before we have access to system services + // Can't set volume behavior before we have access to system services if (getAudioManager() == null) { return; } @@ -4281,20 +4281,20 @@ public class HdmiControlService extends SystemService { // (Doesn't apply to Playback Devices, where if SAM isn't active, we assume the // TV is the System Audio Device instead.) if (!isSystemAudioActivated()) { - disableAbsoluteVolumeControl(); + disableAbsoluteVolumeBehavior(); return; } } else if (isPlaybackDevice() && playback() != null) { localCecDevice = playback(); } else { - // Either this device type doesn't support AVC, or it hasn't fully initialized yet + // Either this device type doesn't support AVB, or it hasn't fully initialized yet return; } HdmiDeviceInfo systemAudioDeviceInfo = getHdmiCecNetwork().getSafeCecDeviceInfo( localCecDevice.findAudioReceiverAddress()); @AudioManager.DeviceVolumeBehavior int currentVolumeBehavior = - getDeviceVolumeBehavior(getAvcAudioOutputDevice()); + getDeviceVolumeBehavior(getAvbAudioOutputDevice()); // Condition 2: Already using full or absolute volume behavior boolean alreadyUsingFullOrAbsoluteVolume = @@ -4305,45 +4305,46 @@ public class HdmiControlService extends SystemService { getHdmiCecVolumeControl() == HdmiControlManager.VOLUME_CONTROL_ENABLED; if (!cecVolumeEnabled || !alreadyUsingFullOrAbsoluteVolume) { - disableAbsoluteVolumeControl(); + disableAbsoluteVolumeBehavior(); return; } - // Check for safety: if the System Audio device is a candidate for AVC, we should already + // Check for safety: if the System Audio device is a candidate for AVB, we should already // have received messages from it to trigger the other conditions. if (systemAudioDeviceInfo == null) { - disableAbsoluteVolumeControl(); + disableAbsoluteVolumeBehavior(); return; } - // Condition 4: The System Audio device supports AVC (i.e. ). + // Condition 4: The System Audio device supports AVB (i.e. ). switch (systemAudioDeviceInfo.getDeviceFeatures().getSetAudioVolumeLevelSupport()) { case DeviceFeatures.FEATURE_SUPPORTED: - if (!isAbsoluteVolumeControlEnabled()) { - // Start an action that will call {@link #enableAbsoluteVolumeControl} + if (!isAbsoluteVolumeBehaviorEnabled()) { + // Start an action that will call {@link #enableAbsoluteVolumeBehavior} // once the System Audio device sends - localCecDevice.addAvcAudioStatusAction( + localCecDevice.addAvbAudioStatusAction( systemAudioDeviceInfo.getLogicalAddress()); } return; case DeviceFeatures.FEATURE_NOT_SUPPORTED: - disableAbsoluteVolumeControl(); + disableAbsoluteVolumeBehavior(); return; case DeviceFeatures.FEATURE_SUPPORT_UNKNOWN: - disableAbsoluteVolumeControl(); - localCecDevice.queryAvcSupport(systemAudioDeviceInfo.getLogicalAddress()); + disableAbsoluteVolumeBehavior(); + localCecDevice.querySetAudioVolumeLevelSupport( + systemAudioDeviceInfo.getLogicalAddress()); return; default: return; } } - private void disableAbsoluteVolumeControl() { + private void disableAbsoluteVolumeBehavior() { if (isPlaybackDevice()) { - playback().removeAvcAudioStatusAction(); + playback().removeAvbAudioStatusAction(); } else if (isTvDevice()) { - tv().removeAvcAudioStatusAction(); + tv().removeAvbAudioStatusAction(); } - AudioDeviceAttributes device = getAvcAudioOutputDevice(); + AudioDeviceAttributes device = getAvbAudioOutputDevice(); if (getDeviceVolumeBehavior(device) == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) { getAudioManager().setDeviceVolumeBehavior(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); @@ -4351,11 +4352,11 @@ public class HdmiControlService extends SystemService { } /** - * Enables Absolute Volume Control. Should only be called when all the conditions for - * AVC are met (see {@link #checkAndUpdateAbsoluteVolumeControlState}). + * Enables absolute volume behavior. Should only be called when all the conditions for + * AVB are met (see {@link #checkAndUpdateAbsoluteVolumeBehavior}). * @param audioStatus The initial audio status to set the audio output device to */ - void enableAbsoluteVolumeControl(AudioStatus audioStatus) { + void enableAbsoluteVolumeBehavior(AudioStatus audioStatus) { HdmiCecLocalDevice localDevice = isPlaybackDevice() ? playback() : tv(); HdmiDeviceInfo systemAudioDevice = getHdmiCecNetwork().getDeviceInfo( localDevice.findAudioReceiverAddress()); @@ -4370,9 +4371,9 @@ public class HdmiControlService extends SystemService { // AudioService sets the volume of the stream and device based on the input VolumeInfo // when enabling absolute volume behavior, but not the mute state - notifyAvcMuteChange(audioStatus.getMute()); + notifyAvbMuteChange(audioStatus.getMute()); getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeBehavior( - getAvcAudioOutputDevice(), volumeInfo, mServiceThreadExecutor, + getAvbAudioOutputDevice(), volumeInfo, mServiceThreadExecutor, mAbsoluteVolumeChangedListener, true); } @@ -4418,8 +4419,8 @@ public class HdmiControlService extends SystemService { if (errorCode == SendMessageResult.SUCCESS) { // Update the volume tracked in our AbsoluteVolumeAudioStatusAction // so it correctly processes incoming messages - HdmiCecLocalDevice avcDevice = isTvDevice() ? tv() : playback(); - avcDevice.updateAvcVolume(volumeInfo.getVolumeIndex()); + HdmiCecLocalDevice avbDevice = isTvDevice() ? tv() : playback(); + avbDevice.updateAvbVolume(volumeInfo.getVolumeIndex()); } else { sendCecCommand(HdmiCecMessageBuilder.buildGiveAudioStatus( localDeviceAddress, @@ -4477,13 +4478,13 @@ public class HdmiControlService extends SystemService { /** * Notifies AudioService of a change in the volume of the System Audio device. Has no effect if - * AVC is disabled, or the audio output device for AVC is not playing for STREAM_MUSIC + * AVB is disabled, or the audio output device for AVB is not playing for STREAM_MUSIC */ - void notifyAvcVolumeChange(int volume) { - if (!isAbsoluteVolumeControlEnabled()) return; + void notifyAvbVolumeChange(int volume) { + if (!isAbsoluteVolumeBehaviorEnabled()) return; List streamMusicDevices = getAudioManager().getDevicesForAttributes(STREAM_MUSIC_ATTRIBUTES); - if (streamMusicDevices.contains(getAvcAudioOutputDevice())) { + if (streamMusicDevices.contains(getAvbAudioOutputDevice())) { int flags = AudioManager.FLAG_ABSOLUTE_VOLUME; if (isTvDevice()) { flags |= AudioManager.FLAG_SHOW_UI; @@ -4494,13 +4495,13 @@ public class HdmiControlService extends SystemService { /** * Notifies AudioService of a change in the mute status of the System Audio device. Has no - * effect if AVC is disabled, or the audio output device for AVC is not playing for STREAM_MUSIC + * effect if AVB is disabled, or the audio output device for AVB is not playing for STREAM_MUSIC */ - void notifyAvcMuteChange(boolean mute) { - if (!isAbsoluteVolumeControlEnabled()) return; + void notifyAvbMuteChange(boolean mute) { + if (!isAbsoluteVolumeBehaviorEnabled()) return; List streamMusicDevices = getAudioManager().getDevicesForAttributes(STREAM_MUSIC_ATTRIBUTES); - if (streamMusicDevices.contains(getAvcAudioOutputDevice())) { + if (streamMusicDevices.contains(getAvbAudioOutputDevice())) { int direction = mute ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE; int flags = AudioManager.FLAG_ABSOLUTE_VOLUME; if (isTvDevice()) { diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java index 7daeaf19c6579..2703a2c01848b 100644 --- a/services/core/java/com/android/server/hdmi/SendKeyAction.java +++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java @@ -172,10 +172,10 @@ final class SendKeyAction extends HdmiCecFeatureAction { } private void sendKeyUp() { - // When using Absolute Volume Control, query audio status after a volume key is released. + // When using absolute volume behavior, query audio status after a volume key is released. // This allows us to notify AudioService of the resulting volume or mute status changes. if (HdmiCecKeycode.isVolumeKeycode(mLastKeycode) - && localDevice().getService().isAbsoluteVolumeControlEnabled()) { + && localDevice().getService().isAbsoluteVolumeBehaviorEnabled()) { sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(), mTargetAddress), __ -> sendCommand(HdmiCecMessageBuilder.buildGiveAudioStatus( diff --git a/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java b/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java index eb3b33d8ca228..bfa8509b4e5fb 100644 --- a/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java +++ b/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java @@ -90,7 +90,7 @@ public class SetAudioVolumeLevelDiscoveryAction extends HdmiCecFeatureAction { } void handleTimerEvent(int state) { - if (updateAvcSupport(FEATURE_SUPPORTED)) { + if (updateSetAudioVolumeLevelSupport(FEATURE_SUPPORTED)) { finishWithCallback(HdmiControlManager.RESULT_SUCCESS); } else { finishWithCallback(HdmiControlManager.RESULT_EXCEPTION); @@ -104,7 +104,7 @@ public class SetAudioVolumeLevelDiscoveryAction extends HdmiCecFeatureAction { * * @return Whether support was successfully updated in the network. */ - private boolean updateAvcSupport( + private boolean updateSetAudioVolumeLevelSupport( @DeviceFeatures.FeatureSupportStatus int setAudioVolumeLevelSupport) { HdmiCecNetwork network = localDevice().mService.getHdmiCecNetwork(); HdmiDeviceInfo currentDeviceInfo = network.getCecDeviceInfo(mTargetAddress); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java similarity index 92% rename from services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java rename to services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java index 5440e0d507dfb..759b271e73eb4 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java @@ -68,19 +68,19 @@ import java.util.Arrays; import java.util.Collections; /** - * Tests that Absolute Volume Control (AVC) is enabled and disabled correctly, and that + * Tests that absolute volume behavior (AVB) is enabled and disabled correctly, and that * the device responds correctly to incoming messages and API calls - * from AudioService when AVC is active. + * from AudioService when AVB is active. * * This is an abstract base class. Concrete subclasses specify the type of the local device, and the * type of the System Audio device. This allows each test to be run for multiple setups. * * We test the following pairs of (local device, System Audio device): - * (Playback, TV): {@link PlaybackDeviceToTvAvcTest} - * (Playback, Audio System): {@link PlaybackDeviceToAudioSystemAvcTest} - * (TV, Audio System): {@link TvToAudioSystemAvcTest} + * (Playback, TV): {@link PlaybackDeviceToTvAvbTest} + * (Playback, Audio System): {@link PlaybackDeviceToAudioSystemAvbTest} + * (TV, Audio System): {@link TvToAudioSystemAvbTest} */ -public abstract class BaseAbsoluteVolumeControlTest { +public abstract class BaseAbsoluteVolumeBehaviorTest { private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private HdmiCecLocalDevice mHdmiCecLocalDevice; @@ -97,12 +97,12 @@ public abstract class BaseAbsoluteVolumeControlTest { protected FakeNativeWrapper mNativeWrapper; // Audio Status given by the System Audio device in its initial that - // triggers AVC being enabled + // triggers AVB being enabled private static final AudioStatus INITIAL_SYSTEM_AUDIO_DEVICE_STATUS = new AudioStatus(50, false); - // VolumeInfo passed to AudioDeviceVolumeManager#setDeviceAbsoluteVolumeBehavior to enable AVC - private static final VolumeInfo ENABLE_AVC_VOLUME_INFO = + // VolumeInfo passed to AudioDeviceVolumeManager#setDeviceAbsoluteVolumeBehavior to enable AVB + private static final VolumeInfo ENABLE_AVB_VOLUME_INFO = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) .setMuted(INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()) .setVolumeIndex(INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume()) @@ -300,9 +300,9 @@ public abstract class BaseAbsoluteVolumeControlTest { } /** - * Triggers all the conditions required to enable Absolute Volume Control. + * Triggers all the conditions required to enable absolute volume behavior. */ - protected void enableAbsoluteVolumeControl() { + protected void enableAbsoluteVolumeBehavior() { setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); @@ -313,8 +313,8 @@ public abstract class BaseAbsoluteVolumeControlTest { } /** - * Verifies that AVC was enabled - that is the audio output device's volume behavior was last - * set to absolute volume behavior. + * Verifies that the audio output device's volume behavior was last set to + * absolute volume behavior. */ protected void verifyAbsoluteVolumeEnabled() { InOrder inOrder = inOrder(mAudioManager, mAudioDeviceVolumeManager); @@ -325,8 +325,8 @@ public abstract class BaseAbsoluteVolumeControlTest { } /** - * Verifies that AVC was disabled - that is, the audio output device's volume behavior was - * last set to something other than absolute volume behavior. + * Verifies that the audio output device's volume behavior was last set to something other than + * absolute volume behavior. */ protected void verifyAbsoluteVolumeDisabled() { InOrder inOrder = inOrder(mAudioManager, mAudioDeviceVolumeManager); @@ -423,13 +423,13 @@ public abstract class BaseAbsoluteVolumeControlTest { } @Test - public void giveAudioStatusSent_systemAudioDeviceSendsReportAudioStatus_avcEnabled() { + public void giveAudioStatusSent_systemAudioDeviceSendsReportAudioStatus_avbEnabled() { setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); enableSystemAudioModeIfNeeded(); receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); - // Verify that AVC was never enabled + // Verify that AVB was never enabled verify(mAudioDeviceVolumeManager, never()).setDeviceAbsoluteVolumeBehavior( eq(getAudioOutputDevice()), any(), any(), any(), anyBoolean()); receiveInitialReportAudioStatus(); @@ -438,7 +438,7 @@ public abstract class BaseAbsoluteVolumeControlTest { } @Test - public void giveAudioStatusSent_reportAudioStatusVolumeOutOfBounds_avcNotEnabled() { + public void giveAudioStatusSent_reportAudioStatusVolumeOutOfBounds_avbNotEnabled() { mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); @@ -453,24 +453,24 @@ public abstract class BaseAbsoluteVolumeControlTest { } @Test - public void avcEnabled_cecVolumeDisabled_absoluteVolumeDisabled() { - enableAbsoluteVolumeControl(); + public void avbEnabled_cecVolumeDisabled_avbDisabled() { + enableAbsoluteVolumeBehavior(); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_DISABLED); verifyAbsoluteVolumeDisabled(); } @Test - public void avcEnabled_setAudioVolumeLevelNotSupported_absoluteVolumeDisabled() { - enableAbsoluteVolumeControl(); + public void avbEnabled_setAudioVolumeLevelNotSupported_avbDisabled() { + enableAbsoluteVolumeBehavior(); receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); verifyAbsoluteVolumeDisabled(); } @Test - public void avcEnabled_setAudioVolumeLevelFeatureAborted_absoluteVolumeDisabled() { - enableAbsoluteVolumeControl(); + public void avbEnabled_setAudioVolumeLevelFeatureAborted_avbDisabled() { + enableAbsoluteVolumeBehavior(); mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildFeatureAbortCommand( getSystemAudioDeviceLogicalAddress(), getLogicalAddress(), @@ -480,20 +480,20 @@ public abstract class BaseAbsoluteVolumeControlTest { } @Test - public void avcEnabled_systemAudioModeDisabled_absoluteVolumeDisabled() { + public void avbEnabled_systemAudioModeDisabled_avbDisabled() { // Only run when the System Audio device is an Audio System. assume().that(getSystemAudioDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - enableAbsoluteVolumeControl(); + enableAbsoluteVolumeBehavior(); receiveSetSystemAudioMode(false); verifyAbsoluteVolumeDisabled(); } @Test - public void avcEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges() { + public void avbEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges() { // Initial has volume=50 and mute=false - enableAbsoluteVolumeControl(); + enableAbsoluteVolumeBehavior(); // New volume and mute status: sets both receiveReportAudioStatus(20, true); @@ -540,7 +540,7 @@ public abstract class BaseAbsoluteVolumeControlTest { // still cause us to call setStreamVolume() mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged( getAudioOutputDevice(), - new VolumeInfo.Builder(ENABLE_AVC_VOLUME_INFO) + new VolumeInfo.Builder(ENABLE_AVB_VOLUME_INFO) .setVolumeIndex(20) .build() ); @@ -553,13 +553,13 @@ public abstract class BaseAbsoluteVolumeControlTest { } @Test - public void avcEnabled_audioDeviceVolumeAdjusted_sendsUserControlPressedAndGiveAudioStatus() { - enableAbsoluteVolumeControl(); + public void avbEnabled_audioDeviceVolumeAdjusted_sendsUserControlPressedAndGiveAudioStatus() { + enableAbsoluteVolumeBehavior(); mNativeWrapper.clearResultMessages(); mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeAdjusted( getAudioOutputDevice(), - ENABLE_AVC_VOLUME_INFO, + ENABLE_AVB_VOLUME_INFO, AudioManager.ADJUST_RAISE, AudioDeviceVolumeManager.ADJUST_MODE_NORMAL ); @@ -577,13 +577,13 @@ public abstract class BaseAbsoluteVolumeControlTest { } @Test - public void avcEnabled_audioDeviceVolumeChanged_sendsSetAudioVolumeLevel() { - enableAbsoluteVolumeControl(); + public void avbEnabled_audioDeviceVolumeChanged_sendsSetAudioVolumeLevel() { + enableAbsoluteVolumeBehavior(); mNativeWrapper.clearResultMessages(); mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged( getAudioOutputDevice(), - new VolumeInfo.Builder(ENABLE_AVC_VOLUME_INFO) + new VolumeInfo.Builder(ENABLE_AVB_VOLUME_INFO) .setVolumeIndex(20) .build() ); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvcTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java similarity index 90% rename from services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvcTest.java rename to services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java index 64186028e6ed2..29fc9424fc706 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvcTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java @@ -33,13 +33,13 @@ import org.junit.runners.JUnit4; import java.util.Arrays; /** - * Tests for Absolute Volume Control where the local device is a Playback device and the + * Tests for absolute volume behavior where the local device is a Playback device and the * System Audio device is an Audio System. */ @SmallTest @Presubmit @RunWith(JUnit4.class) -public class PlaybackDeviceToAudioSystemAvcTest extends BaseAbsoluteVolumeControlTest { +public class PlaybackDeviceToAudioSystemAvbTest extends BaseAbsoluteVolumeBehaviorTest { @Override protected HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService) { @@ -72,15 +72,15 @@ public class PlaybackDeviceToAudioSystemAvcTest extends BaseAbsoluteVolumeContro } /** - * AVC is disabled if the Audio System disables System Audio mode, and the TV has unknown + * AVB is disabled if the Audio System disables System Audio mode, and the TV has unknown * support for . It is enabled once the TV confirms support for * and sends . */ @Test public void switchToTv_absoluteVolumeControlDisabledUntilAllConditionsMet() { - enableAbsoluteVolumeControl(); + enableAbsoluteVolumeBehavior(); - // Audio System disables System Audio Mode. AVC should be disabled. + // Audio System disables System Audio Mode. AVB should be disabled. receiveSetSystemAudioMode(false); verifyAbsoluteVolumeDisabled(); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvcTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java similarity index 90% rename from services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvcTest.java rename to services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java index 504c3bc2626a9..19af558fb4b4a 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvcTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java @@ -34,13 +34,13 @@ import java.util.Arrays; import java.util.Collections; /** - * Tests for Absolute Volume Control where the local device is a Playback device and the + * Tests for absolute volume behavior where the local device is a Playback device and the * System Audio device is a TV. */ @SmallTest @Presubmit @RunWith(JUnit4.class) -public class PlaybackDeviceToTvAvcTest extends BaseAbsoluteVolumeControlTest { +public class PlaybackDeviceToTvAvbTest extends BaseAbsoluteVolumeBehaviorTest { @Override protected HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService) { @@ -73,15 +73,15 @@ public class PlaybackDeviceToTvAvcTest extends BaseAbsoluteVolumeControlTest { } /** - * AVC is disabled when an Audio System with unknown support for + * AVB is disabled when an Audio System with unknown support for * becomes the System Audio device. It is enabled once the Audio System reports that it * supports and sends . */ @Test public void switchToAudioSystem_absoluteVolumeControlDisabledUntilAllConditionsMet() { - enableAbsoluteVolumeControl(); + enableAbsoluteVolumeBehavior(); - // Audio System enables System Audio Mode. AVC should be disabled. + // Audio System enables System Audio Mode. AVB should be disabled. receiveSetSystemAudioMode(true); verifyAbsoluteVolumeDisabled(); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java index cac781509a930..a3d02d4fe26f0 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java @@ -152,11 +152,11 @@ public class SetAudioVolumeLevelDiscoveryActionTest { mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); mTestLooper.dispatchAll(); - @DeviceFeatures.FeatureSupportStatus int avcSupport = + @DeviceFeatures.FeatureSupportStatus int savlSupport = mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV) .getDeviceFeatures().getSetAudioVolumeLevelSupport(); - assertThat(avcSupport).isEqualTo(FEATURE_SUPPORTED); + assertThat(savlSupport).isEqualTo(FEATURE_SUPPORTED); assertThat(mTestCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); } @@ -172,11 +172,11 @@ public class SetAudioVolumeLevelDiscoveryActionTest { Constants.ABORT_UNRECOGNIZED_OPCODE)); mTestLooper.dispatchAll(); - @DeviceFeatures.FeatureSupportStatus int avcSupport = + @DeviceFeatures.FeatureSupportStatus int savlSupport = mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV) .getDeviceFeatures().getSetAudioVolumeLevelSupport(); - assertThat(avcSupport).isEqualTo(FEATURE_NOT_SUPPORTED); + assertThat(savlSupport).isEqualTo(FEATURE_NOT_SUPPORTED); assertThat(mTestCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); } @@ -189,11 +189,11 @@ public class SetAudioVolumeLevelDiscoveryActionTest { mPlaybackDevice.addAndStartAction(mAction); mTestLooper.dispatchAll(); - @DeviceFeatures.FeatureSupportStatus int avcSupport = + @DeviceFeatures.FeatureSupportStatus int savlSupport = mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV) .getDeviceFeatures().getSetAudioVolumeLevelSupport(); - assertThat(avcSupport).isEqualTo(FEATURE_SUPPORT_UNKNOWN); + assertThat(savlSupport).isEqualTo(FEATURE_SUPPORT_UNKNOWN); assertThat(mTestCallback.getResult()).isEqualTo( HdmiControlManager.RESULT_COMMUNICATION_FAILED); } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvcTest.java b/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java similarity index 91% rename from services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvcTest.java rename to services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java index 41c0e0d29879e..64b69fb1e8ba7 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvcTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java @@ -26,13 +26,13 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** - * Tests for Absolute Volume Control where the local device is a TV and the System Audio device + * Tests for absolute volume behavior where the local device is a TV and the System Audio device * is an Audio System. Assumes that the TV uses ARC (rather than eARC). */ @SmallTest @Presubmit @RunWith(JUnit4.class) -public class TvToAudioSystemAvcTest extends BaseAbsoluteVolumeControlTest { +public class TvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehaviorTest { @Override protected HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService) { From 71afeaa6f311f3683d7ced694e74a20391eb0b9e Mon Sep 17 00:00:00 2001 From: Yan Han Date: Wed, 19 Apr 2023 17:06:27 +0200 Subject: [PATCH 3/5] Add wrapper for AudioManager, allowing it to be faked in tests Makes HdmiControlService's test constructor take a wrapper for AudioManager, allowing it to be to be faked in unit tests in a similar way to AudioDeviceVolumeManager. Adds the FakeAudioFramework class, which exposes a fake for both AudioManager and AudioDeviceVolumeManager. FakeAudioFramework stores the shared internal state for both managers, simulating AudioService. Renames the existing wrapper and wrapper interface for AudioDeviceVolumeManager to make it more consistent with PowerManagerInternal. For example, instead of ThingWrapper and FakeThingWrapper implementing ThingWrapperInterface, we have DefaultThingWrapper and FakeThingWrapper implementing ThingWrapper. Bug: 217923086 Test: atest com.android.server.hdmi Change-Id: Ia9d5f7aa382223d523771b8d0382d40d622aa292 --- .../hdmi/AudioDeviceVolumeManagerWrapper.java | 57 +++-- ...ioDeviceVolumeManagerWrapperInterface.java | 61 ----- .../server/hdmi/AudioManagerWrapper.java | 105 ++++++++ ...faultAudioDeviceVolumeManagerWrapper.java} | 44 ++-- .../hdmi/DefaultAudioManagerWrapper.java | 115 +++++++++ .../server/hdmi/HdmiControlService.java | 31 ++- .../server/hdmi/VolumeControlAction.java | 2 +- .../server/hdmi/ActiveSourceActionTest.java | 15 +- .../hdmi/ArcInitiationActionFromAvrTest.java | 17 +- .../hdmi/ArcTerminationActionFromAvrTest.java | 14 +- .../hdmi/BaseAbsoluteVolumeBehaviorTest.java | 166 ++++++------- ...ectTvSystemAudioModeSupportActionTest.java | 6 +- .../hdmi/DevicePowerStatusActionTest.java | 15 +- .../DeviceSelectActionFromPlaybackTest.java | 5 +- .../hdmi/DeviceSelectActionFromTvTest.java | 5 +- .../server/hdmi/FakeAudioFramework.java | 228 ++++++++++++++++++ .../server/hdmi/HdmiCecAtomLoggingTest.java | 4 +- .../server/hdmi/HdmiCecControllerTest.java | 4 +- .../HdmiCecLocalDeviceAudioSystemTest.java | 106 ++------ .../hdmi/HdmiCecLocalDevicePlaybackTest.java | 13 +- .../server/hdmi/HdmiCecLocalDeviceTest.java | 17 +- .../server/hdmi/HdmiCecLocalDeviceTvTest.java | 22 +- .../hdmi/HdmiCecMessageValidatorTest.java | 4 +- .../server/hdmi/HdmiCecNetworkTest.java | 5 +- .../HdmiCecPowerStatusControllerTest.java | 4 +- .../server/hdmi/HdmiControlServiceTest.java | 12 +- .../hdmi/HdmiEarcLocalDeviceTxTest.java | 16 +- .../server/hdmi/OneTouchPlayActionTest.java | 16 +- .../PlaybackDeviceToAudioSystemAvbTest.java | 9 +- .../hdmi/PlaybackDeviceToTvAvbTest.java | 9 +- .../hdmi/PowerStatusMonitorActionTest.java | 16 +- .../server/hdmi/RequestSadActionTest.java | 5 +- .../server/hdmi/RoutingControlActionTest.java | 5 +- ...etAudioVolumeLevelDiscoveryActionTest.java | 4 +- .../SystemAudioAutoInitiationActionTest.java | 16 +- ...ystemAudioInitiationActionFromAvrTest.java | 36 +-- 36 files changed, 710 insertions(+), 499 deletions(-) delete mode 100644 services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapperInterface.java create mode 100644 services/core/java/com/android/server/hdmi/AudioManagerWrapper.java rename services/{tests/servicestests/src/com/android/server/hdmi/FakeAudioDeviceVolumeManagerWrapper.java => core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java} (50%) create mode 100644 services/core/java/com/android/server/hdmi/DefaultAudioManagerWrapper.java create mode 100644 services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java diff --git a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java index 438c1ea01e29f..23e6a12e590d9 100644 --- a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java +++ b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java @@ -16,9 +16,11 @@ package com.android.server.hdmi; +import static android.media.AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener; +import static android.media.AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener; + import android.annotation.CallbackExecutor; import android.annotation.NonNull; -import android.content.Context; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceVolumeManager; import android.media.VolumeInfo; @@ -26,42 +28,37 @@ import android.media.VolumeInfo; import java.util.concurrent.Executor; /** - * Wrapper for {@link AudioDeviceVolumeManager}. Creates an instance of the class and directly - * passes method calls to that instance. + * Interface with the methods from {@link AudioDeviceVolumeManager} used by the HDMI framework. + * Allows the class to be faked for tests. + * + * See implementations {@link DefaultAudioDeviceVolumeManagerWrapper} and + * {@link FakeAudioFramework.FakeAudioDeviceVolumeManagerWrapper}. */ -public class AudioDeviceVolumeManagerWrapper - implements AudioDeviceVolumeManagerWrapperInterface { +public interface AudioDeviceVolumeManagerWrapper { - private static final String TAG = "AudioDeviceVolumeManagerWrapper"; - - private final AudioDeviceVolumeManager mAudioDeviceVolumeManager; - - public AudioDeviceVolumeManagerWrapper(Context context) { - mAudioDeviceVolumeManager = new AudioDeviceVolumeManager(context); - } - - @Override - public void addOnDeviceVolumeBehaviorChangedListener( + /** + * Wrapper for {@link AudioDeviceVolumeManager#addOnDeviceVolumeBehaviorChangedListener( + * Executor, OnDeviceVolumeBehaviorChangedListener)} + */ + void addOnDeviceVolumeBehaviorChangedListener( @NonNull @CallbackExecutor Executor executor, - @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener) - throws SecurityException { - mAudioDeviceVolumeManager.addOnDeviceVolumeBehaviorChangedListener(executor, listener); - } + @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener); - @Override - public void removeOnDeviceVolumeBehaviorChangedListener( - @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener) { - mAudioDeviceVolumeManager.removeOnDeviceVolumeBehaviorChangedListener(listener); - } + /** + * Wrapper for {@link AudioDeviceVolumeManager#removeOnDeviceVolumeBehaviorChangedListener( + * OnDeviceVolumeBehaviorChangedListener)} + */ + void removeOnDeviceVolumeBehaviorChangedListener( + @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener); - @Override - public void setDeviceAbsoluteVolumeBehavior( + /** + * Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeBehavior( + * AudioDeviceAttributes, VolumeInfo, Executor, OnAudioDeviceVolumeChangedListener, boolean)} + */ + void setDeviceAbsoluteVolumeBehavior( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, @NonNull @CallbackExecutor Executor executor, @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment) { - mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeBehavior(device, volume, executor, - vclistener, handlesVolumeAdjustment); - } + boolean handlesVolumeAdjustment); } diff --git a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapperInterface.java b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapperInterface.java deleted file mode 100644 index 1a1d4c19358be..0000000000000 --- a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapperInterface.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.hdmi; - -import static android.media.AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener; -import static android.media.AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener; - -import android.annotation.CallbackExecutor; -import android.annotation.NonNull; -import android.media.AudioDeviceAttributes; -import android.media.AudioDeviceVolumeManager; -import android.media.VolumeInfo; - -import java.util.concurrent.Executor; - -/** - * Interface with the methods from {@link AudioDeviceVolumeManager} used by the HDMI framework. - * Allows the class to be faked for tests. - */ -public interface AudioDeviceVolumeManagerWrapperInterface { - - /** - * Wrapper for {@link AudioDeviceVolumeManager#addOnDeviceVolumeBehaviorChangedListener( - * Executor, OnDeviceVolumeBehaviorChangedListener)} - */ - void addOnDeviceVolumeBehaviorChangedListener( - @NonNull @CallbackExecutor Executor executor, - @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener); - - /** - * Wrapper for {@link AudioDeviceVolumeManager#removeOnDeviceVolumeBehaviorChangedListener( - * OnDeviceVolumeBehaviorChangedListener)} - */ - void removeOnDeviceVolumeBehaviorChangedListener( - @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener); - - /** - * Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeBehavior( - * AudioDeviceAttributes, VolumeInfo, Executor, OnAudioDeviceVolumeChangedListener, boolean)} - */ - void setDeviceAbsoluteVolumeBehavior( - @NonNull AudioDeviceAttributes device, - @NonNull VolumeInfo volume, - @NonNull @CallbackExecutor Executor executor, - @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment); -} diff --git a/services/core/java/com/android/server/hdmi/AudioManagerWrapper.java b/services/core/java/com/android/server/hdmi/AudioManagerWrapper.java new file mode 100644 index 0000000000000..fd4dd516fd517 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/AudioManagerWrapper.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import android.annotation.NonNull; +import android.media.AudioAttributes; +import android.media.AudioDeviceAttributes; +import android.media.AudioDeviceVolumeManager; +import android.media.AudioManager; + +import java.util.List; + +/** + * Interface with the methods from {@link AudioDeviceVolumeManager} used by the HDMI control + * framework. Allows the class to be faked for tests. + * + * See implementations {@link DefaultAudioManagerWrapper} and + * {@link FakeAudioFramework.FakeAudioManagerWrapper}. + */ +public interface AudioManagerWrapper { + + /** + * Wraps {@link AudioManager#adjustStreamVolume(int, int, int)} + */ + void adjustStreamVolume(int streamType, int direction, + @AudioManager.PublicVolumeFlags int flags); + + /** + * Wraps {@link AudioManager#setStreamVolume(int, int, int)} + */ + void setStreamVolume(int streamType, int index, @AudioManager.PublicVolumeFlags int flags); + + /** + * Wraps {@link AudioManager#getStreamVolume(int)} + */ + int getStreamVolume(int streamType); + + /** + * Wraps {@link AudioManager#getStreamMinVolume(int)} + */ + int getStreamMinVolume(int streamType); + + /** + * Wraps {@link AudioManager#getStreamMaxVolume(int)} + */ + int getStreamMaxVolume(int streamType); + + /** + * Wraps {@link AudioManager#isStreamMute(int)} + */ + boolean isStreamMute(int streamType); + + /** + * Wraps {@link AudioManager#setStreamMute(int, boolean)} + */ + void setStreamMute(int streamType, boolean state); + + /** + * Wraps {@link AudioManager#setHdmiSystemAudioSupported(boolean)} + */ + int setHdmiSystemAudioSupported(boolean on); + + /** + * Wraps {@link AudioManager#setWiredDeviceConnectionState(AudioDeviceAttributes, int)} + */ + void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state); + + /** + * Wraps {@link AudioManager#setWiredDeviceConnectionState(int, int, String, String)} + */ + void setWiredDeviceConnectionState(int device, int state, String address, String name); + + /** + * Wraps {@link AudioManager#getDeviceVolumeBehavior(AudioDeviceAttributes)} + */ + @AudioManager.DeviceVolumeBehavior + int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device); + + /** + * Wraps {@link AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)} + */ + void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device, + @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior); + + /** + * Wraps {@link AudioManager#getDevicesForAttributes(AudioAttributes)} + */ + @NonNull + List getDevicesForAttributes( + @NonNull AudioAttributes attributes); +} diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java similarity index 50% rename from services/tests/servicestests/src/com/android/server/hdmi/FakeAudioDeviceVolumeManagerWrapper.java rename to services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java index d33ef9bc88799..b9a78c93989f5 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioDeviceVolumeManagerWrapper.java +++ b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,44 +16,45 @@ package com.android.server.hdmi; -import static android.media.AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener; -import static android.media.AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener; - import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.content.Context; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceVolumeManager; -import android.media.AudioManager; import android.media.VolumeInfo; -import java.util.HashSet; -import java.util.Set; import java.util.concurrent.Executor; /** - * Wrapper for {@link AudioDeviceVolumeManager} that stubs its methods. Useful for testing. + * "Default" wrapper for {@link AudioDeviceVolumeManager}, as opposed to a "Fake" wrapper for + * testing - see {@link FakeAudioFramework.FakeAudioDeviceVolumeManagerWrapper}. + * + * Creates an instance of {@link AudioDeviceVolumeManager} and directly passes method calls + * to that instance. */ -public class FakeAudioDeviceVolumeManagerWrapper implements - AudioDeviceVolumeManagerWrapperInterface { +public class DefaultAudioDeviceVolumeManagerWrapper + implements AudioDeviceVolumeManagerWrapper { - private final Set mVolumeBehaviorListeners; + private static final String TAG = "AudioDeviceVolumeManagerWrapper"; - public FakeAudioDeviceVolumeManagerWrapper() { - mVolumeBehaviorListeners = new HashSet<>(); + private final AudioDeviceVolumeManager mAudioDeviceVolumeManager; + + public DefaultAudioDeviceVolumeManagerWrapper(Context context) { + mAudioDeviceVolumeManager = new AudioDeviceVolumeManager(context); } @Override public void addOnDeviceVolumeBehaviorChangedListener( @NonNull @CallbackExecutor Executor executor, - @NonNull OnDeviceVolumeBehaviorChangedListener listener) + @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener) throws SecurityException { - mVolumeBehaviorListeners.add(listener); + mAudioDeviceVolumeManager.addOnDeviceVolumeBehaviorChangedListener(executor, listener); } @Override public void removeOnDeviceVolumeBehaviorChangedListener( - @NonNull OnDeviceVolumeBehaviorChangedListener listener) { - mVolumeBehaviorListeners.remove(listener); + @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener) { + mAudioDeviceVolumeManager.removeOnDeviceVolumeBehaviorChangedListener(listener); } @Override @@ -61,12 +62,9 @@ public class FakeAudioDeviceVolumeManagerWrapper implements @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, @NonNull @CallbackExecutor Executor executor, - @NonNull OnAudioDeviceVolumeChangedListener vclistener, + @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, boolean handlesVolumeAdjustment) { - // Notify all volume behavior listeners that the device adopted absolute volume behavior - for (OnDeviceVolumeBehaviorChangedListener listener : mVolumeBehaviorListeners) { - listener.onDeviceVolumeBehaviorChanged(device, - AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); - } + mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeBehavior(device, volume, executor, + vclistener, handlesVolumeAdjustment); } } diff --git a/services/core/java/com/android/server/hdmi/DefaultAudioManagerWrapper.java b/services/core/java/com/android/server/hdmi/DefaultAudioManagerWrapper.java new file mode 100644 index 0000000000000..061e145c27f37 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/DefaultAudioManagerWrapper.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import android.annotation.NonNull; +import android.content.Context; +import android.media.AudioAttributes; +import android.media.AudioDeviceAttributes; +import android.media.AudioManager; + +import java.util.List; + +/** + * "Default" wrapper for {@link AudioManager}, as opposed to a "Fake" wrapper for testing - + * see {@link FakeAudioFramework.FakeAudioManagerWrapper}. + * + * Creates an instance of {@link AudioManager} and directly passes method calls to that instance. + * +*/ +public class DefaultAudioManagerWrapper implements AudioManagerWrapper { + + private static final String TAG = "DefaultAudioManagerWrapper"; + + private final AudioManager mAudioManager; + + public DefaultAudioManagerWrapper(Context context) { + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + } + + @Override + public void adjustStreamVolume(int streamType, int direction, + @AudioManager.PublicVolumeFlags int flags) { + mAudioManager.adjustStreamVolume(streamType, direction, flags); + } + + @Override + public void setStreamVolume(int streamType, int index, + @AudioManager.PublicVolumeFlags int flags) { + mAudioManager.setStreamVolume(streamType, index, flags); + } + + @Override + public int getStreamVolume(int streamType) { + return mAudioManager.getStreamVolume(streamType); + } + + @Override + public int getStreamMinVolume(int streamType) { + return mAudioManager.getStreamMinVolume(streamType); + } + + @Override + public int getStreamMaxVolume(int streamType) { + return mAudioManager.getStreamMaxVolume(streamType); + } + + @Override + public boolean isStreamMute(int streamType) { + return mAudioManager.isStreamMute(streamType); + } + + @Override + public void setStreamMute(int streamType, boolean state) { + mAudioManager.setStreamMute(streamType, state); + } + + @Override + public int setHdmiSystemAudioSupported(boolean on) { + return mAudioManager.setHdmiSystemAudioSupported(on); + } + + @Override + public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) { + mAudioManager.setWiredDeviceConnectionState(attributes, state); + } + + @Override + public void setWiredDeviceConnectionState(int device, int state, String address, String name) { + mAudioManager.setWiredDeviceConnectionState(device, state, address, name); + } + + @Override + @AudioManager.DeviceVolumeBehavior + public int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { + return mAudioManager.getDeviceVolumeBehavior(device); + } + + @Override + public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device, + @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior) { + mAudioManager.setDeviceVolumeBehavior(device, deviceVolumeBehavior); + } + + @Override + @NonNull + public List getDevicesForAttributes( + @NonNull AudioAttributes attributes) { + return mAudioManager.getDevicesForAttributes(attributes); + } + +} diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index e8e9b379e74b7..741e730da0221 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -491,10 +491,10 @@ public class HdmiControlService extends SystemService { private PowerManagerInternalWrapper mPowerManagerInternal; @Nullable - private AudioManager mAudioManager; + private AudioManagerWrapper mAudioManager; @Nullable - private AudioDeviceVolumeManagerWrapperInterface mAudioDeviceVolumeManager; + private AudioDeviceVolumeManagerWrapper mAudioDeviceVolumeManager; @Nullable private Looper mIoLooper; @@ -528,18 +528,20 @@ public class HdmiControlService extends SystemService { /** * Constructor for testing. * - * It's critical to use a fake AudioDeviceVolumeManager because a normally instantiated - * AudioDeviceVolumeManager can access the "real" AudioService on the DUT. + * Takes fakes for AudioManager and AudioDeviceVolumeManager. * - * @see FakeAudioDeviceVolumeManagerWrapper + * This is especially important for AudioDeviceVolumeManager because a normally instantiated + * AudioDeviceVolumeManager can access the "real" AudioService on the DUT. */ @VisibleForTesting HdmiControlService(Context context, List deviceTypes, - AudioDeviceVolumeManagerWrapperInterface audioDeviceVolumeManager) { + AudioManagerWrapper audioManager, + AudioDeviceVolumeManagerWrapper audioDeviceVolumeManager) { super(context); mCecLocalDevices = deviceTypes; mSettingsObserver = new SettingsObserver(mHandler); mHdmiCecConfig = new HdmiCecConfig(context); mDeviceConfig = new DeviceConfigWrapper(); + mAudioManager = audioManager; mAudioDeviceVolumeManager = audioDeviceVolumeManager; } @@ -933,11 +935,6 @@ public class HdmiControlService extends SystemService { return HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; } - @VisibleForTesting - void setAudioManager(AudioManager audioManager) { - mAudioManager = audioManager; - } - @VisibleForTesting void setCecController(HdmiCecController cecController) { mCecController = cecController; @@ -975,11 +972,13 @@ public class HdmiControlService extends SystemService { Context.TV_INPUT_SERVICE); mPowerManager = new PowerManagerWrapper(getContext()); mPowerManagerInternal = new PowerManagerInternalWrapper(); - mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); + if (mAudioManager == null) { + mAudioManager = new DefaultAudioManagerWrapper(getContext()); + } mStreamMusicMaxVolume = getAudioManager().getStreamMaxVolume(AudioManager.STREAM_MUSIC); if (mAudioDeviceVolumeManager == null) { mAudioDeviceVolumeManager = - new AudioDeviceVolumeManagerWrapper(getContext()); + new DefaultAudioDeviceVolumeManagerWrapper(getContext()); } getAudioDeviceVolumeManager().addOnDeviceVolumeBehaviorChangedListener( mServiceThreadExecutor, this::onDeviceVolumeBehaviorChanged); @@ -1773,7 +1772,7 @@ public class HdmiControlService extends SystemService { == HdmiControlManager.VOLUME_CONTROL_DISABLED) { return; } - AudioManager audioManager = getAudioManager(); + AudioManagerWrapper audioManager = getAudioManager(); boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); if (mute) { if (!muted) { @@ -3485,7 +3484,7 @@ public class HdmiControlService extends SystemService { * Returns null before the boot phase {@link SystemService#PHASE_SYSTEM_SERVICES_READY}. */ @Nullable - AudioManager getAudioManager() { + AudioManagerWrapper getAudioManager() { return mAudioManager; } @@ -3493,7 +3492,7 @@ public class HdmiControlService extends SystemService { * Returns null before the boot phase {@link SystemService#PHASE_SYSTEM_SERVICES_READY}. */ @Nullable - private AudioDeviceVolumeManagerWrapperInterface getAudioDeviceVolumeManager() { + private AudioDeviceVolumeManagerWrapper getAudioDeviceVolumeManager() { return mAudioDeviceVolumeManager; } diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java index d5761e170d1af..30b188c5dd789 100644 --- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java +++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java @@ -159,7 +159,7 @@ final class VolumeControlAction extends HdmiCecFeatureAction { // Update audio status if current volume position is edge of volume bar, // i.e max or min volume. - AudioManager audioManager = tv().getService().getAudioManager(); + AudioManagerWrapper audioManager = tv().getService().getAudioManager(); int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); if (mIsVolumeUp) { int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java index ad1ecf1ad1c8e..da082682e9128 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.spy; import android.content.Context; import android.content.ContextWrapper; -import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -61,19 +60,9 @@ public class ActiveSourceActionTest { public void setUp() throws Exception { mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); + FakeAudioFramework audioFramework = new FakeAudioFramework(); mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList(), - new FakeAudioDeviceVolumeManagerWrapper()) { - @Override - AudioManager getAudioManager() { - return new AudioManager() { - @Override - public void setWiredDeviceConnectionState( - int type, int state, String address, String name) { - // Do nothing. - } - }; - } - + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isPowerStandby() { return false; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java index 3df0449c14b7a..5be3c8e4671cf 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java @@ -25,7 +25,6 @@ import static org.mockito.Mockito.spy; import android.content.Context; import android.content.ContextWrapper; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -37,8 +36,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Collections; @@ -58,27 +55,21 @@ public class ArcInitiationActionFromAvrTest { private TestLooper mTestLooper = new TestLooper(); private ArrayList mLocalDevices = new ArrayList<>(); - @Mock - private AudioManager mAudioManager; - @Before public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + HdmiControlService hdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList(), - new FakeAudioDeviceVolumeManagerWrapper()) { + audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isPowerStandby() { return false; } - @Override - AudioManager getAudioManager() { - return mAudioManager; - } @Override boolean isAddressAllocated() { diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java index 61ab99b1d017a..7845c307c15f3 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java @@ -27,7 +27,6 @@ import android.content.ContextWrapper; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -39,7 +38,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; @@ -61,8 +59,6 @@ public class ArcTerminationActionFromAvrTest { private TestLooper mTestLooper = new TestLooper(); private ArrayList mLocalDevices = new ArrayList<>(); - @Mock - private AudioManager mAudioManager; @Before public void setUp() throws Exception { @@ -70,14 +66,12 @@ public class ArcTerminationActionFromAvrTest { mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + HdmiControlService hdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList(), - new FakeAudioDeviceVolumeManagerWrapper()) { - @Override - AudioManager getAudioManager() { - return mAudioManager; - } - + audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isPowerStandby() { return false; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java index 759b271e73eb4..fa8927e683dcc 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java @@ -24,16 +24,11 @@ import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_BOOT_UP; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.TruthJUnit.assume; -import static org.mockito.AdditionalMatchers.not; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -59,8 +54,6 @@ import com.android.server.SystemService; import org.junit.Before; import org.junit.Test; -import org.mockito.InOrder; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; @@ -90,14 +83,15 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { private Context mContextSpy; private ArrayList mLocalDevices = new ArrayList<>(); - @Mock protected AudioManager mAudioManager; - protected FakeAudioDeviceVolumeManagerWrapper mAudioDeviceVolumeManager; + protected FakeAudioFramework mAudioFramework; + protected AudioManagerWrapper mAudioManager; + protected AudioDeviceVolumeManagerWrapper mAudioDeviceVolumeManager; protected TestLooper mTestLooper = new TestLooper(); protected FakeNativeWrapper mNativeWrapper; - // Audio Status given by the System Audio device in its initial that - // triggers AVB being enabled + // Default Audio Status given by the System Audio device in its initial + // that triggers AVB being enabled private static final AudioStatus INITIAL_SYSTEM_AUDIO_DEVICE_STATUS = new AudioStatus(50, false); @@ -110,6 +104,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { .setMinVolumeIndex(AudioStatus.MIN_VOLUME) .build(); + private static final int EMPTY_FLAGS = 0; + protected abstract HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService); protected abstract int getPhysicalAddress(); @@ -126,17 +122,17 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { mContextSpy = spy(new ContextWrapper( InstrumentationRegistry.getInstrumentation().getTargetContext())); - mAudioDeviceVolumeManager = spy(new FakeAudioDeviceVolumeManagerWrapper()); + mAudioFramework = new FakeAudioFramework(); + mAudioManager = spy(mAudioFramework.getAudioManager()); + mAudioDeviceVolumeManager = spy(mAudioFramework.getAudioDeviceVolumeManager()); + + mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, EMPTY_FLAGS); + mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext(), Collections.singletonList(getDeviceType()), - mAudioDeviceVolumeManager) { - @Override - AudioManager getAudioManager() { - return mAudioManager; - } - + mAudioManager, mAudioDeviceVolumeManager) { @Override protected void writeStringSystemProperty(String key, String value) { // do nothing @@ -186,22 +182,12 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_BOOT_UP); mTestLooper.dispatchAll(); - // Simulate AudioManager's behavior and response when setDeviceVolumeBehavior is called - doAnswer(invocation -> { - setDeviceVolumeBehavior(invocation.getArgument(0), invocation.getArgument(1)); - return null; - }).when(mAudioManager).setDeviceVolumeBehavior(any(), anyInt()); - - // Set starting volume behavior - doReturn(AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE) - .when(mAudioManager).getDeviceVolumeBehavior(eq(getAudioOutputDevice())); - // Audio service always plays STREAM_MUSIC on the device we need - doReturn(Collections.singletonList(getAudioOutputDevice())).when(mAudioManager) - .getDevicesForAttributes(HdmiControlService.STREAM_MUSIC_ATTRIBUTES); + mAudioFramework.setDevicesForAttributes(HdmiControlService.STREAM_MUSIC_ATTRIBUTES, + Collections.singletonList(getAudioOutputDevice())); // Max volume of STREAM_MUSIC - doReturn(25).when(mAudioManager).getStreamMaxVolume(AudioManager.STREAM_MUSIC); + mAudioFramework.setStreamMaxVolume(AudioManager.STREAM_MUSIC, 25); // Receive messages from devices to make sure they're registered in HdmiCecNetwork mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveDevicePowerStatus( @@ -220,16 +206,6 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { return mHdmiCecLocalDevice.getDeviceInfo().getLogicalAddress(); } - /** - * Simulates the volume behavior of {@code device} being set to {@code behavior}. - */ - protected void setDeviceVolumeBehavior(AudioDeviceAttributes device, - @AudioManager.DeviceVolumeBehavior int behavior) { - doReturn(behavior).when(mAudioManager).getDeviceVolumeBehavior(eq(device)); - mHdmiControlService.onDeviceVolumeBehaviorChanged(device, behavior); - mTestLooper.dispatchAll(); - } - /** * Changes the setting for CEC volume. */ @@ -277,16 +253,6 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { mTestLooper.dispatchAll(); } - /** - * Has the device receive a reporting the status in - * {@link #INITIAL_SYSTEM_AUDIO_DEVICE_STATUS} - */ - protected void receiveInitialReportAudioStatus() { - receiveReportAudioStatus( - INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume(), - INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()); - } - /** * Has the device receive a message from the System Audio Device. */ @@ -303,37 +269,17 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { * Triggers all the conditions required to enable absolute volume behavior. */ protected void enableAbsoluteVolumeBehavior() { - setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); enableSystemAudioModeIfNeeded(); - receiveInitialReportAudioStatus(); + receiveReportAudioStatus( + INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume(), + INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()); - verifyAbsoluteVolumeEnabled(); - } - - /** - * Verifies that the audio output device's volume behavior was last set to - * absolute volume behavior. - */ - protected void verifyAbsoluteVolumeEnabled() { - InOrder inOrder = inOrder(mAudioManager, mAudioDeviceVolumeManager); - inOrder.verify(mAudioDeviceVolumeManager, atLeastOnce()).setDeviceAbsoluteVolumeBehavior( - eq(getAudioOutputDevice()), any(), any(), any(), anyBoolean()); - inOrder.verify(mAudioManager, never()).setDeviceVolumeBehavior( - eq(getAudioOutputDevice()), not(eq(AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE))); - } - - /** - * Verifies that the audio output device's volume behavior was last set to something other than - * absolute volume behavior. - */ - protected void verifyAbsoluteVolumeDisabled() { - InOrder inOrder = inOrder(mAudioManager, mAudioDeviceVolumeManager); - inOrder.verify(mAudioManager, atLeastOnce()).setDeviceVolumeBehavior( - eq(getAudioOutputDevice()), not(eq(AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE))); - inOrder.verify(mAudioDeviceVolumeManager, never()).setDeviceAbsoluteVolumeBehavior( - eq(getAudioOutputDevice()), any(), any(), any(), anyBoolean()); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); } protected void verifyGiveAudioStatusNeverSent() { @@ -350,7 +296,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { @Test public void allConditionsExceptSavlSupportMet_sendsSetAudioVolumeLevelAndGiveFeatures() { - setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); enableSystemAudioModeIfNeeded(); @@ -365,7 +312,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { @Test public void allConditionsMet_savlSupportLast_reportFeatures_giveAudioStatusSent() { - setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); enableSystemAudioModeIfNeeded(); verifyGiveAudioStatusNeverSent(); @@ -376,7 +324,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { @Test public void allConditionsMet_savlSupportLast_noFeatureAbort_giveAudioStatusSent() { - setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); enableSystemAudioModeIfNeeded(); verifyGiveAudioStatusNeverSent(); @@ -388,7 +337,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { @Test public void allConditionsMet_cecVolumeEnabledLast_giveAudioStatusSent() { - setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); enableSystemAudioModeIfNeeded(); receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); verifyGiveAudioStatusNeverSent(); @@ -404,7 +354,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); verifyGiveAudioStatusNeverSent(); - setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + mTestLooper.dispatchAll(); verifyGiveAudioStatusSent(); } @@ -413,7 +365,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { // Only run when the System Audio device is an Audio System. assume().that(getSystemAudioDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); - setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); verifyGiveAudioStatusNeverSent(); @@ -424,17 +377,32 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { @Test public void giveAudioStatusSent_systemAudioDeviceSendsReportAudioStatus_avbEnabled() { + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); enableSystemAudioModeIfNeeded(); receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); - setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); - // Verify that AVB was never enabled - verify(mAudioDeviceVolumeManager, never()).setDeviceAbsoluteVolumeBehavior( - eq(getAudioOutputDevice()), any(), any(), any(), anyBoolean()); - receiveInitialReportAudioStatus(); + // AVB should not be enabled before receiving + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); - verifyAbsoluteVolumeEnabled(); + receiveReportAudioStatus(60, false); + + // Check that absolute volume behavior was the last one adopted + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); + + // Check that the volume and mute status received were included when setting AVB + verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeBehavior( + eq(getAudioOutputDevice()), + eq(new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setVolumeIndex(60) + .setMuted(false) + .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) + .setMinVolumeIndex(AudioStatus.MIN_VOLUME) + .build()), + any(), any(), anyBoolean()); } @Test @@ -457,7 +425,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { enableAbsoluteVolumeBehavior(); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_DISABLED); - verifyAbsoluteVolumeDisabled(); + + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); } @Test @@ -465,7 +435,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { enableAbsoluteVolumeBehavior(); receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); - verifyAbsoluteVolumeDisabled(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); } @Test @@ -476,7 +447,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { getSystemAudioDeviceLogicalAddress(), getLogicalAddress(), Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, Constants.ABORT_UNRECOGNIZED_OPCODE)); mTestLooper.dispatchAll(); - verifyAbsoluteVolumeDisabled(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); } @Test @@ -487,9 +459,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { enableAbsoluteVolumeBehavior(); receiveSetSystemAudioMode(false); - verifyAbsoluteVolumeDisabled(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); } - @Test public void avbEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges() { // Initial has volume=50 and mute=false @@ -583,8 +555,10 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged( getAudioOutputDevice(), - new VolumeInfo.Builder(ENABLE_AVB_VOLUME_INFO) + new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) .setVolumeIndex(20) + .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) + .setMinVolumeIndex(AudioStatus.MIN_VOLUME) .build() ); mTestLooper.dispatchAll(); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java index 28ba4bb503f91..9b65762e48ec2 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/DetectTvSystemAudioModeSupportActionTest.java @@ -54,9 +54,13 @@ public class DetectTvSystemAudioModeSupportActionTest { @Before public void SetUp() { mDeviceInfoForTests = HdmiDeviceInfo.hardwarePort(1001, 1234); + + FakeAudioFramework audioFramework = new FakeAudioFramework(); + HdmiControlService hdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext(), - Collections.emptyList(), new FakeAudioDeviceVolumeManagerWrapper()) { + Collections.emptyList(), audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { @Override void sendCecCommand( diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java index c4c5c2a7008e0..af4eab39492d5 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java @@ -31,7 +31,6 @@ import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -76,19 +75,11 @@ public class DevicePowerStatusActionTest { mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(mContextSpy, Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK), - new FakeAudioDeviceVolumeManagerWrapper()) { - @Override - AudioManager getAudioManager() { - return new AudioManager() { - @Override - public void setWiredDeviceConnectionState( - int type, int state, String address, String name) { - // Do nothing. - } - }; - } + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isPowerStandby() { diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java index b571f4354452e..5070b08a10cc9 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java @@ -97,10 +97,13 @@ public class DeviceSelectActionFromPlaybackTest { Context context = InstrumentationRegistry.getTargetContext(); mMyLooper = mTestLooper.getLooper(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext(), Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK), - new FakeAudioDeviceVolumeManagerWrapper()) { + audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isCecControlEnabled() { return true; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java index 9c1b67010d033..49023c6a22c44 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java @@ -106,10 +106,13 @@ public class DeviceSelectActionFromTvTest { Context context = InstrumentationRegistry.getTargetContext(); mMyLooper = mTestLooper.getLooper(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext(), Collections.singletonList(HdmiDeviceInfo.DEVICE_TV), - new FakeAudioDeviceVolumeManagerWrapper()) { + audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isCecControlEnabled() { return true; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java new file mode 100644 index 0000000000000..3bcfac38e85b7 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import static android.media.AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener; +import static android.media.AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.media.AudioAttributes; +import android.media.AudioDeviceAttributes; +import android.media.AudioManager; +import android.media.AudioSystem; +import android.media.VolumeInfo; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; + +/** + * Contains a fake AudioManager and fake AudioDeviceVolumeManager. + * Stores the shared state for these managers, simulating a fake AudioService. + */ +public class FakeAudioFramework { + + private final FakeAudioManagerWrapper mAudioManager = new FakeAudioManagerWrapper(); + private final FakeAudioDeviceVolumeManagerWrapper mAudioDeviceVolumeManager = + new FakeAudioDeviceVolumeManagerWrapper(); + + private static final int DEFAULT_DEVICE_VOLUME_BEHAVIOR = + AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE; + private final Map mDeviceVolumeBehaviors = new HashMap<>(); + + private final Set mVolumeBehaviorListeners = + new HashSet<>(); + + private final Map> mDevicesForAttributes = + new HashMap<>(); + + private static final int DEFAULT_VOLUME = 0; + private final Map mStreamVolumes = new HashMap<>(); + + private static final int DEFAULT_MAX_VOLUME = 100; + private final Map mStreamMaxVolumes = new HashMap<>(); + + private static final boolean DEFAULT_MUTE_STATUS = false; + private final Map mStreamMuteStatuses = new HashMap<>(); + + public FakeAudioFramework() { + } + + /** + * Returns a fake AudioManager whose methods affect this object's internal state. + */ + public FakeAudioManagerWrapper getAudioManager() { + return mAudioManager; + } + + public class FakeAudioManagerWrapper implements AudioManagerWrapper { + @Override + public void adjustStreamVolume(int streamType, int direction, + @AudioManager.PublicVolumeFlags int flags) { + switch (direction) { + case AudioManager.ADJUST_MUTE: + mStreamMuteStatuses.put(streamType, true); + break; + case AudioManager.ADJUST_UNMUTE: + mStreamMuteStatuses.put(streamType, false); + break; + default: + // Other adjustments not implemented + } + } + + @Override + public void setStreamVolume(int streamType, int index, + @AudioManager.PublicVolumeFlags int flags) { + mStreamVolumes.put(streamType, index); + } + + @Override + public int getStreamVolume(int streamType) { + return mStreamVolumes.getOrDefault(streamType, DEFAULT_VOLUME); + } + + @Override + public int getStreamMinVolume(int streamType) { + return 0; + } + + @Override + public int getStreamMaxVolume(int streamType) { + return mStreamMaxVolumes.getOrDefault(streamType, DEFAULT_MAX_VOLUME); + } + + @Override + public boolean isStreamMute(int streamType) { + return mStreamMuteStatuses.getOrDefault(streamType, DEFAULT_MUTE_STATUS); + } + + @Override + public void setStreamMute(int streamType, boolean state) { + mStreamMuteStatuses.put(streamType, state); + } + + @Override + public int setHdmiSystemAudioSupported(boolean on) { + return AudioSystem.DEVICE_NONE; + } + + @Override + public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) { + // Do nothing + } + + @Override + public void setWiredDeviceConnectionState(int device, int state, String address, + String name) { + // Do nothing + } + + + @Override + @AudioManager.DeviceVolumeBehavior + public int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { + return mDeviceVolumeBehaviors.getOrDefault(device, DEFAULT_DEVICE_VOLUME_BEHAVIOR); + } + + public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device, + @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior) { + setVolumeBehaviorHelper(device, deviceVolumeBehavior); + } + + @Override + @NonNull + public List getDevicesForAttributes( + @NonNull AudioAttributes attributes) { + return mDevicesForAttributes.getOrDefault(attributes, Collections.emptyList()); + } + } + + /** + * Returns a fake AudioDeviceVolumeManager whose methods affect this object's internal state. + */ + public FakeAudioDeviceVolumeManagerWrapper getAudioDeviceVolumeManager() { + return mAudioDeviceVolumeManager; + } + + public class FakeAudioDeviceVolumeManagerWrapper implements AudioDeviceVolumeManagerWrapper { + @Override + public void addOnDeviceVolumeBehaviorChangedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull OnDeviceVolumeBehaviorChangedListener listener) + throws SecurityException { + mVolumeBehaviorListeners.add(listener); + } + + @Override + public void removeOnDeviceVolumeBehaviorChangedListener( + @NonNull OnDeviceVolumeBehaviorChangedListener listener) { + mVolumeBehaviorListeners.remove(listener); + } + + @Override + public void setDeviceAbsoluteVolumeBehavior( + @NonNull AudioDeviceAttributes device, + @NonNull VolumeInfo volume, + @NonNull @CallbackExecutor Executor executor, + @NonNull OnAudioDeviceVolumeChangedListener vclistener, + boolean handlesVolumeAdjustment) { + setVolumeBehaviorHelper(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); + } + } + + /** + * Allows tests to manipulate the return value of + * {@link FakeAudioManagerWrapper#getDevicesForAttributes} + */ + public void setDevicesForAttributes(AudioAttributes attributes, + List devices) { + mDevicesForAttributes.put(attributes, devices); + } + + /** + * Allows tests to manipulate the return value of + * {@link FakeAudioManagerWrapper#getStreamMaxVolume} + */ + public void setStreamMaxVolume(int streamType, int maxVolume) { + mStreamMaxVolumes.put(streamType, maxVolume); + } + + /** + * Helper method for changing an audio device's volume behavior. Notifies listeners. + */ + private void setVolumeBehaviorHelper(AudioDeviceAttributes device, + @AudioManager.DeviceVolumeBehavior int newVolumeBehavior) { + + int currentVolumeBehavior = mDeviceVolumeBehaviors.getOrDefault( + device, DEFAULT_DEVICE_VOLUME_BEHAVIOR); + + mDeviceVolumeBehaviors.put(device, newVolumeBehavior); + + if (newVolumeBehavior != currentVolumeBehavior) { + // Notify volume behavior listeners + for (OnDeviceVolumeBehaviorChangedListener listener : mVolumeBehaviorListeners) { + listener.onDeviceVolumeBehaviorChanged(device, newVolumeBehavior); + } + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java index e3d95586f9436..5e54d3b8c2378 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java @@ -86,9 +86,11 @@ public class HdmiCecAtomLoggingTest { mContextSpy = spy(new ContextWrapper( InstrumentationRegistry.getInstrumentation().getTargetContext())); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK), - new FakeAudioDeviceVolumeManagerWrapper())); + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager())); doNothing().when(mHdmiControlServiceSpy) .writeStringSystemProperty(anyString(), anyString()); doReturn(mHdmiCecAtomWriterSpy).when(mHdmiControlServiceSpy).getAtomWriter(); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java index a7232fefed10b..0870bac6ef381 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java @@ -100,9 +100,11 @@ public class HdmiCecControllerTest { public void SetUp() { mMyLooper = mTestLooper.getLooper(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlServiceSpy = spy(new HdmiControlService( InstrumentationRegistry.getTargetContext(), Collections.emptyList(), - new FakeAudioDeviceVolumeManagerWrapper())); + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager())); doReturn(mMyLooper).when(mHdmiControlServiceSpy).getIoLooper(); doReturn(mMyLooper).when(mHdmiControlServiceSpy).getServiceLooper(); doAnswer(__ -> mCecVersion).when(mHdmiControlServiceSpy).getCecVersion(); 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 f5c0f2a0a4b68..a6e05ddc792c9 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -54,23 +54,23 @@ import java.util.ArrayList; @RunWith(JUnit4.class) /** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */ public class HdmiCecLocalDeviceAudioSystemTest { - private static final HdmiCecMessage MESSAGE_REQUEST_SAD_LCPM = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor( ADDR_TV, ADDR_AUDIO_SYSTEM, new int[] {Constants.AUDIO_CODEC_LPCM}); + private static final int EMPTY_FLAGS = 0; + private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem; private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback; private FakeNativeWrapper mNativeWrapper; private FakePowerManagerWrapper mPowerManager; + private FakeAudioFramework mAudioFramework; + private AudioManagerWrapper mAudioManager; private Looper mMyLooper; private TestLooper mTestLooper = new TestLooper(); private ArrayList mLocalDevices = new ArrayList<>(); - private int mMusicVolume; - private int mMusicMaxVolume; - private boolean mMusicMute; private static final int SELF_PHYSICAL_ADDRESS = 0x2000; private static final int HDMI_1_PHYSICAL_ADDRESS = 0x2100; private static final int HDMI_2_PHYSICAL_ADDRESS = 0x2200; @@ -88,66 +88,12 @@ public class HdmiCecLocalDeviceAudioSystemTest { mLocalDeviceTypes.add(HdmiDeviceInfo.DEVICE_PLAYBACK); mLocalDeviceTypes.add(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mAudioFramework = new FakeAudioFramework(); + mAudioManager = mAudioFramework.getAudioManager(); mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext(), - mLocalDeviceTypes, - new FakeAudioDeviceVolumeManagerWrapper()) { - @Override - AudioManager getAudioManager() { - return new AudioManager() { - @Override - public int getStreamVolume(int streamType) { - switch (streamType) { - case STREAM_MUSIC: - return mMusicVolume; - default: - return 0; - } - } - - @Override - public boolean isStreamMute(int streamType) { - switch (streamType) { - case STREAM_MUSIC: - return mMusicMute; - default: - return false; - } - } - - @Override - public int getStreamMaxVolume(int streamType) { - switch (streamType) { - case STREAM_MUSIC: - return mMusicMaxVolume; - default: - return 100; - } - } - - @Override - public void adjustStreamVolume( - int streamType, int direction, int flags) { - switch (streamType) { - case STREAM_MUSIC: - if (direction == AudioManager.ADJUST_UNMUTE) { - mMusicMute = false; - } else if (direction == AudioManager.ADJUST_MUTE) { - mMusicMute = true; - } - break; - default: - } - } - - @Override - public void setWiredDeviceConnectionState( - int type, int state, String address, String name) { - // Do nothing. - } - }; - } - + mLocalDeviceTypes, mAudioManager, + mAudioFramework.getAudioDeviceVolumeManager()) { @Override void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { mDeviceInfo = device; @@ -236,10 +182,12 @@ public class HdmiCecLocalDeviceAudioSystemTest { @Test public void handleGiveAudioStatus_volume_10_mute_true() throws Exception { - mMusicVolume = 10; - mMusicMute = true; - mMusicMaxVolume = 20; - int scaledVolume = VolumeControlAction.scaleToCecVolume(10, mMusicMaxVolume); + mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 10, EMPTY_FLAGS); + mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_MUTE, + EMPTY_FLAGS); + mAudioFramework.setStreamMaxVolume(AudioManager.STREAM_MUSIC, 20); + int scaledVolume = VolumeControlAction.scaleToCecVolume(10, + mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)); HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildReportAudioStatus( ADDR_AUDIO_SYSTEM, ADDR_TV, scaledVolume, true); @@ -303,7 +251,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { @Test @Ignore("b/120845532") public void handleSetSystemAudioMode_setOn_orignalOff() throws Exception { - mMusicMute = true; + mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); HdmiCecMessage messageSet = HdmiCecMessageBuilder.buildSetSystemAudioMode(ADDR_TV, ADDR_AUDIO_SYSTEM, true); HdmiCecMessage messageGive = @@ -326,13 +274,13 @@ public class HdmiCecLocalDeviceAudioSystemTest { .isEqualTo(Constants.HANDLED); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); - assertThat(mMusicMute).isFalse(); + assertThat(mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)).isFalse(); } @Test @Ignore("b/120845532") public void handleSystemAudioModeRequest_turnOffByTv() throws Exception { - assertThat(mMusicMute).isFalse(); + assertThat(mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)).isFalse(); // Check if feature correctly turned off HdmiCecMessage messageGive = HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(ADDR_TV, ADDR_AUDIO_SYSTEM); @@ -354,7 +302,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { .isEqualTo(Constants.HANDLED); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); - assertThat(mMusicMute).isTrue(); + assertThat(mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)).isTrue(); } @Test @@ -368,7 +316,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { HdmiCecMessageBuilder.buildSetSystemAudioMode( ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false); assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); - assertThat(mMusicMute).isTrue(); + assertThat(mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)).isTrue(); } @Test @@ -463,13 +411,13 @@ public class HdmiCecLocalDeviceAudioSystemTest { public void terminateSystemAudioMode_systemAudioModeOff() throws Exception { mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(false); assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse(); - mMusicMute = false; + mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); HdmiCecMessage message = HdmiCecMessageBuilder.buildSetSystemAudioMode( ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false); mHdmiCecLocalDeviceAudioSystem.terminateSystemAudioMode(); assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse(); - assertThat(mMusicMute).isFalse(); + assertThat(mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)).isFalse(); assertThat(mNativeWrapper.getResultMessages()).isEmpty(); } @@ -477,13 +425,13 @@ public class HdmiCecLocalDeviceAudioSystemTest { public void terminateSystemAudioMode_systemAudioModeOn() throws Exception { mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(true); assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue(); - mMusicMute = false; + mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildSetSystemAudioMode( ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false); mHdmiCecLocalDeviceAudioSystem.terminateSystemAudioMode(); assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse(); - assertThat(mMusicMute).isTrue(); + assertThat(mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)).isTrue(); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); } @@ -705,8 +653,6 @@ public class HdmiCecLocalDeviceAudioSystemTest { @Test public void giveAudioStatus_volumeEnabled() { - mMusicVolume = 50; - mMusicMaxVolume = 100; mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); @@ -733,8 +679,6 @@ public class HdmiCecLocalDeviceAudioSystemTest { @Test public void giveAudioStatus_volumeDisabled() { - mMusicVolume = 50; - mMusicMaxVolume = 100; mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( HdmiControlManager.VOLUME_CONTROL_DISABLED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); @@ -761,8 +705,6 @@ public class HdmiCecLocalDeviceAudioSystemTest { @Test public void reportAudioStatus_volumeEnabled() { - mMusicVolume = 50; - mMusicMaxVolume = 100; mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); @@ -786,8 +728,6 @@ public class HdmiCecLocalDeviceAudioSystemTest { @Test public void reportAudioStatus_volumeDisabled() { - mMusicVolume = 50; - mMusicMaxVolume = 100; mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( HdmiControlManager.VOLUME_CONTROL_DISABLED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); 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 beba9c64a88f2..40c762c281948 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -31,7 +31,6 @@ import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.media.AudioManager; import android.os.Looper; import android.os.RemoteException; import android.os.test.TestLooper; @@ -46,7 +45,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; @@ -88,8 +86,6 @@ public class HdmiCecLocalDevicePlaybackTest { private boolean mActiveMediaSessionsPaused; private FakePowerManagerInternalWrapper mPowerManagerInternal = new FakePowerManagerInternalWrapper(); - @Mock - protected AudioManager mAudioManager; @Before public void setUp() { @@ -98,10 +94,12 @@ public class HdmiCecLocalDevicePlaybackTest { Context context = InstrumentationRegistry.getTargetContext(); mMyLooper = mTestLooper.getLooper(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext(), Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK), - new FakeAudioDeviceVolumeManagerWrapper()) { + audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { @Override void wakeUp() { @@ -109,11 +107,6 @@ public class HdmiCecLocalDevicePlaybackTest { super.wakeUp(); } - @Override - AudioManager getAudioManager() { - return mAudioManager; - } - @Override void pauseActiveMediaSessions() { mActiveMediaSessionsPaused = true; 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 9c5c0d4dd66f0..9882670432ae2 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java @@ -33,6 +33,7 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -53,8 +54,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; @@ -128,18 +127,17 @@ public class HdmiCecLocalDeviceTest { private boolean isControlEnabled; private int mPowerStatus; - @Mock - private AudioManager mAudioManager; + private AudioManagerWrapper mAudioManager; @Before public void SetUp() { - MockitoAnnotations.initMocks(this); - Context context = InstrumentationRegistry.getTargetContext(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mAudioManager = spy(audioFramework.getAudioManager()); mHdmiControlService = new HdmiControlService(context, Collections.emptyList(), - new FakeAudioDeviceVolumeManagerWrapper()) { + mAudioManager, audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isCecControlEnabled() { return isControlEnabled; @@ -171,11 +169,6 @@ public class HdmiCecLocalDeviceTest { void wakeUp() { mWakeupMessageReceived = true; } - - @Override - AudioManager getAudioManager() { - return mAudioManager; - } }; mHdmiControlService.setIoLooper(mTestLooper.getLooper()); mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context)); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java index d2b1bdd127d2c..d52b7ea387254 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java @@ -33,9 +33,9 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.content.Context; import android.hardware.hdmi.HdmiControlManager; @@ -55,8 +55,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Collections; @@ -122,20 +120,21 @@ public class HdmiCecLocalDeviceTvTest { } } - @Mock - private AudioManager mAudioManager; + private FakeAudioFramework mAudioFramework; + private AudioManagerWrapper mAudioManager; @Before public void setUp() { - MockitoAnnotations.initMocks(this); - Context context = InstrumentationRegistry.getTargetContext(); mMyLooper = mTestLooper.getLooper(); + mAudioFramework = new FakeAudioFramework(); + mAudioManager = spy(mAudioFramework.getAudioManager()); + mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext(), Collections.singletonList(HdmiDeviceInfo.DEVICE_TV), - new FakeAudioDeviceVolumeManagerWrapper()) { + mAudioManager, mAudioFramework.getAudioDeviceVolumeManager()) { @Override void wakeUp() { mWokenUp = true; @@ -166,11 +165,6 @@ public class HdmiCecLocalDeviceTvTest { return false; } - @Override - AudioManager getAudioManager() { - return mAudioManager; - } - @Override void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { mDeviceEventListeners.add(new DeviceEventListener(device, status)); @@ -967,7 +961,7 @@ public class HdmiCecLocalDeviceTvTest { @Test public void receiveSetAudioVolumeLevel_samNotActivated_noFeatureAbort_volumeChanges() { - when(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)).thenReturn(25); + mAudioFramework.setStreamMaxVolume(AudioManager.STREAM_MUSIC, 25); // Max volume of STREAM_MUSIC is retrieved on boot mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java index c53a7a708cfd3..ded744c098181 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java @@ -51,9 +51,11 @@ public class HdmiCecMessageValidatorTest { @Before public void setUp() throws Exception { + FakeAudioFramework audioFramework = new FakeAudioFramework(); + HdmiControlService mHdmiControlService = new HdmiControlService( InstrumentationRegistry.getTargetContext(), Collections.emptyList(), - new FakeAudioDeviceVolumeManagerWrapper()); + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()); mHdmiControlService.setIoLooper(mTestLooper.getLooper()); } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java index d341153ac0ce1..1ad9ce02daa31 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java @@ -67,8 +67,11 @@ public class HdmiCecNetworkTest { @Before public void setUp() throws Exception { mContext = InstrumentationRegistry.getTargetContext(); + + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(mContext, Collections.emptyList(), - new FakeAudioDeviceVolumeManagerWrapper()) { + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()) { @Override void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { mDeviceEventListenerStatuses.add(status); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java index 55e8b20ca7f01..c002067ae9e71 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java @@ -64,9 +64,11 @@ public class HdmiCecPowerStatusControllerTest { Context contextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); Looper myLooper = mTestLooper.getLooper(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(contextSpy, Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK), - new FakeAudioDeviceVolumeManagerWrapper()) { + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isCecControlEnabled() { return true; 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 fd6eb9286651d..0e6b412e330de 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -49,7 +49,6 @@ import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener; import android.hardware.hdmi.IHdmiControlStatusChangeListener; import android.hardware.hdmi.IHdmiVendorCommandListener; -import android.media.AudioManager; import android.os.Binder; import android.os.Looper; import android.os.RemoteException; @@ -64,9 +63,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; @@ -96,19 +93,17 @@ public class HdmiControlServiceTest { private HdmiPortInfo[] mHdmiPortInfo; private ArrayList mLocalDeviceTypes = new ArrayList<>(); - @Mock protected AudioManager mAudioManager; - @Before public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); mLocalDeviceTypes.add(HdmiDeviceInfo.DEVICE_PLAYBACK); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, mLocalDeviceTypes, - new FakeAudioDeviceVolumeManagerWrapper())); + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager())); doNothing().when(mHdmiControlServiceSpy) .writeStringSystemProperty(anyString(), anyString()); @@ -171,7 +166,6 @@ public class HdmiControlServiceTest { mPowerManager = new FakePowerManagerWrapper(mContextSpy); mHdmiControlServiceSpy.setPowerManager(mPowerManager); mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); - mHdmiControlServiceSpy.setAudioManager(mAudioManager); mHdmiControlServiceSpy.setEarcSupported(true); mTestLooper.dispatchAll(); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java index c3aec841ac3db..185f90f4e803e 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java @@ -28,6 +28,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -35,7 +36,6 @@ import android.content.Context; import android.hardware.hdmi.HdmiDeviceInfo; import android.media.AudioDescriptor; import android.media.AudioDeviceAttributes; -import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -49,7 +49,6 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; import org.mockito.Captor; -import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -78,8 +77,7 @@ public class HdmiEarcLocalDeviceTxTest { private Looper mMyLooper; private TestLooper mTestLooper = new TestLooper(); - @Mock - private AudioManager mAudioManager; + private AudioManagerWrapper mAudioManager; @Captor ArgumentCaptor mAudioAttributesCaptor; @@ -91,10 +89,13 @@ public class HdmiEarcLocalDeviceTxTest { Context context = InstrumentationRegistry.getTargetContext(); mMyLooper = mTestLooper.getLooper(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mAudioManager = spy(audioFramework.getAudioManager()); + mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext(), Collections.singletonList(HdmiDeviceInfo.DEVICE_TV), - new FakeAudioDeviceVolumeManagerWrapper()) { + mAudioManager, audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isCecControlEnabled() { return true; @@ -114,11 +115,6 @@ public class HdmiEarcLocalDeviceTxTest { boolean isPowerStandby() { return false; } - - @Override - AudioManager getAudioManager() { - return mAudioManager; - } }; mHdmiControlService.setIoLooper(mMyLooper); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java index b0e8ca75d2d82..1172a8744da7f 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java @@ -31,7 +31,6 @@ import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -88,20 +87,11 @@ public class OneTouchPlayActionTest { mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); mHdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(mContextSpy, Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK), - new FakeAudioDeviceVolumeManagerWrapper()) { - @Override - AudioManager getAudioManager() { - return new AudioManager() { - @Override - public void setWiredDeviceConnectionState( - int type, int state, String address, String name) { - // Do nothing. - } - }; - } - + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isPowerStandby() { return false; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java index 29fc9424fc706..abfe0e2e6db8a 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java @@ -16,10 +16,13 @@ package com.android.server.hdmi; +import static com.google.common.truth.Truth.assertThat; + import android.hardware.hdmi.DeviceFeatures; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.media.AudioDeviceAttributes; +import android.media.AudioManager; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -82,7 +85,8 @@ public class PlaybackDeviceToAudioSystemAvbTest extends BaseAbsoluteVolumeBehavi // Audio System disables System Audio Mode. AVB should be disabled. receiveSetSystemAudioMode(false); - verifyAbsoluteVolumeDisabled(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); // TV reports support for mNativeWrapper.onCecMessage(ReportFeaturesMessage.build( @@ -102,6 +106,7 @@ public class PlaybackDeviceToAudioSystemAvbTest extends BaseAbsoluteVolumeBehavi false)); mTestLooper.dispatchAll(); - verifyAbsoluteVolumeEnabled(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java index 19af558fb4b4a..c65b26a1e8bfe 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java @@ -16,12 +16,15 @@ package com.android.server.hdmi; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.clearInvocations; import android.hardware.hdmi.DeviceFeatures; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.media.AudioDeviceAttributes; +import android.media.AudioManager; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -83,7 +86,8 @@ public class PlaybackDeviceToTvAvbTest extends BaseAbsoluteVolumeBehaviorTest { // Audio System enables System Audio Mode. AVB should be disabled. receiveSetSystemAudioMode(true); - verifyAbsoluteVolumeDisabled(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); clearInvocations(mAudioManager, mAudioDeviceVolumeManager); @@ -105,6 +109,7 @@ public class PlaybackDeviceToTvAvbTest extends BaseAbsoluteVolumeBehaviorTest { false)); mTestLooper.dispatchAll(); - verifyAbsoluteVolumeEnabled(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java index 89743cdeabf57..9f0a44ce008a0 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java @@ -30,7 +30,6 @@ import android.content.ContextWrapper; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; -import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -65,20 +64,11 @@ public class PowerStatusMonitorActionTest { public void setUp() throws Exception { mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(mContextSpy, Collections.singletonList(HdmiDeviceInfo.DEVICE_TV), - new FakeAudioDeviceVolumeManagerWrapper()) { - @Override - AudioManager getAudioManager() { - return new AudioManager() { - @Override - public void setWiredDeviceConnectionState( - int type, int state, String address, String name) { - // Do nothing. - } - }; - } - + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isPowerStandby() { return false; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java index 1c193411b9324..043db1eb298db 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java @@ -95,9 +95,12 @@ public class RequestSadActionTest { Context context = InstrumentationRegistry.getTargetContext(); mMyLooper = mTestLooper.getLooper(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(context, Collections.singletonList(HdmiDeviceInfo.DEVICE_TV), - new FakeAudioDeviceVolumeManagerWrapper()) { + audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isCecControlEnabled() { return true; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java index 5b1bdf6916da7..1bc99b6b8ffbe 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java @@ -146,10 +146,13 @@ public class RoutingControlActionTest { HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(InstrumentationRegistry.getTargetContext(), Collections.singletonList(HdmiDeviceInfo.DEVICE_TV), - new FakeAudioDeviceVolumeManagerWrapper()) { + audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isCecControlEnabled() { return true; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java index a3d02d4fe26f0..a73f4aa35cf93 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryActionTest.java @@ -80,9 +80,11 @@ public class SetAudioVolumeLevelDiscoveryActionTest { mContextSpy = spy(new ContextWrapper( InstrumentationRegistry.getInstrumentation().getTargetContext())); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK), - new FakeAudioDeviceVolumeManagerWrapper())); + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager())); doNothing().when(mHdmiControlServiceSpy) .writeStringSystemProperty(anyString(), anyString()); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java index c40cd0eeaf7e8..c3beff74ca1c3 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java @@ -29,7 +29,6 @@ import android.content.Context; import android.content.ContextWrapper; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; -import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -68,20 +67,11 @@ public class SystemAudioAutoInitiationActionTest { Looper myLooper = mTestLooper.getLooper(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + mHdmiControlService = new HdmiControlService(mContextSpy, Collections.singletonList(HdmiDeviceInfo.DEVICE_TV), - new FakeAudioDeviceVolumeManagerWrapper()) { - @Override - AudioManager getAudioManager() { - return new AudioManager() { - @Override - public void setWiredDeviceConnectionState( - int type, int state, String address, String name) { - // Do nothing. - } - }; - } - + audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()) { @Override boolean isPowerStandby() { return false; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java index b13ef4fa7014b..f801f8853980f 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java @@ -24,7 +24,6 @@ import android.annotation.Nullable; import android.content.Context; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.tv.cec.V1_0.SendMessageResult; -import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; @@ -68,8 +67,11 @@ public class SystemAudioInitiationActionFromAvrTest { Context context = InstrumentationRegistry.getTargetContext(); + FakeAudioFramework audioFramework = new FakeAudioFramework(); + HdmiControlService hdmiControlService = new HdmiControlService(context, - Collections.emptyList(), new FakeAudioDeviceVolumeManagerWrapper()) { + Collections.emptyList(), audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { @Override void sendCecCommand( HdmiCecMessage command, @Nullable SendMessageCallback callback) { @@ -99,36 +101,6 @@ public class SystemAudioInitiationActionFromAvrTest { } } - @Override - AudioManager getAudioManager() { - return new AudioManager() { - - @Override - public int setHdmiSystemAudioSupported(boolean on) { - return 0; - } - - @Override - public int getStreamVolume(int streamType) { - return 0; - } - - @Override - public boolean isStreamMute(int streamType) { - return false; - } - - @Override - public int getStreamMaxVolume(int streamType) { - return 100; - } - - @Override - public void adjustStreamVolume( - int streamType, int direction, int flags) {} - }; - } - @Override boolean isPowerStandby() { return false; From 556aa155a04f3390d3b961372aa7fa365d77b5da Mon Sep 17 00:00:00 2001 From: Yan Han Date: Thu, 13 Apr 2023 14:39:21 +0200 Subject: [PATCH 4/5] Implement soundbar volume UI for TV panels. This is done by adopting adjust-only absolute volume behavior when the connected amplifier is able to send . Adjust-only absolute volume behavior supports volume tracking and automatically displays volume UI when the volume level is updated in AudioService. In HdmiControlService, adoption of this behavior is implemented as a special case in the logic for adopting absolute volume behavior: - Absolute volume behavior is currently adopted when a TV panel or playback device is able to track AND set the percentage volume level of the System Audio device. - Adjust-only absolute volume behavior will be adopted when a TV panel can track, but not set, the volume level of the System Audio device. The only behavioral difference in HdmiControlService when using adjust-only AVB, compared to regular AVB, is that it does not send to the System Audio device. Bug: 240663266 Test: atest TvToAudioSystemAvbTest PlaybackDeviceToTvAvbTest PlaybackDeviceToAudioSystemAvbTest Change-Id: I05465cd0eab2f3c3464bf41c1194cdc3be7af4bf --- .../hdmi/AbsoluteVolumeAudioStatusAction.java | 9 +- .../hdmi/AudioDeviceVolumeManagerWrapper.java | 11 + ...efaultAudioDeviceVolumeManagerWrapper.java | 11 + .../server/hdmi/HdmiCecLocalDevice.java | 6 + .../server/hdmi/HdmiCecLocalDeviceTv.java | 2 +- .../server/hdmi/HdmiControlService.java | 130 ++++++++---- .../hdmi/BaseAbsoluteVolumeBehaviorTest.java | 17 +- .../hdmi/BasePlaybackDeviceAvbTest.java | 71 +++++++ .../server/hdmi/FakeAudioFramework.java | 11 + .../PlaybackDeviceToAudioSystemAvbTest.java | 23 +- .../hdmi/PlaybackDeviceToTvAvbTest.java | 23 +- .../server/hdmi/TvToAudioSystemAvbTest.java | 199 ++++++++++++++++++ 12 files changed, 423 insertions(+), 90 deletions(-) create mode 100644 services/tests/servicestests/src/com/android/server/hdmi/BasePlaybackDeviceAvbTest.java diff --git a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java index 113384f375bdb..d764ec41b3b96 100644 --- a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java +++ b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java @@ -17,10 +17,13 @@ package com.android.server.hdmi; /** - * Action to query and track the audio status of the System Audio device when enabling or using - * absolute volume behavior. Must be removed when AVB is disabled. Performs two main functions: + * Action to query and track the audio status of the System Audio device when using + * absolute volume behavior, or adjust-only absolute volume behavior. Must be removed when + * neither behavior is used. + * + * Performs two main functions: * 1. When enabling AVB: queries the starting audio status of the System Audio device and - * enables the feature upon receiving a response. + * adopts the appropriate volume behavior upon receiving a response. * 2. While AVB is enabled: monitors messages from the System Audio device and * notifies AudioService if the audio status changes. */ diff --git a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java index 23e6a12e590d9..94842041af827 100644 --- a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java +++ b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java @@ -61,4 +61,15 @@ public interface AudioDeviceVolumeManagerWrapper { @NonNull @CallbackExecutor Executor executor, @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, boolean handlesVolumeAdjustment); + + /** + * Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeAdjustOnlyBehavior( + * AudioDeviceAttributes, VolumeInfo, Executor, OnAudioDeviceVolumeChangedListener, boolean)} + */ + void setDeviceAbsoluteVolumeAdjustOnlyBehavior( + @NonNull AudioDeviceAttributes device, + @NonNull VolumeInfo volume, + @NonNull @CallbackExecutor Executor executor, + @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, + boolean handlesVolumeAdjustment); } diff --git a/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java index b9a78c93989f5..ff99ace38ef0e 100644 --- a/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java +++ b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java @@ -67,4 +67,15 @@ public class DefaultAudioDeviceVolumeManagerWrapper mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeBehavior(device, volume, executor, vclistener, handlesVolumeAdjustment); } + + @Override + public void setDeviceAbsoluteVolumeAdjustOnlyBehavior( + @NonNull AudioDeviceAttributes device, + @NonNull VolumeInfo volume, + @NonNull @CallbackExecutor Executor executor, + @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, + boolean handlesVolumeAdjustment) { + mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeAdjustOnlyBehavior(device, volume, + executor, vclistener, handlesVolumeAdjustment); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 8b2942489c7f0..f37ad5ed70492 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -1012,17 +1012,23 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice { action.start(); } + @ServiceThreadOnly void addAvbAudioStatusAction(int targetAddress) { + assertRunOnServiceThread(); if (!hasAction(AbsoluteVolumeAudioStatusAction.class)) { addAndStartAction(new AbsoluteVolumeAudioStatusAction(this, targetAddress)); } } + @ServiceThreadOnly void removeAvbAudioStatusAction() { + assertRunOnServiceThread(); removeAction(AbsoluteVolumeAudioStatusAction.class); } + @ServiceThreadOnly void updateAvbVolume(int volumeIndex) { + assertRunOnServiceThread(); for (AbsoluteVolumeAudioStatusAction action : getActions(AbsoluteVolumeAudioStatusAction.class)) { action.updateVolume(volumeIndex); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index f47c4b2c24d9e..5ef06f9f89673 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -66,7 +66,7 @@ import java.util.stream.Collectors; /** * Represent a logical device of type TV residing in Android system. */ -final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { +public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { private static final String TAG = "HdmiCecLocalDeviceTv"; // Whether ARC is available or not. "true" means that ARC is established between TV and diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 741e730da0221..9edab6da1a7ee 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -4230,14 +4230,18 @@ public class HdmiControlService extends SystemService { if (avbAudioOutputDevice == null) { return false; } - return getDeviceVolumeBehavior(avbAudioOutputDevice) - == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE; + + @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior = + getDeviceVolumeBehavior(avbAudioOutputDevice); + + return deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE + || deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY; } private AudioDeviceAttributes getAvbAudioOutputDevice() { - if (isTvDevice()) { + if (tv() != null) { return tv().getSystemAudioOutputDevice(); - } else if (isPlaybackDevice()) { + } else if (playback() != null) { return AUDIO_OUTPUT_DEVICE_HDMI; } else { return null; @@ -4245,24 +4249,24 @@ public class HdmiControlService extends SystemService { } /** - * Checks the conditions for Absolute Volume Behavior (AVB), and enables or disables the feature - * if necessary. AVB is enabled precisely when a specific audio output device - * (HDMI for playback devices, and HDMI_ARC or HDMI_EARC for TVs) is using absolute volume - * behavior. + * This method is responsible for adopting or disabling absolute volume behavior and + * adjust-only absolute volume behavior in AudioService. These volume behaviors are adopted on + * specific audio output devices: HDMI for playback devices, and HDMI_ARC or HDMI_EARC for TVs. * - * AVB must be enabled on a Playback device or TV precisely when it is playing - * audio on an external device (the System Audio device) that supports the feature. - * This reduces to these conditions: + * This method enables absolute volume behavior on a Playback device or TV panel when it is + * playing audio on an external device (the System Audio device) that supports the feature. + * This allows the volume level of the System Audio device to be tracked and set by Android. * + * Absolute volume behavior requires the following conditions: * 1. If the System Audio Device is an Audio System: System Audio Mode is active * 2. Our HDMI audio output device is using full volume behavior * 3. CEC volume is enabled - * 4. The System Audio device supports AVB (i.e. it supports ) + * 4. The System Audio device supports the message * - * If not all of these conditions are met, this method disables AVB if necessary. - * - * If all of these conditions are met, this method starts an action to query the System Audio - * device's audio status, which enables AVB upon obtaining the audio status. + * This method enables adjust-only absolute volume behavior on TV panels when conditions + * 1, 2, and 3 are met, but condition 4 is not. This allows TVs to track the volume level of + * the System Audio device and display numeric volume UI for it, even if the System Audio device + * does not support . */ @ServiceThreadOnly void checkAndUpdateAbsoluteVolumeBehavior() { @@ -4280,7 +4284,7 @@ public class HdmiControlService extends SystemService { // (Doesn't apply to Playback Devices, where if SAM isn't active, we assume the // TV is the System Audio Device instead.) if (!isSystemAudioActivated()) { - disableAbsoluteVolumeBehavior(); + switchToFullVolumeBehavior(); return; } } else if (isPlaybackDevice() && playback() != null) { @@ -4290,75 +4294,100 @@ public class HdmiControlService extends SystemService { return; } - HdmiDeviceInfo systemAudioDeviceInfo = getHdmiCecNetwork().getSafeCecDeviceInfo( + HdmiDeviceInfo systemAudioDeviceInfo = getDeviceInfo( localCecDevice.findAudioReceiverAddress()); @AudioManager.DeviceVolumeBehavior int currentVolumeBehavior = getDeviceVolumeBehavior(getAvbAudioOutputDevice()); // Condition 2: Already using full or absolute volume behavior boolean alreadyUsingFullOrAbsoluteVolume = - currentVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL - || currentVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE; + (currentVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL) + || (currentVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) + || (currentVolumeBehavior + == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); // Condition 3: CEC volume is enabled boolean cecVolumeEnabled = getHdmiCecVolumeControl() == HdmiControlManager.VOLUME_CONTROL_ENABLED; if (!cecVolumeEnabled || !alreadyUsingFullOrAbsoluteVolume) { - disableAbsoluteVolumeBehavior(); + switchToFullVolumeBehavior(); return; } // Check for safety: if the System Audio device is a candidate for AVB, we should already // have received messages from it to trigger the other conditions. if (systemAudioDeviceInfo == null) { - disableAbsoluteVolumeBehavior(); + switchToFullVolumeBehavior(); return; } - // Condition 4: The System Audio device supports AVB (i.e. ). + + // Condition 4: The System Audio device supports switch (systemAudioDeviceInfo.getDeviceFeatures().getSetAudioVolumeLevelSupport()) { case DeviceFeatures.FEATURE_SUPPORTED: - if (!isAbsoluteVolumeBehaviorEnabled()) { - // Start an action that will call {@link #enableAbsoluteVolumeBehavior} + if (currentVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) { + // If we're currently using adjust-only absolute volume behavior, switch to + // full volume behavior until we successfully adopt absolute volume behavior + switchToFullVolumeBehavior(); + // Start an action that will call enableAbsoluteVolumeBehavior // once the System Audio device sends localCecDevice.addAvbAudioStatusAction( systemAudioDeviceInfo.getLogicalAddress()); } return; case DeviceFeatures.FEATURE_NOT_SUPPORTED: - disableAbsoluteVolumeBehavior(); + // TVs may adopt adjust-only absolute volume behavior if condition 4 isn't met. + // This allows the device to display numeric volume UI for the System Audio device. + if (tv() != null) { + if (currentVolumeBehavior + != AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) { + // If we're currently using absolute volume behavior, switch to full volume + // behavior until we successfully adopt adjust-only absolute volume behavior + switchToFullVolumeBehavior(); + // Start an action that will call enableAbsoluteVolumeBehavior + // once the System Audio device sends + localCecDevice.addAvbAudioStatusAction( + systemAudioDeviceInfo.getLogicalAddress()); + } + } else { + switchToFullVolumeBehavior(); + } return; case DeviceFeatures.FEATURE_SUPPORT_UNKNOWN: - disableAbsoluteVolumeBehavior(); + switchToFullVolumeBehavior(); localCecDevice.querySetAudioVolumeLevelSupport( systemAudioDeviceInfo.getLogicalAddress()); - return; - default: - return; } } - private void disableAbsoluteVolumeBehavior() { - if (isPlaybackDevice()) { + /** + * Switches to full volume behavior, if either absolute or adjust-only absolute volume behavior + * are currently used. Removes the action for handling volume updates for these behaviors. + */ + private void switchToFullVolumeBehavior() { + if (playback() != null) { playback().removeAvbAudioStatusAction(); - } else if (isTvDevice()) { + } else if (tv() != null) { tv().removeAvbAudioStatusAction(); } AudioDeviceAttributes device = getAvbAudioOutputDevice(); - if (getDeviceVolumeBehavior(device) == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) { + int volumeBehavior = getDeviceVolumeBehavior(device); + if (volumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE + || volumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) { getAudioManager().setDeviceVolumeBehavior(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); } } /** - * Enables absolute volume behavior. Should only be called when all the conditions for - * AVB are met (see {@link #checkAndUpdateAbsoluteVolumeBehavior}). + * Enables absolute volume behavior or adjust-only absolute volume behavior. Should only be + * called when the conditions for one of these behaviors is met - + * see {@link #checkAndUpdateAbsoluteVolumeBehavior}. + * * @param audioStatus The initial audio status to set the audio output device to */ void enableAbsoluteVolumeBehavior(AudioStatus audioStatus) { HdmiCecLocalDevice localDevice = isPlaybackDevice() ? playback() : tv(); - HdmiDeviceInfo systemAudioDevice = getHdmiCecNetwork().getDeviceInfo( - localDevice.findAudioReceiverAddress()); + HdmiDeviceInfo systemAudioDevice = getDeviceInfo(localDevice.findAudioReceiverAddress()); VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) .setMuted(audioStatus.getMute()) .setVolumeIndex(audioStatus.getVolume()) @@ -4371,9 +4400,20 @@ public class HdmiControlService extends SystemService { // AudioService sets the volume of the stream and device based on the input VolumeInfo // when enabling absolute volume behavior, but not the mute state notifyAvbMuteChange(audioStatus.getMute()); - getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeBehavior( - getAvbAudioOutputDevice(), volumeInfo, mServiceThreadExecutor, - mAbsoluteVolumeChangedListener, true); + + // If is supported, enable absolute volume behavior. + // Otherwise, enable adjust-only AVB on TVs only. + if (systemAudioDevice.getDeviceFeatures().getSetAudioVolumeLevelSupport() + == DeviceFeatures.FEATURE_SUPPORTED) { + getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeBehavior( + getAvbAudioOutputDevice(), volumeInfo, mServiceThreadExecutor, + mAbsoluteVolumeChangedListener, true); + } else if (tv() != null) { + getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeAdjustOnlyBehavior( + getAvbAudioOutputDevice(), volumeInfo, mServiceThreadExecutor, + mAbsoluteVolumeChangedListener, true); + } + } private AbsoluteVolumeChangedListener mAbsoluteVolumeChangedListener; @@ -4407,6 +4447,14 @@ public class HdmiControlService extends SystemService { public void onAudioDeviceVolumeChanged( @NonNull AudioDeviceAttributes audioDevice, @NonNull VolumeInfo volumeInfo) { + + // Do nothing if the System Audio device does not support + if (mSystemAudioDevice.getDeviceFeatures().getSetAudioVolumeLevelSupport() + != DeviceFeatures.FEATURE_SUPPORTED) { + return; + } + + // Send to notify the System Audio device of the volume change int localDeviceAddress = mLocalDevice.getDeviceInfo().getLogicalAddress(); sendCecCommand(SetAudioVolumeLevelMessage.build( localDeviceAddress, diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java index fa8927e683dcc..bc09d4b107230 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java @@ -74,7 +74,7 @@ import java.util.Collections; * (TV, Audio System): {@link TvToAudioSystemAvbTest} */ public abstract class BaseAbsoluteVolumeBehaviorTest { - private HdmiControlService mHdmiControlService; + protected HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private HdmiCecLocalDevice mHdmiCecLocalDevice; private FakeHdmiCecConfig mHdmiCecConfig; @@ -282,6 +282,20 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); } + protected void enableAdjustOnlyAbsoluteVolumeBehavior() { + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); + enableSystemAudioModeIfNeeded(); + receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); + receiveReportAudioStatus( + INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume(), + INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()); + + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); + } + protected void verifyGiveAudioStatusNeverSent() { assertThat(mNativeWrapper.getResultMessages()).doesNotContain( HdmiCecMessageBuilder.buildGiveAudioStatus( @@ -462,6 +476,7 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); } + @Test public void avbEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges() { // Initial has volume=50 and mute=false diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BasePlaybackDeviceAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BasePlaybackDeviceAvbTest.java new file mode 100644 index 0000000000000..4c12e436542b2 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/BasePlaybackDeviceAvbTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import android.hardware.hdmi.DeviceFeatures; +import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.HdmiDeviceInfo; +import android.media.AudioDeviceAttributes; +import android.media.AudioManager; + +import org.junit.Test; + +/** + * Base class for tests for absolute volume behavior on Playback devices. Contains tests that are + * relevant to Playback devices but not to TVs. + * + * Subclasses contain tests for the following pairs of (local device, System Audio device): + * (Playback, TV): {@link PlaybackDeviceToTvAvbTest} + * (Playback, Audio System): {@link PlaybackDeviceToAudioSystemAvbTest} + */ +public abstract class BasePlaybackDeviceAvbTest extends BaseAbsoluteVolumeBehaviorTest { + + @Override + protected HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService) { + return new HdmiCecLocalDevicePlayback(hdmiControlService); + } + + @Override + protected int getPhysicalAddress() { + return 0x1100; + } + + @Override + protected int getDeviceType() { + return HdmiDeviceInfo.DEVICE_PLAYBACK; + } + + @Override + protected AudioDeviceAttributes getAudioOutputDevice() { + return HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI; + } + + /** + * Unlike TVs, Playback devices don't start the process for adopting adjust-only AVB + * if the System Audio device doesn't support + */ + @Test + public void savlNotSupported_allOtherConditionsMet_giveAudioStatusNotSent() { + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); + enableSystemAudioModeIfNeeded(); + + receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); + verifyGiveAudioStatusNeverSent(); + } +} diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java index 3bcfac38e85b7..7294ba62cdae7 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java @@ -188,6 +188,17 @@ public class FakeAudioFramework { boolean handlesVolumeAdjustment) { setVolumeBehaviorHelper(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); } + + @Override + public void setDeviceAbsoluteVolumeAdjustOnlyBehavior( + @NonNull AudioDeviceAttributes device, + @NonNull VolumeInfo volume, + @NonNull @CallbackExecutor Executor executor, + @NonNull OnAudioDeviceVolumeChangedListener vclistener, + boolean handlesVolumeAdjustment) { + setVolumeBehaviorHelper(device, + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); + } } /** diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java index abfe0e2e6db8a..43ab804e04bee 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java @@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat; import android.hardware.hdmi.DeviceFeatures; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; -import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.platform.test.annotations.Presubmit; @@ -42,27 +41,7 @@ import java.util.Arrays; @SmallTest @Presubmit @RunWith(JUnit4.class) -public class PlaybackDeviceToAudioSystemAvbTest extends BaseAbsoluteVolumeBehaviorTest { - - @Override - protected HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService) { - return new HdmiCecLocalDevicePlayback(hdmiControlService); - } - - @Override - protected int getPhysicalAddress() { - return 0x1100; - } - - @Override - protected int getDeviceType() { - return HdmiDeviceInfo.DEVICE_PLAYBACK; - } - - @Override - protected AudioDeviceAttributes getAudioOutputDevice() { - return HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI; - } +public class PlaybackDeviceToAudioSystemAvbTest extends BasePlaybackDeviceAvbTest { @Override protected int getSystemAudioDeviceLogicalAddress() { diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java index c65b26a1e8bfe..9b343e34706a0 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.clearInvocations; import android.hardware.hdmi.DeviceFeatures; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; -import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.platform.test.annotations.Presubmit; @@ -43,27 +42,7 @@ import java.util.Collections; @SmallTest @Presubmit @RunWith(JUnit4.class) -public class PlaybackDeviceToTvAvbTest extends BaseAbsoluteVolumeBehaviorTest { - - @Override - protected HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService) { - return new HdmiCecLocalDevicePlayback(hdmiControlService); - } - - @Override - protected int getPhysicalAddress() { - return 0x1100; - } - - @Override - protected int getDeviceType() { - return HdmiDeviceInfo.DEVICE_PLAYBACK; - } - - @Override - protected AudioDeviceAttributes getAudioOutputDevice() { - return HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI; - } +public class PlaybackDeviceToTvAvbTest extends BasePlaybackDeviceAvbTest { @Override protected int getSystemAudioDeviceLogicalAddress() { diff --git a/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java index 64b69fb1e8ba7..079ef2e36673e 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java @@ -16,12 +16,30 @@ package com.android.server.hdmi; +import static com.android.server.hdmi.HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.hardware.hdmi.DeviceFeatures; +import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.media.AudioDeviceAttributes; +import android.media.AudioDeviceVolumeManager; +import android.media.AudioManager; +import android.media.VolumeInfo; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -63,4 +81,185 @@ public class TvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehaviorTest { protected int getSystemAudioDeviceType() { return HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM; } + + /** + * TVs start the process for adopting adjust-only AVB if the System Audio device doesn't + * support + */ + @Test + public void savlNotSupported_allOtherConditionsMet_giveAudioStatusSent() { + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); + enableSystemAudioModeIfNeeded(); + verifyGiveAudioStatusNeverSent(); + + receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); + verifyGiveAudioStatusSent(); + } + + @Test + public void savlNotSupported_systemAudioDeviceSendsReportAudioStatus_adjustOnlyAvbEnabled() { + mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); + enableSystemAudioModeIfNeeded(); + receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); + + // Adjust-only AVB should not be enabled before receiving + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + + receiveReportAudioStatus(20, false); + + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); + + verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeAdjustOnlyBehavior( + eq(getAudioOutputDevice()), + eq(new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setVolumeIndex(20) + .setMuted(false) + .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) + .setMinVolumeIndex(AudioStatus.MIN_VOLUME) + .build()), + any(), any(), anyBoolean()); + } + + + @Test + public void avbEnabled_savlNotSupported_receiveReportAudioStatus_switchToAdjustOnlyAvb() { + enableAbsoluteVolumeBehavior(); + + receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); + + receiveReportAudioStatus(40, true); + + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); + + verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeAdjustOnlyBehavior( + eq(getAudioOutputDevice()), + eq(new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setVolumeIndex(40) + .setMuted(true) + .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) + .setMinVolumeIndex(AudioStatus.MIN_VOLUME) + .build()), + any(), any(), anyBoolean()); + } + + @Test + public void avbEnabled_savlFeatureAborted_receiveReportAudioStatus_switchToAdjustOnlyAvb() { + enableAbsoluteVolumeBehavior(); + + mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildFeatureAbortCommand( + getSystemAudioDeviceLogicalAddress(), getLogicalAddress(), + Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, Constants.ABORT_UNRECOGNIZED_OPCODE)); + mTestLooper.dispatchAll(); + + receiveReportAudioStatus(40, true); + + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); + + verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeAdjustOnlyBehavior( + eq(getAudioOutputDevice()), + eq(new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setVolumeIndex(40) + .setMuted(true) + .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) + .setMinVolumeIndex(AudioStatus.MIN_VOLUME) + .build()), + any(), any(), anyBoolean()); + } + + @Test + public void adjustOnlyAvbEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges() { + enableAdjustOnlyAbsoluteVolumeBehavior(); + + // New volume and mute status: sets both + receiveReportAudioStatus(20, true); + verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(5), + anyInt()); + verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), + eq(AudioManager.ADJUST_MUTE), anyInt()); + clearInvocations(mAudioManager); + + // New volume only: sets volume only + receiveReportAudioStatus(32, true); + verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), + anyInt()); + verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), + eq(AudioManager.ADJUST_MUTE), anyInt()); + clearInvocations(mAudioManager); + + // New mute status only: sets mute only + receiveReportAudioStatus(32, false); + verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), + anyInt()); + verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), + eq(AudioManager.ADJUST_UNMUTE), anyInt()); + clearInvocations(mAudioManager); + + // Repeat of earlier message: sets neither volume nor mute + receiveReportAudioStatus(32, false); + verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), + anyInt()); + verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), + eq(AudioManager.ADJUST_UNMUTE), anyInt()); + + // Volume not within range [0, 100]: sets neither volume nor mute + receiveReportAudioStatus(127, true); + verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(), + anyInt()); + verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(), + anyInt()); + } + + @Test + public void adjustOnlyAvbEnabled_audioDeviceVolumeAdjusted_sendsUcpAndGiveAudioStatus() { + enableAdjustOnlyAbsoluteVolumeBehavior(); + mNativeWrapper.clearResultMessages(); + + mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeAdjusted( + getAudioOutputDevice(), + new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) + .setMinVolumeIndex(AudioStatus.MIN_VOLUME) + .build(), + AudioManager.ADJUST_RAISE, + AudioDeviceVolumeManager.ADJUST_MODE_NORMAL + ); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).contains( + HdmiCecMessageBuilder.buildUserControlPressed(getLogicalAddress(), + getSystemAudioDeviceLogicalAddress(), CEC_KEYCODE_VOLUME_UP)); + assertThat(mNativeWrapper.getResultMessages()).contains( + HdmiCecMessageBuilder.buildUserControlReleased(getLogicalAddress(), + getSystemAudioDeviceLogicalAddress())); + assertThat(mNativeWrapper.getResultMessages()).contains( + HdmiCecMessageBuilder.buildGiveAudioStatus(getLogicalAddress(), + getSystemAudioDeviceLogicalAddress())); + } + + @Test + public void adjustOnlyAvbEnabled_audioDeviceVolumeChanged_doesNotSendSetAudioVolumeLevel() { + enableAdjustOnlyAbsoluteVolumeBehavior(); + + mNativeWrapper.clearResultMessages(); + + mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged( + getAudioOutputDevice(), + new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setVolumeIndex(20) + .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) + .setMinVolumeIndex(AudioStatus.MIN_VOLUME) + .build() + ); + mTestLooper.dispatchAll(); + + assertThat(mNativeWrapper.getResultMessages()).isEmpty(); + } } From 7298a68a881dfd9b89593f970fc8155da9309a61 Mon Sep 17 00:00:00 2001 From: Yan Han Date: Tue, 2 May 2023 17:33:37 +0200 Subject: [PATCH 5/5] Check for feature flag for numeric volume UI Bug: 240663266 Test: atest Change-Id: Ifb84df22a247190bc9c967f57a1402e3a3515d98 --- .../com/android/server/hdmi/Constants.java | 6 +++++- .../server/hdmi/HdmiControlService.java | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java index c235299e3a65c..090d728aedc88 100644 --- a/services/core/java/com/android/server/hdmi/Constants.java +++ b/services/core/java/com/android/server/hdmi/Constants.java @@ -631,10 +631,14 @@ final class Constants { static final String DEVICE_CONFIG_FEATURE_FLAG_ENABLE_EARC_TX = "enable_earc_tx"; static final String DEVICE_CONFIG_FEATURE_FLAG_TRANSITION_ARC_TO_EARC_TX = "transition_arc_to_earc_tx"; + // Name is abbreviated slightly to avoid line length issues + static final String DEVICE_CONFIG_FEATURE_FLAG_TV_NUMERIC_SOUNDBAR_VOLUME_UI = + "enable_numeric_soundbar_volume_ui_on_tv"; @StringDef({ DEVICE_CONFIG_FEATURE_FLAG_SOUNDBAR_MODE, DEVICE_CONFIG_FEATURE_FLAG_ENABLE_EARC_TX, - DEVICE_CONFIG_FEATURE_FLAG_TRANSITION_ARC_TO_EARC_TX + DEVICE_CONFIG_FEATURE_FLAG_TRANSITION_ARC_TO_EARC_TX, + DEVICE_CONFIG_FEATURE_FLAG_TV_NUMERIC_SOUNDBAR_VOLUME_UI }) @interface FeatureFlag {} diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 9edab6da1a7ee..e87ed0a32a972 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -457,6 +457,9 @@ public class HdmiControlService extends SystemService { @ServiceThreadOnly private boolean mEarcTxFeatureFlagEnabled = false; + @ServiceThreadOnly + private boolean mNumericSoundbarVolumeUiOnTvFeatureFlagEnabled = false; + @ServiceThreadOnly private boolean mTransitionFromArcToEarcTxEnabled = false; @@ -682,6 +685,8 @@ public class HdmiControlService extends SystemService { Constants.DEVICE_CONFIG_FEATURE_FLAG_ENABLE_EARC_TX, false); mTransitionFromArcToEarcTxEnabled = mDeviceConfig.getBoolean( Constants.DEVICE_CONFIG_FEATURE_FLAG_TRANSITION_ARC_TO_EARC_TX, false); + mNumericSoundbarVolumeUiOnTvFeatureFlagEnabled = mDeviceConfig.getBoolean( + Constants.DEVICE_CONFIG_FEATURE_FLAG_TV_NUMERIC_SOUNDBAR_VOLUME_UI, false); synchronized (mLock) { mEarcEnabled = (mHdmiCecConfig.getIntValue( @@ -901,6 +906,17 @@ public class HdmiControlService extends SystemService { false); } }); + + mDeviceConfig.addOnPropertiesChangedListener(getContext().getMainExecutor(), + new DeviceConfig.OnPropertiesChangedListener() { + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + mNumericSoundbarVolumeUiOnTvFeatureFlagEnabled = properties.getBoolean( + Constants.DEVICE_CONFIG_FEATURE_FLAG_TV_NUMERIC_SOUNDBAR_VOLUME_UI, + false); + checkAndUpdateAbsoluteVolumeBehavior(); + } + }); } /** Returns true if the device screen is off */ boolean isScreenOff() { @@ -4337,7 +4353,7 @@ public class HdmiControlService extends SystemService { case DeviceFeatures.FEATURE_NOT_SUPPORTED: // TVs may adopt adjust-only absolute volume behavior if condition 4 isn't met. // This allows the device to display numeric volume UI for the System Audio device. - if (tv() != null) { + if (tv() != null && mNumericSoundbarVolumeUiOnTvFeatureFlagEnabled) { if (currentVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) { // If we're currently using absolute volume behavior, switch to full volume