1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.hdmi; 18 19 import static android.hardware.hdmi.DeviceFeatures.FEATURE_NOT_SUPPORTED; 20 import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORTED; 21 import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORT_UNKNOWN; 22 23 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static org.mockito.ArgumentMatchers.anyString; 28 import static org.mockito.Mockito.doNothing; 29 import static org.mockito.Mockito.spy; 30 31 import android.content.Context; 32 import android.content.ContextWrapper; 33 import android.hardware.hdmi.DeviceFeatures; 34 import android.hardware.hdmi.HdmiControlManager; 35 import android.hardware.hdmi.HdmiDeviceInfo; 36 import android.hardware.hdmi.IHdmiControlCallback; 37 import android.hardware.tv.cec.V1_0.SendMessageResult; 38 import android.os.Looper; 39 import android.os.RemoteException; 40 import android.os.test.TestLooper; 41 import android.platform.test.annotations.Presubmit; 42 43 import androidx.test.InstrumentationRegistry; 44 import androidx.test.filters.SmallTest; 45 46 import com.android.server.SystemService; 47 48 import org.junit.Before; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 import org.junit.runners.JUnit4; 52 53 import java.util.ArrayList; 54 import java.util.Collections; 55 56 @SmallTest 57 @Presubmit 58 @RunWith(JUnit4.class) 59 public class SetAudioVolumeLevelDiscoveryActionTest { 60 private HdmiControlService mHdmiControlServiceSpy; 61 private HdmiCecController mHdmiCecController; 62 private HdmiCecLocalDevicePlayback mPlaybackDevice; 63 private FakeNativeWrapper mNativeWrapper; 64 private FakePowerManagerWrapper mPowerManager; 65 private Looper mLooper; 66 private Context mContextSpy; 67 private TestLooper mTestLooper = new TestLooper(); 68 private int mPhysicalAddress = 0x1100; 69 private int mPlaybackLogicalAddress; 70 71 private TestCallback mTestCallback; 72 private SetAudioVolumeLevelDiscoveryAction mAction; 73 74 /** 75 * Setup: Local Playback device attempts to determine whether a connected TV supports 76 * <Set Audio Volume Level>. 77 */ 78 @Before setUp()79 public void setUp() throws RemoteException { 80 mContextSpy = spy(new ContextWrapper( 81 InstrumentationRegistry.getInstrumentation().getTargetContext())); 82 83 FakeAudioFramework audioFramework = new FakeAudioFramework(); 84 85 mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, 86 Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK), 87 audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager())); 88 doNothing().when(mHdmiControlServiceSpy) 89 .writeStringSystemProperty(anyString(), anyString()); 90 91 mLooper = mTestLooper.getLooper(); 92 mHdmiControlServiceSpy.setIoLooper(mLooper); 93 mHdmiControlServiceSpy.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy)); 94 mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper()); 95 96 mNativeWrapper = new FakeNativeWrapper(); 97 mNativeWrapper.setPhysicalAddress(mPhysicalAddress); 98 99 mHdmiCecController = HdmiCecController.createWithNativeWrapper( 100 mHdmiControlServiceSpy, mNativeWrapper, mHdmiControlServiceSpy.getAtomWriter()); 101 mHdmiControlServiceSpy.setCecController(mHdmiCecController); 102 mHdmiControlServiceSpy.setHdmiMhlController( 103 HdmiMhlControllerStub.create(mHdmiControlServiceSpy)); 104 mHdmiControlServiceSpy.initService(); 105 mHdmiControlServiceSpy.onBootPhase(PHASE_SYSTEM_SERVICES_READY); 106 mPowerManager = new FakePowerManagerWrapper(mContextSpy); 107 mHdmiControlServiceSpy.setPowerManager(mPowerManager); 108 109 mHdmiControlServiceSpy.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); 110 mTestLooper.dispatchAll(); 111 112 mPlaybackDevice = mHdmiControlServiceSpy.playback(); 113 mPlaybackLogicalAddress = mPlaybackDevice.getDeviceInfo().getLogicalAddress(); 114 115 // Setup specific to these tests 116 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( 117 Constants.ADDR_TV, 0x0000, HdmiDeviceInfo.DEVICE_TV)); 118 mTestLooper.dispatchAll(); 119 mTestCallback = new TestCallback(); 120 mAction = new SetAudioVolumeLevelDiscoveryAction(mPlaybackDevice, 121 Constants.ADDR_TV, mTestCallback); 122 } 123 124 @Test sendsSetAudioVolumeLevel()125 public void sendsSetAudioVolumeLevel() { 126 mPlaybackDevice.addAndStartAction(mAction); 127 mTestLooper.dispatchAll(); 128 129 HdmiCecMessage setAudioVolumeLevel = SetAudioVolumeLevelMessage.build( 130 mPlaybackLogicalAddress, Constants.ADDR_TV, 131 Constants.AUDIO_VOLUME_STATUS_UNKNOWN); 132 assertThat(mNativeWrapper.getResultMessages()).contains(setAudioVolumeLevel); 133 } 134 135 @Test noMatchingFeatureAbortReceived_actionSucceedsAndSetsFeatureSupported()136 public void noMatchingFeatureAbortReceived_actionSucceedsAndSetsFeatureSupported() { 137 mPlaybackDevice.addAndStartAction(mAction); 138 mTestLooper.dispatchAll(); 139 140 // Wrong opcode 141 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildFeatureAbortCommand( 142 Constants.ADDR_TV, 143 mPlaybackLogicalAddress, 144 Constants.MESSAGE_GIVE_DECK_STATUS, 145 Constants.ABORT_UNRECOGNIZED_OPCODE)); 146 // Wrong source 147 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildFeatureAbortCommand( 148 Constants.ADDR_AUDIO_SYSTEM, 149 mPlaybackLogicalAddress, 150 Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, 151 Constants.ABORT_UNRECOGNIZED_OPCODE)); 152 mTestLooper.dispatchAll(); 153 154 mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); 155 mTestLooper.dispatchAll(); 156 157 @DeviceFeatures.FeatureSupportStatus int savlSupport = 158 mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV) 159 .getDeviceFeatures().getSetAudioVolumeLevelSupport(); 160 161 assertThat(savlSupport).isEqualTo(FEATURE_SUPPORTED); 162 assertThat(mTestCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); 163 } 164 165 @Test matchingFeatureAbortReceived_actionSucceedsAndSetsFeatureNotSupported()166 public void matchingFeatureAbortReceived_actionSucceedsAndSetsFeatureNotSupported() { 167 mPlaybackDevice.addAndStartAction(mAction); 168 mTestLooper.dispatchAll(); 169 170 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildFeatureAbortCommand( 171 Constants.ADDR_TV, 172 mPlaybackLogicalAddress, 173 Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, 174 Constants.ABORT_UNRECOGNIZED_OPCODE)); 175 mTestLooper.dispatchAll(); 176 177 @DeviceFeatures.FeatureSupportStatus int savlSupport = 178 mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV) 179 .getDeviceFeatures().getSetAudioVolumeLevelSupport(); 180 181 assertThat(savlSupport).isEqualTo(FEATURE_NOT_SUPPORTED); 182 assertThat(mTestCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); 183 } 184 185 @Test messageFailedToSend_actionFailsAndDoesNotUpdateFeatureSupport()186 public void messageFailedToSend_actionFailsAndDoesNotUpdateFeatureSupport() { 187 mNativeWrapper.setMessageSendResult(Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, 188 SendMessageResult.FAIL); 189 mTestLooper.dispatchAll(); 190 191 mPlaybackDevice.addAndStartAction(mAction); 192 mTestLooper.dispatchAll(); 193 194 @DeviceFeatures.FeatureSupportStatus int savlSupport = 195 mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV) 196 .getDeviceFeatures().getSetAudioVolumeLevelSupport(); 197 198 assertThat(savlSupport).isEqualTo(FEATURE_SUPPORT_UNKNOWN); 199 assertThat(mTestCallback.getResult()).isEqualTo( 200 HdmiControlManager.RESULT_COMMUNICATION_FAILED); 201 } 202 203 private static class TestCallback extends IHdmiControlCallback.Stub { 204 private final ArrayList<Integer> mCallbackResult = new ArrayList<Integer>(); 205 206 @Override onComplete(int result)207 public void onComplete(int result) { 208 mCallbackResult.add(result); 209 } 210 getResult()211 private int getResult() { 212 assertThat(mCallbackResult.size()).isEqualTo(1); 213 return mCallbackResult.get(0); 214 } 215 } 216 } 217