diff --git a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java index d7563e085e614..d764ec41b3b96 100644 --- a/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java +++ b/services/core/java/com/android/server/hdmi/AbsoluteVolumeAudioStatusAction.java @@ -17,11 +17,14 @@ 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 - * enables the feature upon receiving a response. - * 2. While AVC is enabled: monitors messages from the System Audio device and + * 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 + * 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. */ final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction { @@ -74,16 +77,23 @@ 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); + 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/AudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java index 438c1ea01e29f..94842041af827 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,48 @@ 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); + + /** + * 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/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/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/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/DefaultAudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java new file mode 100644 index 0000000000000..ff99ace38ef0e --- /dev/null +++ b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java @@ -0,0 +1,81 @@ +/* + * 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.CallbackExecutor; +import android.annotation.NonNull; +import android.content.Context; +import android.media.AudioDeviceAttributes; +import android.media.AudioDeviceVolumeManager; +import android.media.VolumeInfo; + +import java.util.concurrent.Executor; + +/** + * "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 DefaultAudioDeviceVolumeManagerWrapper + implements AudioDeviceVolumeManagerWrapper { + + private static final String TAG = "AudioDeviceVolumeManagerWrapper"; + + private final AudioDeviceVolumeManager mAudioDeviceVolumeManager; + + public DefaultAudioDeviceVolumeManagerWrapper(Context context) { + mAudioDeviceVolumeManager = new AudioDeviceVolumeManager(context); + } + + @Override + public void addOnDeviceVolumeBehaviorChangedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener) + throws SecurityException { + mAudioDeviceVolumeManager.addOnDeviceVolumeBehaviorChangedListener(executor, listener); + } + + @Override + public void removeOnDeviceVolumeBehaviorChangedListener( + @NonNull AudioDeviceVolumeManager.OnDeviceVolumeBehaviorChangedListener listener) { + mAudioDeviceVolumeManager.removeOnDeviceVolumeBehaviorChangedListener(listener); + } + + @Override + public 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); + } + + @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/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/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 35c70fbce8ad8..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(); } - void addAvcAudioStatusAction(int targetAddress) { + @ServiceThreadOnly + void addAvbAudioStatusAction(int targetAddress) { + assertRunOnServiceThread(); if (!hasAction(AbsoluteVolumeAudioStatusAction.class)) { addAndStartAction(new AbsoluteVolumeAudioStatusAction(this, targetAddress)); } } - void removeAvcAudioStatusAction() { + @ServiceThreadOnly + void removeAvbAudioStatusAction() { + assertRunOnServiceThread(); removeAction(AbsoluteVolumeAudioStatusAction.class); } - void updateAvcVolume(int volumeIndex) { + @ServiceThreadOnly + void updateAvbVolume(int volumeIndex) { + assertRunOnServiceThread(); for (AbsoluteVolumeAudioStatusAction action : getActions(AbsoluteVolumeAudioStatusAction.class)) { action.updateVolume(volumeIndex); @@ -1035,7 +1041,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 +1060,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/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/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..e87ed0a32a972 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<>(); @@ -457,6 +457,9 @@ public class HdmiControlService extends SystemService { @ServiceThreadOnly private boolean mEarcTxFeatureFlagEnabled = false; + @ServiceThreadOnly + private boolean mNumericSoundbarVolumeUiOnTvFeatureFlagEnabled = false; + @ServiceThreadOnly private boolean mTransitionFromArcToEarcTxEnabled = false; @@ -491,10 +494,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 +531,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; } @@ -680,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( @@ -899,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() { @@ -933,11 +951,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 +988,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 +1788,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) { @@ -2751,7 +2766,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 +2934,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 @@ -3485,7 +3500,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 +3508,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; } @@ -3882,7 +3897,7 @@ public class HdmiControlService extends SystemService { synchronized (mLock) { mSystemAudioActivated = on; } - runOnServiceThread(this::checkAndUpdateAbsoluteVolumeControlState); + runOnServiceThread(this::checkAndUpdateAbsoluteVolumeBehavior); } @ServiceThreadOnly @@ -3993,7 +4008,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 +4204,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 +4224,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,25 +4235,29 @@ 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) - == 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 getAvcAudioOutputDevice() { - if (isTvDevice()) { + private AudioDeviceAttributes getAvbAudioOutputDevice() { + if (tv() != null) { return tv().getSystemAudioOutputDevice(); - } else if (isPlaybackDevice()) { + } else if (playback() != null) { return AUDIO_OUTPUT_DEVICE_HDMI; } else { return null; @@ -4246,30 +4265,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 - * (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. * - * AVC 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 AVC (i.e. it supports ) + * 4. The System Audio device supports the message * - * If not all of these conditions are met, this method disables AVC 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. + * 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 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,84 +4300,110 @@ 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(); + switchToFullVolumeBehavior(); 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( + HdmiDeviceInfo systemAudioDeviceInfo = getDeviceInfo( localCecDevice.findAudioReceiverAddress()); @AudioManager.DeviceVolumeBehavior int currentVolumeBehavior = - getDeviceVolumeBehavior(getAvcAudioOutputDevice()); + 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) { - disableAbsoluteVolumeControl(); + switchToFullVolumeBehavior(); 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(); + switchToFullVolumeBehavior(); return; } - // Condition 4: The System Audio device supports AVC (i.e. ). + + // Condition 4: The System Audio device supports switch (systemAudioDeviceInfo.getDeviceFeatures().getSetAudioVolumeLevelSupport()) { case DeviceFeatures.FEATURE_SUPPORTED: - if (!isAbsoluteVolumeControlEnabled()) { - // Start an action that will call {@link #enableAbsoluteVolumeControl} + 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.addAvcAudioStatusAction( + localCecDevice.addAvbAudioStatusAction( systemAudioDeviceInfo.getLogicalAddress()); } return; case DeviceFeatures.FEATURE_NOT_SUPPORTED: - disableAbsoluteVolumeControl(); + // 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 && mNumericSoundbarVolumeUiOnTvFeatureFlagEnabled) { + 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: - disableAbsoluteVolumeControl(); - localCecDevice.queryAvcSupport(systemAudioDeviceInfo.getLogicalAddress()); - return; - default: - return; + switchToFullVolumeBehavior(); + localCecDevice.querySetAudioVolumeLevelSupport( + systemAudioDeviceInfo.getLogicalAddress()); } } - private void disableAbsoluteVolumeControl() { - if (isPlaybackDevice()) { - playback().removeAvcAudioStatusAction(); - } else if (isTvDevice()) { - tv().removeAvcAudioStatusAction(); + /** + * 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 (tv() != null) { + tv().removeAvbAudioStatusAction(); } - AudioDeviceAttributes device = getAvcAudioOutputDevice(); - if (getDeviceVolumeBehavior(device) == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE) { + AudioDeviceAttributes device = getAvbAudioOutputDevice(); + 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 Control. Should only be called when all the conditions for - * AVC are met (see {@link #checkAndUpdateAbsoluteVolumeControlState}). + * 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 enableAbsoluteVolumeControl(AudioStatus audioStatus) { + 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()) @@ -4370,10 +4415,21 @@ 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()); - getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeBehavior( - getAvcAudioOutputDevice(), volumeInfo, mServiceThreadExecutor, - mAbsoluteVolumeChangedListener, true); + notifyAvbMuteChange(audioStatus.getMute()); + + // 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 +4463,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, @@ -4418,8 +4482,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 +4541,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 +4558,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/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 a7fe64adf1ff8..be5e2623ac205 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/BaseAbsoluteVolumeControlTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java similarity index 71% 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 9f295b8f42c2f..bc09d4b107230 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeControlTest.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; @@ -68,20 +61,20 @@ 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 { - private HdmiControlService mHdmiControlService; +public abstract class BaseAbsoluteVolumeBehaviorTest { + protected HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private HdmiCecLocalDevice mHdmiCecLocalDevice; private FakeHdmiCecConfig mHdmiCecConfig; @@ -90,19 +83,20 @@ public abstract class BaseAbsoluteVolumeControlTest { 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 AVC 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); - // 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()) @@ -110,6 +104,8 @@ public abstract class BaseAbsoluteVolumeControlTest { .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 BaseAbsoluteVolumeControlTest { 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 BaseAbsoluteVolumeControlTest { 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 BaseAbsoluteVolumeControlTest { 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 BaseAbsoluteVolumeControlTest { 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. */ @@ -300,40 +266,34 @@ 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() { - setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); + protected void enableAbsoluteVolumeBehavior() { + 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(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); } - /** - * Verifies that AVC was enabled - that is 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))); - } + 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()); - /** - * Verifies that AVC was disabled - that is, 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_ADJUST_ONLY); } protected void verifyGiveAudioStatusNeverSent() { @@ -350,7 +310,8 @@ public abstract class BaseAbsoluteVolumeControlTest { @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 +326,8 @@ public abstract class BaseAbsoluteVolumeControlTest { @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 +338,8 @@ public abstract class BaseAbsoluteVolumeControlTest { @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 +351,8 @@ public abstract class BaseAbsoluteVolumeControlTest { @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 +368,9 @@ public abstract class BaseAbsoluteVolumeControlTest { 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 +379,8 @@ public abstract class BaseAbsoluteVolumeControlTest { // 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(); @@ -423,62 +390,97 @@ public abstract class BaseAbsoluteVolumeControlTest { } @Test - public void giveAudioStatusSent_systemAudioDeviceSendsReportAudioStatus_avcEnabled() { + 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 AVC 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 - public void avcEnabled_cecVolumeDisabled_absoluteVolumeDisabled() { - enableAbsoluteVolumeControl(); + public void giveAudioStatusSent_reportAudioStatusVolumeOutOfBounds_avbNotEnabled() { + 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 avbEnabled_cecVolumeDisabled_avbDisabled() { + enableAbsoluteVolumeBehavior(); setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_DISABLED); - verifyAbsoluteVolumeDisabled(); + + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); } @Test - public void avcEnabled_setAudioVolumeLevelNotSupported_absoluteVolumeDisabled() { - enableAbsoluteVolumeControl(); + public void avbEnabled_setAudioVolumeLevelNotSupported_avbDisabled() { + enableAbsoluteVolumeBehavior(); receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); - verifyAbsoluteVolumeDisabled(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); } @Test - public void avcEnabled_setAudioVolumeLevelFeatureAborted_absoluteVolumeDisabled() { - enableAbsoluteVolumeControl(); + public void avbEnabled_setAudioVolumeLevelFeatureAborted_avbDisabled() { + enableAbsoluteVolumeBehavior(); mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildFeatureAbortCommand( 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 - 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(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); } @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); @@ -512,12 +514,20 @@ 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() mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged( getAudioOutputDevice(), - new VolumeInfo.Builder(ENABLE_AVC_VOLUME_INFO) + new VolumeInfo.Builder(ENABLE_AVB_VOLUME_INFO) .setVolumeIndex(20) .build() ); @@ -530,13 +540,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 ); @@ -554,14 +564,16 @@ 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(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/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/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/FakeAudioDeviceVolumeManagerWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioDeviceVolumeManagerWrapper.java deleted file mode 100644 index d33ef9bc88799..0000000000000 --- a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioDeviceVolumeManagerWrapper.java +++ /dev/null @@ -1,72 +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.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. - */ -public class FakeAudioDeviceVolumeManagerWrapper implements - AudioDeviceVolumeManagerWrapperInterface { - - private final Set mVolumeBehaviorListeners; - - public FakeAudioDeviceVolumeManagerWrapper() { - mVolumeBehaviorListeners = new HashSet<>(); - } - - @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) { - // Notify all volume behavior listeners that the device adopted absolute volume behavior - for (OnDeviceVolumeBehaviorChangedListener listener : mVolumeBehaviorListeners) { - listener.onDeviceVolumeBehaviorChanged(device, - AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); - } - } -} 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..7294ba62cdae7 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java @@ -0,0 +1,239 @@ +/* + * 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); + } + + @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); + } + } + + /** + * 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 81cfdbee78317..bdf3a5ffbd84e 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java @@ -58,9 +58,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/PlaybackDeviceToAudioSystemAvcTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java similarity index 72% 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..43ab804e04bee 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvcTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToAudioSystemAvbTest.java @@ -16,10 +16,12 @@ 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; @@ -33,33 +35,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 { - - @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() { @@ -72,17 +54,18 @@ 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(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); // TV reports support for mNativeWrapper.onCecMessage(ReportFeaturesMessage.build( @@ -102,6 +85,7 @@ public class PlaybackDeviceToAudioSystemAvcTest extends BaseAbsoluteVolumeContro 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/PlaybackDeviceToTvAvcTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java similarity index 73% 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..9b343e34706a0 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvcTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/PlaybackDeviceToTvAvbTest.java @@ -16,12 +16,14 @@ 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; @@ -34,33 +36,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 { - - @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() { @@ -73,17 +55,18 @@ 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(); + assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); clearInvocations(mAudioManager, mAudioDeviceVolumeManager); @@ -105,6 +88,7 @@ public class PlaybackDeviceToTvAvcTest extends BaseAbsoluteVolumeControlTest { 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 cac781509a930..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()); @@ -152,11 +154,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 +174,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 +191,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/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; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java new file mode 100644 index 0000000000000..079ef2e36673e --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvbTest.java @@ -0,0 +1,265 @@ +/* + * 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 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; + +/** + * 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 TvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehaviorTest { + + @Override + protected HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService) { + return new HdmiCecLocalDeviceTv(hdmiControlService); + } + + @Override + protected int getPhysicalAddress() { + return 0x0000; + } + + @Override + protected int getDeviceType() { + return HdmiDeviceInfo.DEVICE_TV; + } + + @Override + protected AudioDeviceAttributes getAudioOutputDevice() { + return HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI_ARC; + } + + @Override + protected int getSystemAudioDeviceLogicalAddress() { + return Constants.ADDR_AUDIO_SYSTEM; + } + + @Override + 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(); + } +} diff --git a/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvcTest.java b/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvcTest.java deleted file mode 100644 index 41c0e0d29879e..0000000000000 --- a/services/tests/servicestests/src/com/android/server/hdmi/TvToAudioSystemAvcTest.java +++ /dev/null @@ -1,66 +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 android.hardware.hdmi.HdmiDeviceInfo; -import android.media.AudioDeviceAttributes; -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; - -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 - * is an Audio System. Assumes that the TV uses ARC (rather than eARC). - */ -@SmallTest -@Presubmit -@RunWith(JUnit4.class) -public class TvToAudioSystemAvcTest extends BaseAbsoluteVolumeControlTest { - - @Override - protected HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService) { - return new HdmiCecLocalDeviceTv(hdmiControlService); - } - - @Override - protected int getPhysicalAddress() { - return 0x0000; - } - - @Override - protected int getDeviceType() { - return HdmiDeviceInfo.DEVICE_TV; - } - - @Override - protected AudioDeviceAttributes getAudioOutputDevice() { - return HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI_ARC; - } - - @Override - protected int getSystemAudioDeviceLogicalAddress() { - return Constants.ADDR_AUDIO_SYSTEM; - } - - @Override - protected int getSystemAudioDeviceType() { - return HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM; - } -}