blob: 759b271e73eb44d3886eca236c530c2d1e0d3e6c [file] [log] [blame]
/*
* Copyright (C) 2021 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.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM;
import static com.android.server.hdmi.HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP;
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;
import android.content.Context;
import android.content.ContextWrapper;
import android.hardware.hdmi.DeviceFeatures;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceVolumeManager;
import android.media.AudioManager;
import android.media.VolumeInfo;
import android.os.Looper;
import android.os.RemoteException;
import android.os.test.TestLooper;
import androidx.test.InstrumentationRegistry;
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;
import java.util.Arrays;
import java.util.Collections;
/**
* Tests that absolute volume behavior (AVB) is enabled and disabled correctly, and that
* the device responds correctly to incoming <Report Audio Status> messages and API calls
* 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 PlaybackDeviceToTvAvbTest}
* (Playback, Audio System): {@link PlaybackDeviceToAudioSystemAvbTest}
* (TV, Audio System): {@link TvToAudioSystemAvbTest}
*/
public abstract class BaseAbsoluteVolumeBehaviorTest {
private HdmiControlService mHdmiControlService;
private HdmiCecController mHdmiCecController;
private HdmiCecLocalDevice mHdmiCecLocalDevice;
private FakeHdmiCecConfig mHdmiCecConfig;
private FakePowerManagerWrapper mPowerManager;
private Looper mLooper;
private Context mContextSpy;
private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
@Mock protected AudioManager mAudioManager;
protected FakeAudioDeviceVolumeManagerWrapper mAudioDeviceVolumeManager;
protected TestLooper mTestLooper = new TestLooper();
protected FakeNativeWrapper mNativeWrapper;
// Audio Status given by the System Audio device in its initial <Report Audio Status> 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 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())
.setMaxVolumeIndex(AudioStatus.MAX_VOLUME)
.setMinVolumeIndex(AudioStatus.MIN_VOLUME)
.build();
protected abstract HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService);
protected abstract int getPhysicalAddress();
protected abstract int getDeviceType();
protected abstract AudioDeviceAttributes getAudioOutputDevice();
protected abstract int getSystemAudioDeviceLogicalAddress();
protected abstract int getSystemAudioDeviceType();
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mContextSpy = spy(new ContextWrapper(
InstrumentationRegistry.getInstrumentation().getTargetContext()));
mAudioDeviceVolumeManager = spy(new FakeAudioDeviceVolumeManagerWrapper());
mHdmiControlService =
new HdmiControlService(InstrumentationRegistry.getTargetContext(),
Collections.singletonList(getDeviceType()),
mAudioDeviceVolumeManager) {
@Override
AudioManager getAudioManager() {
return mAudioManager;
}
@Override
protected void writeStringSystemProperty(String key, String value) {
// do nothing
}
};
mLooper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(mLooper);
mHdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
mHdmiCecConfig.setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
HdmiControlManager.HDMI_CEC_VERSION_2_0);
mHdmiCecConfig.setIntValue(
HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
HdmiControlManager.VOLUME_CONTROL_DISABLED);
mHdmiControlService.setHdmiCecConfig(mHdmiCecConfig);
mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
mNativeWrapper = new FakeNativeWrapper();
mNativeWrapper.setPhysicalAddress(getPhysicalAddress());
mNativeWrapper.setPollAddressResponse(Constants.ADDR_TV, SendMessageResult.SUCCESS);
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
mHdmiControlService.setCecController(mHdmiCecController);
mHdmiControlService.setHdmiMhlController(
HdmiMhlControllerStub.create(mHdmiControlService));
mHdmiControlService.initService();
mPowerManager = new FakePowerManagerWrapper(mContextSpy);
mHdmiControlService.setPowerManager(mPowerManager);
mHdmiCecLocalDevice = createLocalDevice(mHdmiControlService);
mHdmiCecLocalDevice.init();
mLocalDevices.add(mHdmiCecLocalDevice);
HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
hdmiPortInfos[0] =
new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_OUTPUT, 0x0000)
.setCecSupported(true)
.setMhlSupported(false)
.setArcSupported(false)
.build();
mNativeWrapper.setPortInfo(hdmiPortInfos);
mNativeWrapper.setPortConnectionStatus(1, true);
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);
// Max volume of STREAM_MUSIC
doReturn(25).when(mAudioManager).getStreamMaxVolume(AudioManager.STREAM_MUSIC);
// Receive messages from devices to make sure they're registered in HdmiCecNetwork
mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
Constants.ADDR_TV, getLogicalAddress()));
if (getSystemAudioDeviceType() == DEVICE_AUDIO_SYSTEM) {
mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
Constants.ADDR_AUDIO_SYSTEM, getLogicalAddress()));
}
mHdmiControlService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
mHdmiControlService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
mTestLooper.dispatchAll();
}
protected int getLogicalAddress() {
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.
*/
protected void setCecVolumeControlSetting(@HdmiControlManager.VolumeControl int setting) {
mHdmiControlService.getHdmiCecConfig().setIntValue(
HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, setting);
mTestLooper.dispatchAll();
}
/**
* Has the device receive a <Report Features> message from the System Audio device specifying
* whether <Set Audio Volume Level> is supported or not.
*/
protected void receiveSetAudioVolumeLevelSupport(
@DeviceFeatures.FeatureSupportStatus int featureSupportStatus) {
// <Report Features> can't specify an unknown feature support status
if (featureSupportStatus != DeviceFeatures.FEATURE_SUPPORT_UNKNOWN) {
mNativeWrapper.onCecMessage(ReportFeaturesMessage.build(
getSystemAudioDeviceLogicalAddress(), HdmiControlManager.HDMI_CEC_VERSION_2_0,
Arrays.asList(getSystemAudioDeviceType()), Constants.RC_PROFILE_SOURCE,
Collections.emptyList(),
DeviceFeatures.NO_FEATURES_SUPPORTED.toBuilder()
.setSetAudioVolumeLevelSupport(featureSupportStatus)
.build()));
mTestLooper.dispatchAll();
}
}
/**
* Enables System Audio mode if the System Audio device is an Audio System.
*/
protected void enableSystemAudioModeIfNeeded() {
if (getSystemAudioDeviceType() == DEVICE_AUDIO_SYSTEM) {
receiveSetSystemAudioMode(true);
}
}
/**
* Sets System Audio Mode by having the device receive <Set System Audio Mode>
* from the Audio System.
*/
protected void receiveSetSystemAudioMode(boolean status) {
mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildSetSystemAudioMode(
Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_BROADCAST, status));
mTestLooper.dispatchAll();
}
/**
* Has the device receive a <Report Audio Status> 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 <Report Audio Status> message from the System Audio Device.
*/
protected void receiveReportAudioStatus(int volume, boolean mute) {
mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildReportAudioStatus(
getSystemAudioDeviceLogicalAddress(),
getLogicalAddress(),
volume,
mute));
mTestLooper.dispatchAll();
}
/**
* Triggers all the conditions required to enable absolute volume behavior.
*/
protected void enableAbsoluteVolumeBehavior() {
setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED);
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED);
enableSystemAudioModeIfNeeded();
receiveInitialReportAudioStatus();
verifyAbsoluteVolumeEnabled();
}
/**
* Verifies that the audio output device's volume behavior was last set to
* absolute volume behavior.
*/
protected void verifyAbsoluteVolumeEnabled() {
InOrder inOrder = inOrder(mAudioManager, mAudioDeviceVolumeManager);
inOrder.verify(mAudioDeviceVolumeManager, atLeastOnce()).setDeviceAbsoluteVolumeBehavior(
eq(getAudioOutputDevice()), any(), any(), any(), anyBoolean());
inOrder.verify(mAudioManager, never()).setDeviceVolumeBehavior(
eq(getAudioOutputDevice()), not(eq(AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE)));
}
/**
* Verifies that the audio output device's volume behavior was last set to something other than
* absolute volume behavior.
*/
protected void verifyAbsoluteVolumeDisabled() {
InOrder inOrder = inOrder(mAudioManager, mAudioDeviceVolumeManager);
inOrder.verify(mAudioManager, atLeastOnce()).setDeviceVolumeBehavior(
eq(getAudioOutputDevice()), not(eq(AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE)));
inOrder.verify(mAudioDeviceVolumeManager, never()).setDeviceAbsoluteVolumeBehavior(
eq(getAudioOutputDevice()), any(), any(), any(), anyBoolean());
}
protected void verifyGiveAudioStatusNeverSent() {
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(
HdmiCecMessageBuilder.buildGiveAudioStatus(
getLogicalAddress(), getSystemAudioDeviceLogicalAddress()));
}
protected void verifyGiveAudioStatusSent() {
assertThat(mNativeWrapper.getResultMessages()).contains(
HdmiCecMessageBuilder.buildGiveAudioStatus(
getLogicalAddress(), getSystemAudioDeviceLogicalAddress()));
}
@Test
public void allConditionsExceptSavlSupportMet_sendsSetAudioVolumeLevelAndGiveFeatures() {
setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED);
enableSystemAudioModeIfNeeded();
assertThat(mNativeWrapper.getResultMessages()).contains(
SetAudioVolumeLevelMessage.build(
getLogicalAddress(), getSystemAudioDeviceLogicalAddress(),
Constants.AUDIO_VOLUME_STATUS_UNKNOWN));
assertThat(mNativeWrapper.getResultMessages()).contains(
HdmiCecMessageBuilder.buildGiveFeatures(
getLogicalAddress(), getSystemAudioDeviceLogicalAddress()));
}
@Test
public void allConditionsMet_savlSupportLast_reportFeatures_giveAudioStatusSent() {
setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED);
enableSystemAudioModeIfNeeded();
verifyGiveAudioStatusNeverSent();
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED);
verifyGiveAudioStatusSent();
}
@Test
public void allConditionsMet_savlSupportLast_noFeatureAbort_giveAudioStatusSent() {
setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED);
enableSystemAudioModeIfNeeded();
verifyGiveAudioStatusNeverSent();
mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
mTestLooper.dispatchAll();
verifyGiveAudioStatusSent();
}
@Test
public void allConditionsMet_cecVolumeEnabledLast_giveAudioStatusSent() {
setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
enableSystemAudioModeIfNeeded();
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED);
verifyGiveAudioStatusNeverSent();
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED);
verifyGiveAudioStatusSent();
}
@Test
public void allConditionsMet_fullVolumeBehaviorLast_giveAudioStatusSent() {
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED);
enableSystemAudioModeIfNeeded();
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED);
verifyGiveAudioStatusNeverSent();
setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
verifyGiveAudioStatusSent();
}
@Test
public void allConditionsMet_systemAudioModeEnabledLast_giveAudioStatusSent() {
// 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);
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED);
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED);
verifyGiveAudioStatusNeverSent();
receiveSetSystemAudioMode(true);
verifyGiveAudioStatusSent();
}
@Test
public void giveAudioStatusSent_systemAudioDeviceSendsReportAudioStatus_avbEnabled() {
setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED);
enableSystemAudioModeIfNeeded();
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED);
setDeviceVolumeBehavior(getAudioOutputDevice(), AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL);
// Verify that AVB was never enabled
verify(mAudioDeviceVolumeManager, never()).setDeviceAbsoluteVolumeBehavior(
eq(getAudioOutputDevice()), any(), any(), any(), anyBoolean());
receiveInitialReportAudioStatus();
verifyAbsoluteVolumeEnabled();
}
@Test
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();
}
@Test
public void avbEnabled_setAudioVolumeLevelNotSupported_avbDisabled() {
enableAbsoluteVolumeBehavior();
receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED);
verifyAbsoluteVolumeDisabled();
}
@Test
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();
}
@Test
public void avbEnabled_systemAudioModeDisabled_avbDisabled() {
// Only run when the System Audio device is an Audio System.
assume().that(getSystemAudioDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
enableAbsoluteVolumeBehavior();
receiveSetSystemAudioMode(false);
verifyAbsoluteVolumeDisabled();
}
@Test
public void avbEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges() {
// Initial <Report Audio Status> has volume=50 and mute=false
enableAbsoluteVolumeBehavior();
// 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());
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 <Set Audio Volume Level>, the System Audio device's
// volume changes. Afterward, a duplicate of an earlier <Report Audio Status> should
// still cause us to call setStreamVolume()
mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged(
getAudioOutputDevice(),
new VolumeInfo.Builder(ENABLE_AVB_VOLUME_INFO)
.setVolumeIndex(20)
.build()
);
mTestLooper.dispatchAll();
receiveReportAudioStatus(32, false);
verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
anyInt());
verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
eq(AudioManager.ADJUST_UNMUTE), anyInt());
}
@Test
public void avbEnabled_audioDeviceVolumeAdjusted_sendsUserControlPressedAndGiveAudioStatus() {
enableAbsoluteVolumeBehavior();
mNativeWrapper.clearResultMessages();
mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeAdjusted(
getAudioOutputDevice(),
ENABLE_AVB_VOLUME_INFO,
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 avbEnabled_audioDeviceVolumeChanged_sendsSetAudioVolumeLevel() {
enableAbsoluteVolumeBehavior();
mNativeWrapper.clearResultMessages();
mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged(
getAudioOutputDevice(),
new VolumeInfo.Builder(ENABLE_AVB_VOLUME_INFO)
.setVolumeIndex(20)
.build()
);
mTestLooper.dispatchAll();
assertThat(mNativeWrapper.getResultMessages()).contains(
SetAudioVolumeLevelMessage.build(getLogicalAddress(),
getSystemAudioDeviceLogicalAddress(), 20));
}
}