1 /*
2  * Copyright (C) 2018 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 package com.android.server.hdmi;
17 
18 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM;
19 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK;
20 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
21 
22 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
23 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
24 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
25 import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static junit.framework.Assert.assertFalse;
30 import static junit.framework.Assert.assertTrue;
31 import static junit.framework.TestCase.assertEquals;
32 
33 import static org.mockito.ArgumentMatchers.any;
34 import static org.mockito.ArgumentMatchers.anyBoolean;
35 import static org.mockito.ArgumentMatchers.anyInt;
36 import static org.mockito.ArgumentMatchers.anyString;
37 import static org.mockito.ArgumentMatchers.eq;
38 import static org.mockito.Mockito.doNothing;
39 import static org.mockito.Mockito.doReturn;
40 import static org.mockito.Mockito.spy;
41 import static org.mockito.Mockito.times;
42 import static org.mockito.Mockito.verify;
43 
44 import android.content.Context;
45 import android.content.ContextWrapper;
46 import android.hardware.hdmi.HdmiControlManager;
47 import android.hardware.hdmi.HdmiDeviceInfo;
48 import android.hardware.hdmi.HdmiPortInfo;
49 import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
50 import android.hardware.hdmi.IHdmiControlStatusChangeListener;
51 import android.hardware.hdmi.IHdmiVendorCommandListener;
52 import android.os.Binder;
53 import android.os.Looper;
54 import android.os.RemoteException;
55 import android.os.test.TestLooper;
56 import android.platform.test.annotations.Presubmit;
57 import android.sysprop.HdmiProperties;
58 
59 import androidx.test.InstrumentationRegistry;
60 import androidx.test.filters.SmallTest;
61 
62 import org.junit.Before;
63 import org.junit.Test;
64 import org.junit.runner.RunWith;
65 import org.junit.runners.JUnit4;
66 import org.mockito.Mockito;
67 
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.Optional;
71 
72 /**
73  * Tests for {@link HdmiControlService} class.
74  */
75 @SmallTest
76 @Presubmit
77 @RunWith(JUnit4.class)
78 public class HdmiControlServiceTest {
79 
80     private static final String TAG = "HdmiControlServiceTest";
81     private Context mContextSpy;
82     private HdmiControlService mHdmiControlServiceSpy;
83     private HdmiCecController mHdmiCecController;
84     private MockAudioSystemDevice mAudioSystemDeviceSpy;
85     private MockPlaybackDevice mPlaybackDeviceSpy;
86     private FakeNativeWrapper mNativeWrapper;
87     private HdmiEarcController mHdmiEarcController;
88     private FakeEarcNativeWrapper mEarcNativeWrapper;
89     private FakePowerManagerWrapper mPowerManager;
90     private Looper mMyLooper;
91     private TestLooper mTestLooper = new TestLooper();
92     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
93     private HdmiPortInfo[] mHdmiPortInfo;
94     private ArrayList<Integer> mLocalDeviceTypes = new ArrayList<>();
95     private static final int PORT_ID_EARC_SUPPORTED = 3;
96 
97     @Before
setUp()98     public void setUp() throws Exception {
99         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
100 
101         HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
102         mLocalDeviceTypes.add(HdmiDeviceInfo.DEVICE_PLAYBACK);
103 
104         FakeAudioFramework audioFramework = new FakeAudioFramework();
105 
106         mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, mLocalDeviceTypes,
107                 audioFramework.getAudioManager(), audioFramework.getAudioDeviceVolumeManager()));
108         doNothing().when(mHdmiControlServiceSpy)
109                 .writeStringSystemProperty(anyString(), anyString());
110 
111         mMyLooper = mTestLooper.getLooper();
112 
113         mAudioSystemDeviceSpy = spy(new MockAudioSystemDevice(mHdmiControlServiceSpy));
114         mPlaybackDeviceSpy = spy(new MockPlaybackDevice(mHdmiControlServiceSpy));
115         mAudioSystemDeviceSpy.init();
116         mPlaybackDeviceSpy.init();
117 
118         mHdmiControlServiceSpy.setIoLooper(mMyLooper);
119         mHdmiControlServiceSpy.setHdmiCecConfig(hdmiCecConfig);
120         mHdmiControlServiceSpy.setDeviceConfig(new FakeDeviceConfigWrapper());
121         mHdmiControlServiceSpy.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
122 
123         mNativeWrapper = new FakeNativeWrapper();
124         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
125                 mHdmiControlServiceSpy, mNativeWrapper, mHdmiControlServiceSpy.getAtomWriter());
126         mHdmiControlServiceSpy.setCecController(mHdmiCecController);
127         mEarcNativeWrapper = new FakeEarcNativeWrapper();
128         mHdmiEarcController = HdmiEarcController.createWithNativeWrapper(
129                 mHdmiControlServiceSpy, mEarcNativeWrapper);
130         mHdmiControlServiceSpy.setEarcController(mHdmiEarcController);
131         mHdmiControlServiceSpy.setHdmiMhlController(HdmiMhlControllerStub.create(
132                 mHdmiControlServiceSpy));
133 
134         mLocalDevices.add(mAudioSystemDeviceSpy);
135         mLocalDevices.add(mPlaybackDeviceSpy);
136         mHdmiPortInfo = new HdmiPortInfo[4];
137         mHdmiPortInfo[0] =
138                 new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, 0x2100)
139                         .setCecSupported(true)
140                         .setMhlSupported(false)
141                         .setArcSupported(false)
142                         .setEarcSupported(false)
143                         .build();
144         mHdmiPortInfo[1] =
145                 new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, 0x2200)
146                         .setCecSupported(true)
147                         .setMhlSupported(false)
148                         .setArcSupported(false)
149                         .setEarcSupported(false)
150                         .build();
151         mHdmiPortInfo[2] =
152                 new HdmiPortInfo.Builder(PORT_ID_EARC_SUPPORTED, HdmiPortInfo.PORT_INPUT, 0x2000)
153                         .setCecSupported(true)
154                         .setMhlSupported(false)
155                         .setArcSupported(true)
156                         .setEarcSupported(true)
157                         .build();
158         mHdmiPortInfo[3] =
159                 new HdmiPortInfo.Builder(4, HdmiPortInfo.PORT_INPUT, 0x3000)
160                         .setCecSupported(true)
161                         .setMhlSupported(false)
162                         .setArcSupported(false)
163                         .setEarcSupported(false)
164                         .build();
165         mNativeWrapper.setPortInfo(mHdmiPortInfo);
166         mHdmiControlServiceSpy.initService();
167         mPowerManager = new FakePowerManagerWrapper(mContextSpy);
168         mHdmiControlServiceSpy.setPowerManager(mPowerManager);
169         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
170         mHdmiControlServiceSpy.setEarcSupported(true);
171 
172         mTestLooper.dispatchAll();
173     }
174 
175     @Test
onStandby_notByCec_cannotGoToStandby()176     public void onStandby_notByCec_cannotGoToStandby() {
177         doReturn(false).when(mHdmiControlServiceSpy).isStandbyMessageReceived();
178 
179         mPlaybackDeviceSpy.setCanGoToStandby(false);
180 
181         mHdmiControlServiceSpy.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
182         assertTrue(mPlaybackDeviceSpy.isStandby());
183         assertTrue(mAudioSystemDeviceSpy.isStandby());
184         assertFalse(mPlaybackDeviceSpy.isDisabled());
185         assertFalse(mAudioSystemDeviceSpy.isDisabled());
186     }
187 
188     @Test
onStandby_byCec()189     public void onStandby_byCec() {
190         doReturn(true).when(mHdmiControlServiceSpy).isStandbyMessageReceived();
191 
192         mHdmiControlServiceSpy.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
193         assertTrue(mPlaybackDeviceSpy.isStandby());
194         assertTrue(mAudioSystemDeviceSpy.isStandby());
195         assertTrue(mPlaybackDeviceSpy.isDisabled());
196         assertTrue(mAudioSystemDeviceSpy.isDisabled());
197     }
198 
199     @Test
initialPowerStatus_normalBoot_isTransientToStandby()200     public void initialPowerStatus_normalBoot_isTransientToStandby() {
201         assertThat(mHdmiControlServiceSpy.getInitialPowerStatus()).isEqualTo(
202                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY);
203     }
204 
205     @Test
initialPowerStatus_quiescentBoot_isTransientToStandby()206     public void initialPowerStatus_quiescentBoot_isTransientToStandby() throws RemoteException {
207         mPowerManager.setInteractive(false);
208         assertThat(mHdmiControlServiceSpy.getInitialPowerStatus()).isEqualTo(
209                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY);
210     }
211 
212     @Test
powerStatusAfterBootComplete_normalBoot_isOn()213     public void powerStatusAfterBootComplete_normalBoot_isOn() {
214         mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
215         mHdmiControlServiceSpy.onBootPhase(PHASE_BOOT_COMPLETED);
216         assertThat(mHdmiControlServiceSpy.getPowerStatus()).isEqualTo(
217                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
218     }
219 
220     @Test
powerStatusAfterBootComplete_quiescentBoot_isStandby()221     public void powerStatusAfterBootComplete_quiescentBoot_isStandby() throws RemoteException {
222         mPowerManager.setInteractive(false);
223         mHdmiControlServiceSpy.onBootPhase(PHASE_BOOT_COMPLETED);
224         assertThat(mHdmiControlServiceSpy.getPowerStatus()).isEqualTo(
225                 HdmiControlManager.POWER_STATUS_STANDBY);
226     }
227 
228     @Test
initialPowerStatus_normalBoot_goToStandby_doesNotBroadcastsPowerStatus_1_4()229     public void initialPowerStatus_normalBoot_goToStandby_doesNotBroadcastsPowerStatus_1_4() {
230         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
231                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
232                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
233 
234         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
235         mNativeWrapper.clearResultMessages();
236 
237         assertThat(mHdmiControlServiceSpy.getInitialPowerStatus()).isEqualTo(
238                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY);
239 
240         mHdmiControlServiceSpy.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
241 
242         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
243                 Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
244                 HdmiControlManager.POWER_STATUS_STANDBY);
245         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportPowerStatus);
246     }
247 
248     @Test
normalBoot_queuedActionsStartedAfterBoot()249     public void normalBoot_queuedActionsStartedAfterBoot() {
250         Mockito.clearInvocations(mAudioSystemDeviceSpy);
251         Mockito.clearInvocations(mPlaybackDeviceSpy);
252 
253         mHdmiControlServiceSpy.onBootPhase(PHASE_BOOT_COMPLETED);
254         mTestLooper.dispatchAll();
255 
256         verify(mAudioSystemDeviceSpy, times(1)).startQueuedActions();
257         verify(mPlaybackDeviceSpy, times(1)).startQueuedActions();
258     }
259 
260     @Test
initialPowerStatus_normalBoot_goToStandby_broadcastsPowerStatus_2_0()261     public void initialPowerStatus_normalBoot_goToStandby_broadcastsPowerStatus_2_0() {
262         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
263                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
264                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
265         mTestLooper.dispatchAll();
266 
267         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
268         mNativeWrapper.clearResultMessages();
269         mTestLooper.dispatchAll();
270 
271         assertThat(mHdmiControlServiceSpy.getInitialPowerStatus()).isEqualTo(
272                 HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY);
273 
274         mHdmiControlServiceSpy.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
275         mTestLooper.dispatchAll();
276 
277         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
278                 Constants.ADDR_PLAYBACK_1, Constants.ADDR_BROADCAST,
279                 HdmiControlManager.POWER_STATUS_STANDBY);
280         assertThat(mNativeWrapper.getResultMessages()).contains(reportPowerStatus);
281     }
282 
283     @Test
setAndGetCecVolumeControlEnabled_isApi()284     public void setAndGetCecVolumeControlEnabled_isApi() {
285         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
286                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
287                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
288         assertThat(mHdmiControlServiceSpy.getHdmiCecConfig().getIntValue(
289                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo(
290                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
291 
292         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
293                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
294                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
295         assertThat(mHdmiControlServiceSpy.getHdmiCecConfig().getIntValue(
296                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo(
297                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
298     }
299 
300     @Test
setAndGetCecVolumeControlEnabledInternal_doesNotChangeSetting()301     public void setAndGetCecVolumeControlEnabledInternal_doesNotChangeSetting() {
302         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
303                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
304                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
305 
306         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
307                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
308         assertThat(mHdmiControlServiceSpy.getHdmiCecConfig().getIntValue(
309                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo(
310                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
311 
312         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
313                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
314         assertThat(mHdmiControlServiceSpy.getHdmiCecConfig().getIntValue(
315                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo(
316                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
317     }
318 
319     @Test
disableAndReenableCec_volumeControlReturnsToOriginalValue_enabled()320     public void disableAndReenableCec_volumeControlReturnsToOriginalValue_enabled() {
321         int volumeControlEnabled = HdmiControlManager.VOLUME_CONTROL_ENABLED;
322         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(volumeControlEnabled);
323 
324         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
325         assertThat(mHdmiControlServiceSpy.getHdmiCecVolumeControl()).isEqualTo(
326                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
327 
328         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
329         assertThat(mHdmiControlServiceSpy.getHdmiCecVolumeControl())
330                 .isEqualTo(volumeControlEnabled);
331     }
332 
333     @Test
disableAndReenableCec_volumeControlReturnsToOriginalValue_disabled()334     public void disableAndReenableCec_volumeControlReturnsToOriginalValue_disabled() {
335         int volumeControlEnabled = HdmiControlManager.VOLUME_CONTROL_DISABLED;
336         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
337                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, volumeControlEnabled);
338 
339         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
340         assertThat(mHdmiControlServiceSpy.getHdmiCecConfig().getIntValue(
341                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo(
342                 volumeControlEnabled);
343 
344         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
345         assertThat(mHdmiControlServiceSpy.getHdmiCecConfig().getIntValue(
346                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo(
347                 volumeControlEnabled);
348     }
349 
350     @Test
disableAndReenableCec_volumeControlFeatureListenersNotified()351     public void disableAndReenableCec_volumeControlFeatureListenersNotified() {
352         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
353                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
354                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
355 
356         VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
357         mHdmiControlServiceSpy.addHdmiCecVolumeControlFeatureListener(callback);
358 
359         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
360         assertThat(callback.mCallbackReceived).isTrue();
361         assertThat(callback.mVolumeControlEnabled).isEqualTo(
362                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
363 
364 
365         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
366         assertThat(callback.mVolumeControlEnabled).isEqualTo(
367                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
368     }
369 
370     @Test
addHdmiCecVolumeControlFeatureListener_emitsCurrentState_enabled()371     public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_enabled() {
372         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
373                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
374         VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
375 
376         mHdmiControlServiceSpy.addHdmiCecVolumeControlFeatureListener(callback);
377         mTestLooper.dispatchAll();
378 
379         assertThat(callback.mCallbackReceived).isTrue();
380         assertThat(callback.mVolumeControlEnabled).isEqualTo(
381                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
382     }
383 
384     @Test
addHdmiCecVolumeControlFeatureListener_emitsCurrentState_disabled()385     public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_disabled() {
386         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
387                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
388         VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
389 
390         mHdmiControlServiceSpy.addHdmiCecVolumeControlFeatureListener(callback);
391         mTestLooper.dispatchAll();
392 
393         assertThat(callback.mCallbackReceived).isTrue();
394         assertThat(callback.mVolumeControlEnabled).isEqualTo(
395                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
396     }
397 
398     @Test
addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate()399     public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate() {
400         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
401                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
402         VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
403 
404         mHdmiControlServiceSpy.addHdmiCecVolumeControlFeatureListener(callback);
405 
406         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
407                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
408         mTestLooper.dispatchAll();
409 
410         assertThat(callback.mCallbackReceived).isTrue();
411         assertThat(callback.mVolumeControlEnabled).isEqualTo(
412                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
413     }
414 
415     @Test
addHdmiCecVolumeControlFeatureListener_honorsUnregistration()416     public void addHdmiCecVolumeControlFeatureListener_honorsUnregistration() {
417         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
418                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
419         VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
420 
421         mHdmiControlServiceSpy.addHdmiCecVolumeControlFeatureListener(callback);
422         mTestLooper.dispatchAll();
423 
424         mHdmiControlServiceSpy.removeHdmiControlVolumeControlStatusChangeListener(callback);
425         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
426                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
427         mTestLooper.dispatchAll();
428 
429         assertThat(callback.mCallbackReceived).isTrue();
430         assertThat(callback.mVolumeControlEnabled).isEqualTo(
431                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
432     }
433 
434     @Test
addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate_multiple()435     public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate_multiple() {
436         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
437                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
438         VolumeControlFeatureCallback callback1 = new VolumeControlFeatureCallback();
439         VolumeControlFeatureCallback callback2 = new VolumeControlFeatureCallback();
440 
441         mHdmiControlServiceSpy.addHdmiCecVolumeControlFeatureListener(callback1);
442         mHdmiControlServiceSpy.addHdmiCecVolumeControlFeatureListener(callback2);
443 
444 
445         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(
446                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
447         mTestLooper.dispatchAll();
448 
449         assertThat(callback1.mCallbackReceived).isTrue();
450         assertThat(callback2.mCallbackReceived).isTrue();
451         assertThat(callback1.mVolumeControlEnabled).isEqualTo(
452                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
453         assertThat(callback2.mVolumeControlEnabled).isEqualTo(
454                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
455     }
456 
457     @Test
getCecVersion_1_4()458     public void getCecVersion_1_4() {
459         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
460                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
461                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
462         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
463         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
464                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
465     }
466 
467     @Test
getCecVersion_2_0()468     public void getCecVersion_2_0() {
469         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
470                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
471                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
472         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
473         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
474                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
475     }
476 
477     @Test
getCecVersion_change()478     public void getCecVersion_change() {
479         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
480                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
481                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
482         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
483         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
484                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
485 
486         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
487                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
488                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
489         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
490         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
491                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
492     }
493 
494     @Test
handleGiveFeatures_cec14_featureAbort()495     public void handleGiveFeatures_cec14_featureAbort() {
496         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
497                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
498                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
499         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
500         mTestLooper.dispatchAll();
501 
502         mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV,
503                 Constants.ADDR_PLAYBACK_1));
504         mTestLooper.dispatchAll();
505 
506         HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
507                 Constants.ADDR_PLAYBACK_1, Constants.ADDR_TV, Constants.MESSAGE_GIVE_FEATURES,
508                 Constants.ABORT_UNRECOGNIZED_OPCODE);
509         assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort);
510     }
511 
512     @Test
handleGiveFeatures_cec20_reportsFeatures()513     public void handleGiveFeatures_cec20_reportsFeatures() {
514         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
515                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
516                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
517         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
518         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
519         mTestLooper.dispatchAll();
520 
521         mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV,
522                 Constants.ADDR_PLAYBACK_1));
523         mTestLooper.dispatchAll();
524 
525         HdmiCecMessage reportFeatures = ReportFeaturesMessage.build(
526                 Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
527                 Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
528                 mPlaybackDeviceSpy.getRcProfile(), mPlaybackDeviceSpy.getRcFeatures(),
529                 mPlaybackDeviceSpy.getDeviceFeatures());
530         assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
531     }
532 
533     @Test
initializeCec_14_doesNotBroadcastReportFeatures()534     public void initializeCec_14_doesNotBroadcastReportFeatures() {
535         mNativeWrapper.clearResultMessages();
536         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
537                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
538                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
539         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
540         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
541         mTestLooper.dispatchAll();
542 
543         HdmiCecMessage reportFeatures = ReportFeaturesMessage.build(
544                 Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
545                 Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
546                 mPlaybackDeviceSpy.getRcProfile(), mPlaybackDeviceSpy.getRcFeatures(),
547                 mPlaybackDeviceSpy.getDeviceFeatures());
548         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportFeatures);
549     }
550 
551     @Test
initializeCec_20_reportsFeaturesBroadcast()552     public void initializeCec_20_reportsFeaturesBroadcast() {
553         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
554                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
555                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
556         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
557         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
558         mTestLooper.dispatchAll();
559 
560         HdmiCecMessage reportFeatures = ReportFeaturesMessage.build(
561                 Constants.ADDR_PLAYBACK_1, HdmiControlManager.HDMI_CEC_VERSION_2_0,
562                 Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
563                 mPlaybackDeviceSpy.getRcProfile(), mPlaybackDeviceSpy.getRcFeatures(),
564                 mPlaybackDeviceSpy.getDeviceFeatures());
565         assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
566     }
567 
568     @Test
runOnServiceThread_preservesAndRestoresWorkSourceUid()569     public void runOnServiceThread_preservesAndRestoresWorkSourceUid() {
570         int callerUid = 1234;
571         int runnerUid = 5678;
572 
573         Binder.setCallingWorkSourceUid(callerUid);
574         WorkSourceUidReadingRunnable uidReadingRunnable = new WorkSourceUidReadingRunnable();
575         mHdmiControlServiceSpy.runOnServiceThread(uidReadingRunnable);
576 
577         Binder.setCallingWorkSourceUid(runnerUid);
578 
579         mTestLooper.dispatchAll();
580 
581         assertEquals(Optional.of(callerUid), uidReadingRunnable.getWorkSourceUid());
582         assertEquals(runnerUid, Binder.getCallingWorkSourceUid());
583     }
584 
585     @Test
initCecVersion_limitToMinimumSupportedVersion()586     public void initCecVersion_limitToMinimumSupportedVersion() {
587         mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
588         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
589                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
590                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
591 
592         mTestLooper.dispatchAll();
593         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
594                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
595     }
596 
597     @Test
initCecVersion_limitToAtLeast1_4()598     public void initCecVersion_limitToAtLeast1_4() {
599         mNativeWrapper.setCecVersion(0x0);
600         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
601                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
602                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
603 
604         mTestLooper.dispatchAll();
605         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
606                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
607     }
608 
609     @Test
initCecVersion_useHighestMatchingVersion()610     public void initCecVersion_useHighestMatchingVersion() {
611         mNativeWrapper.setCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0);
612         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
613                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
614                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
615 
616         mTestLooper.dispatchAll();
617         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
618                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
619     }
620 
621     @Test
initCec_statusListener_CecDisabled()622     public void initCec_statusListener_CecDisabled() {
623         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
624 
625         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
626 
627         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
628                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
629                 HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
630         mTestLooper.dispatchAll();
631 
632         assertThat(hdmiControlStatusCallback.mCecEnabled).isFalse();
633         assertThat(hdmiControlStatusCallback.mCecAvailable).isFalse();
634     }
635 
636     @Test
initCec_statusListener_CecEnabled_NoCecResponse()637     public void initCec_statusListener_CecEnabled_NoCecResponse() {
638         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
639 
640         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
641 
642         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
643                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
644                 HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
645         mTestLooper.dispatchAll();
646         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
647                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
648                 HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
649         mTestLooper.dispatchAll();
650         // Hit timeout twice due to retries
651         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
652         mTestLooper.dispatchAll();
653         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
654         mTestLooper.dispatchAll();
655 
656         assertThat(hdmiControlStatusCallback.mCecEnabled).isTrue();
657         assertThat(hdmiControlStatusCallback.mCecAvailable).isFalse();
658     }
659 
660     @Test
initCec_statusListener_CecEnabled_CecAvailable_TvOn()661     public void initCec_statusListener_CecEnabled_CecAvailable_TvOn() {
662         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
663         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
664         mTestLooper.dispatchAll();
665 
666         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
667         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
668         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
669         mTestLooper.dispatchAll();
670 
671         HdmiCecMessage reportPowerStatus =
672                 HdmiCecMessageBuilder.buildReportPowerStatus(
673                         Constants.ADDR_TV,
674                         mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(),
675                         HdmiControlManager.POWER_STATUS_ON);
676         mNativeWrapper.onCecMessage(reportPowerStatus);
677         mTestLooper.dispatchAll();
678 
679         assertThat(hdmiControlStatusCallback.mCecEnabled).isTrue();
680         assertThat(hdmiControlStatusCallback.mCecAvailable).isTrue();
681     }
682 
683     @Test
initCec_statusListener_CecEnabled_CecAvailable_TvStandby()684     public void initCec_statusListener_CecEnabled_CecAvailable_TvStandby() {
685         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
686         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
687         mTestLooper.dispatchAll();
688 
689         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
690         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
691         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
692         mTestLooper.dispatchAll();
693 
694         HdmiCecMessage reportPowerStatus =
695                 HdmiCecMessageBuilder.buildReportPowerStatus(
696                         Constants.ADDR_TV,
697                         mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(),
698                         HdmiControlManager.POWER_STATUS_STANDBY);
699         mNativeWrapper.onCecMessage(reportPowerStatus);
700         mTestLooper.dispatchAll();
701 
702         assertThat(hdmiControlStatusCallback.mCecEnabled).isTrue();
703         assertThat(hdmiControlStatusCallback.mCecAvailable).isTrue();
704     }
705 
706     @Test
initCec_statusListener_CecEnabled_CecAvailable_TvTransientToOn()707     public void initCec_statusListener_CecEnabled_CecAvailable_TvTransientToOn() {
708         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
709         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
710         mTestLooper.dispatchAll();
711 
712         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
713         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
714         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
715         mTestLooper.dispatchAll();
716 
717         HdmiCecMessage reportPowerStatus =
718                 HdmiCecMessageBuilder.buildReportPowerStatus(
719                         Constants.ADDR_TV,
720                         mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(),
721                         HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON);
722         mNativeWrapper.onCecMessage(reportPowerStatus);
723         mTestLooper.dispatchAll();
724 
725         assertThat(hdmiControlStatusCallback.mCecEnabled).isTrue();
726         assertThat(hdmiControlStatusCallback.mCecAvailable).isTrue();
727     }
728 
729     @Test
initCec_statusListener_CecEnabled_CecAvailable_TvTransientToStandby()730     public void initCec_statusListener_CecEnabled_CecAvailable_TvTransientToStandby() {
731         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
732         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
733         mTestLooper.dispatchAll();
734 
735         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
736         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
737         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
738         mTestLooper.dispatchAll();
739 
740         HdmiCecMessage reportPowerStatus =
741                 HdmiCecMessageBuilder.buildReportPowerStatus(
742                         Constants.ADDR_TV,
743                         mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress(),
744                         HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY);
745         mNativeWrapper.onCecMessage(reportPowerStatus);
746         mTestLooper.dispatchAll();
747 
748         assertThat(hdmiControlStatusCallback.mCecEnabled).isTrue();
749         assertThat(hdmiControlStatusCallback.mCecAvailable).isTrue();
750     }
751 
752     @Test
handleCecCommand_errorParameter_returnsAbortInvalidOperand()753     public void handleCecCommand_errorParameter_returnsAbortInvalidOperand() {
754         // Validity ERROR_PARAMETER. Taken from HdmiCecMessageValidatorTest#isValid_menuStatus
755         HdmiCecMessage message = HdmiUtils.buildMessage("80:8D:03");
756 
757         assertThat(mHdmiControlServiceSpy.handleCecCommand(message))
758                 .isEqualTo(Constants.ABORT_INVALID_OPERAND);
759 
760         // Validating ERROR_PARAMETER_LONG will generate ABORT_INVALID_OPERAND.
761         // Taken from HdmiCecMessageValidatorTest#isValid_systemAudioModeStatus
762         HdmiCecMessage systemAudioModeStatus = HdmiUtils.buildMessage("40:7E:01:1F:28");
763 
764         assertThat(mHdmiControlServiceSpy.handleCecCommand(systemAudioModeStatus))
765                 .isEqualTo(Constants.ABORT_INVALID_OPERAND);
766     }
767 
768     @Test
handleCecCommand_errorSource_returnsHandled()769     public void handleCecCommand_errorSource_returnsHandled() {
770         // Validity ERROR_SOURCE. Taken from HdmiCecMessageValidatorTest#isValid_menuStatus
771         HdmiCecMessage message = HdmiUtils.buildMessage("F0:8E");
772 
773         assertThat(mHdmiControlServiceSpy.handleCecCommand(message))
774                 .isEqualTo(Constants.HANDLED);
775 
776     }
777 
778     @Test
handleCecCommand_errorDestination_returnsHandled()779     public void handleCecCommand_errorDestination_returnsHandled() {
780         // Validity ERROR_DESTINATION. Taken from HdmiCecMessageValidatorTest#isValid_menuStatus
781         HdmiCecMessage message = HdmiUtils.buildMessage("0F:8E:00");
782 
783         assertThat(mHdmiControlServiceSpy.handleCecCommand(message))
784                 .isEqualTo(Constants.HANDLED);
785     }
786 
787     @Test
handleCecCommand_errorParameterShort_returnsHandled()788     public void handleCecCommand_errorParameterShort_returnsHandled() {
789         // Validity ERROR_PARAMETER_SHORT
790         // Taken from HdmiCecMessageValidatorTest#isValid_menuStatus
791         HdmiCecMessage message = HdmiUtils.buildMessage("40:8E");
792 
793         assertThat(mHdmiControlServiceSpy.handleCecCommand(message))
794                 .isEqualTo(Constants.HANDLED);
795     }
796 
797     @Test
handleCecCommand_notHandledByLocalDevice_returnsNotHandled()798     public void handleCecCommand_notHandledByLocalDevice_returnsNotHandled() {
799         HdmiCecMessage message = HdmiCecMessageBuilder.buildReportPowerStatus(
800                 Constants.ADDR_TV,
801                 Constants.ADDR_PLAYBACK_1,
802                 HdmiControlManager.POWER_STATUS_ON);
803 
804         doReturn(Constants.NOT_HANDLED).when(mHdmiControlServiceSpy)
805                 .dispatchMessageToLocalDevice(message);
806 
807         assertThat(mHdmiControlServiceSpy.handleCecCommand(message))
808                 .isEqualTo(Constants.NOT_HANDLED);
809     }
810 
811     @Test
handleCecCommand_handledByLocalDevice_returnsHandled()812     public void handleCecCommand_handledByLocalDevice_returnsHandled() {
813         HdmiCecMessage message = HdmiCecMessageBuilder.buildReportPowerStatus(
814                 Constants.ADDR_TV,
815                 Constants.ADDR_PLAYBACK_1,
816                 HdmiControlManager.POWER_STATUS_ON);
817 
818         doReturn(Constants.HANDLED).when(mHdmiControlServiceSpy)
819                 .dispatchMessageToLocalDevice(message);
820 
821         assertThat(mHdmiControlServiceSpy.handleCecCommand(message))
822                 .isEqualTo(Constants.HANDLED);
823     }
824 
825     @Test
handleCecCommand_localDeviceReturnsFeatureAbort_returnsFeatureAbort()826     public void handleCecCommand_localDeviceReturnsFeatureAbort_returnsFeatureAbort() {
827         HdmiCecMessage message = HdmiCecMessageBuilder.buildReportPowerStatus(
828                 Constants.ADDR_TV,
829                 Constants.ADDR_PLAYBACK_1,
830                 HdmiControlManager.POWER_STATUS_ON);
831 
832         doReturn(Constants.ABORT_REFUSED).when(mHdmiControlServiceSpy)
833                 .dispatchMessageToLocalDevice(message);
834 
835         assertThat(mHdmiControlServiceSpy.handleCecCommand(message))
836                 .isEqualTo(Constants.ABORT_REFUSED);
837     }
838 
839     @Test
addVendorCommandListener_receiveCallback_VendorCmdNoIdTest()840     public void addVendorCommandListener_receiveCallback_VendorCmdNoIdTest() {
841         int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
842         int sourceAddress = Constants.ADDR_TV;
843         byte[] params = {0x00, 0x01, 0x02, 0x03};
844         int vendorId = 0x123456;
845         mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
846 
847         VendorCommandListener vendorCmdListener =
848                 new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
849         mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
850         mTestLooper.dispatchAll();
851 
852         HdmiCecMessage vendorCommandNoId =
853                 HdmiCecMessageBuilder.buildVendorCommand(sourceAddress, destAddress, params);
854         mNativeWrapper.onCecMessage(vendorCommandNoId);
855         mTestLooper.dispatchAll();
856         assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue();
857         assertThat(vendorCmdListener.mParamsCorrect).isTrue();
858         assertThat(vendorCmdListener.mHasVendorId).isFalse();
859     }
860 
861     @Test
addVendorCommandListener_receiveCallback_VendorCmdWithIdTest()862     public void addVendorCommandListener_receiveCallback_VendorCmdWithIdTest() {
863         int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
864         int sourceAddress = Constants.ADDR_TV;
865         byte[] params = {0x00, 0x01, 0x02, 0x03};
866         int vendorId = 0x123456;
867         mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
868 
869         VendorCommandListener vendorCmdListener =
870                 new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
871         mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
872         mTestLooper.dispatchAll();
873 
874         HdmiCecMessage vendorCommandWithId =
875                 HdmiCecMessageBuilder.buildVendorCommandWithId(
876                         sourceAddress, destAddress, vendorId, params);
877         mNativeWrapper.onCecMessage(vendorCommandWithId);
878         mTestLooper.dispatchAll();
879         assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue();
880         assertThat(vendorCmdListener.mParamsCorrect).isTrue();
881         assertThat(vendorCmdListener.mHasVendorId).isTrue();
882     }
883 
884     @Test
addVendorCommandListener_noCallback_VendorCmdDiffIdTest()885     public void addVendorCommandListener_noCallback_VendorCmdDiffIdTest() {
886         int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
887         int sourceAddress = Constants.ADDR_TV;
888         byte[] params = {0x00, 0x01, 0x02, 0x03};
889         int vendorId = 0x123456;
890         int diffVendorId = 0x345678;
891         mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
892 
893         VendorCommandListener vendorCmdListener =
894                 new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
895         mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
896         mTestLooper.dispatchAll();
897 
898         HdmiCecMessage vendorCommandWithDiffId =
899                 HdmiCecMessageBuilder.buildVendorCommandWithId(
900                         sourceAddress, destAddress, diffVendorId, params);
901         mNativeWrapper.onCecMessage(vendorCommandWithDiffId);
902         mTestLooper.dispatchAll();
903         assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isFalse();
904     }
905 
906     private static class VendorCommandListener extends IHdmiVendorCommandListener.Stub {
907         boolean mVendorCommandCallbackReceived = false;
908         boolean mParamsCorrect = false;
909         boolean mHasVendorId = false;
910 
911         int mSourceAddress;
912         int mDestAddress;
913         byte[] mParams;
914         int mVendorId;
915 
VendorCommandListener(int sourceAddress, int destAddress, byte[] params, int vendorId)916         VendorCommandListener(int sourceAddress, int destAddress, byte[] params, int vendorId) {
917             this.mSourceAddress = sourceAddress;
918             this.mDestAddress = destAddress;
919             this.mParams = params.clone();
920             this.mVendorId = vendorId;
921         }
922 
923         @Override
onReceived( int sourceAddress, int destAddress, byte[] params, boolean hasVendorId)924         public void onReceived(
925                 int sourceAddress, int destAddress, byte[] params, boolean hasVendorId) {
926             mVendorCommandCallbackReceived = true;
927             if (mSourceAddress == sourceAddress && mDestAddress == destAddress) {
928                 byte[] expectedParams;
929                 if (hasVendorId) {
930                     // If the command has vendor ID, we have to add it to mParams.
931                     expectedParams = new byte[params.length];
932                     expectedParams[0] = (byte) ((mVendorId >> 16) & 0xFF);
933                     expectedParams[1] = (byte) ((mVendorId >> 8) & 0xFF);
934                     expectedParams[2] = (byte) (mVendorId & 0xFF);
935                     System.arraycopy(mParams, 0, expectedParams, 3, mParams.length);
936                 } else {
937                     expectedParams = params.clone();
938                 }
939                 if (Arrays.equals(expectedParams, params)) {
940                     mParamsCorrect = true;
941                 }
942             }
943             mHasVendorId = hasVendorId;
944         }
945 
946         @Override
onControlStateChanged(boolean enabled, int reason)947         public void onControlStateChanged(boolean enabled, int reason) {}
948     }
949 
950     @Test
dispatchMessageToLocalDevice_broadcastMessage_returnsHandled()951     public void dispatchMessageToLocalDevice_broadcastMessage_returnsHandled() {
952         HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby(
953                 Constants.ADDR_TV,
954                 Constants.ADDR_BROADCAST);
955 
956         doReturn(Constants.ABORT_REFUSED).when(mPlaybackDeviceSpy).dispatchMessage(message);
957         doReturn(Constants.ABORT_NOT_IN_CORRECT_MODE)
958                 .when(mAudioSystemDeviceSpy).dispatchMessage(message);
959 
960         assertThat(mHdmiControlServiceSpy.dispatchMessageToLocalDevice(message))
961                 .isEqualTo(Constants.HANDLED);
962     }
963 
964     @Test
dispatchMessageToLocalDevice_localDevicesDoNotHandleMessage_returnsUnhandled()965     public void dispatchMessageToLocalDevice_localDevicesDoNotHandleMessage_returnsUnhandled() {
966         HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby(
967                 Constants.ADDR_TV,
968                 Constants.ADDR_PLAYBACK_1);
969 
970         doReturn(Constants.NOT_HANDLED).when(mPlaybackDeviceSpy).dispatchMessage(message);
971         doReturn(Constants.NOT_HANDLED)
972                 .when(mAudioSystemDeviceSpy).dispatchMessage(message);
973 
974         assertThat(mHdmiControlServiceSpy.dispatchMessageToLocalDevice(message))
975                 .isEqualTo(Constants.NOT_HANDLED);
976     }
977 
978     @Test
dispatchMessageToLocalDevice_localDeviceHandlesMessage_returnsHandled()979     public void dispatchMessageToLocalDevice_localDeviceHandlesMessage_returnsHandled() {
980         HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby(
981                 Constants.ADDR_TV,
982                 Constants.ADDR_PLAYBACK_1);
983 
984         doReturn(Constants.NOT_HANDLED).when(mPlaybackDeviceSpy).dispatchMessage(message);
985         doReturn(Constants.HANDLED)
986                 .when(mAudioSystemDeviceSpy).dispatchMessage(message);
987 
988         assertThat(mHdmiControlServiceSpy.dispatchMessageToLocalDevice(message))
989                 .isEqualTo(Constants.HANDLED);
990     }
991 
992     @Test
dispatchMessageToLocalDevice_localDeviceReturnsFeatureAbort_returnsFeatureAbort()993     public void dispatchMessageToLocalDevice_localDeviceReturnsFeatureAbort_returnsFeatureAbort() {
994         HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby(
995                 Constants.ADDR_TV,
996                 Constants.ADDR_PLAYBACK_1);
997 
998         doReturn(Constants.NOT_HANDLED).when(mPlaybackDeviceSpy).dispatchMessage(message);
999         doReturn(Constants.ABORT_REFUSED)
1000                 .when(mAudioSystemDeviceSpy).dispatchMessage(message);
1001 
1002         assertThat(mHdmiControlServiceSpy.dispatchMessageToLocalDevice(message))
1003                 .isEqualTo(Constants.ABORT_REFUSED);
1004     }
1005 
1006     @Test
readDeviceTypes_readsIntegerDeviceTypes()1007     public void readDeviceTypes_readsIntegerDeviceTypes() {
1008         doReturn(Arrays.asList(new Integer[]{DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM}))
1009                 .when(mHdmiControlServiceSpy).getDeviceTypes();
1010         doReturn(Arrays.asList(new HdmiProperties.cec_device_types_values[]{}))
1011                 .when(mHdmiControlServiceSpy).getCecDeviceTypes();
1012 
1013         assertThat(mHdmiControlServiceSpy.readDeviceTypes())
1014                 .containsExactly(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM);
1015     }
1016 
1017     @Test
readDeviceTypes_readsEnumDeviceTypes()1018     public void readDeviceTypes_readsEnumDeviceTypes() {
1019         doReturn(Arrays.asList(new Integer[]{})).when(mHdmiControlServiceSpy).getDeviceTypes();
1020         doReturn(Arrays.asList(
1021                 new HdmiProperties.cec_device_types_values[]{
1022                         HdmiProperties.cec_device_types_values.PLAYBACK_DEVICE,
1023                         HdmiProperties.cec_device_types_values.AUDIO_SYSTEM
1024                 }))
1025                 .when(mHdmiControlServiceSpy).getCecDeviceTypes();
1026 
1027         assertThat(mHdmiControlServiceSpy.readDeviceTypes())
1028                 .containsExactly(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM);
1029     }
1030 
1031     @Test
readDeviceTypes_readsEnumOverIntegerDeviceTypes()1032     public void readDeviceTypes_readsEnumOverIntegerDeviceTypes() {
1033         doReturn(Arrays.asList(new Integer[]{DEVICE_TV}))
1034                 .when(mHdmiControlServiceSpy).getDeviceTypes();
1035         doReturn(Arrays.asList(
1036                 new HdmiProperties.cec_device_types_values[]{
1037                         HdmiProperties.cec_device_types_values.PLAYBACK_DEVICE,
1038                         HdmiProperties.cec_device_types_values.AUDIO_SYSTEM
1039                 }))
1040                 .when(mHdmiControlServiceSpy).getCecDeviceTypes();
1041 
1042         assertThat(mHdmiControlServiceSpy.readDeviceTypes())
1043                 .containsExactly(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM);
1044     }
1045 
1046     @Test
readDeviceTypes_doesNotReadNullEnumDeviceType()1047     public void readDeviceTypes_doesNotReadNullEnumDeviceType() {
1048         doReturn(Arrays.asList(new Integer[]{})).when(mHdmiControlServiceSpy).getDeviceTypes();
1049         doReturn(Arrays.asList(
1050                 new HdmiProperties.cec_device_types_values[]{
1051                         HdmiProperties.cec_device_types_values.PLAYBACK_DEVICE,
1052                         HdmiProperties.cec_device_types_values.AUDIO_SYSTEM,
1053                         null
1054                 }))
1055                 .when(mHdmiControlServiceSpy).getCecDeviceTypes();
1056 
1057         assertThat(mHdmiControlServiceSpy.readDeviceTypes())
1058                 .containsExactly(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM);
1059     }
1060 
1061     @Test
readDeviceTypes_doesNotReadNullIntegerDeviceType()1062     public void readDeviceTypes_doesNotReadNullIntegerDeviceType() {
1063         doReturn(Arrays.asList(new Integer[]{DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM, null}))
1064                 .when(mHdmiControlServiceSpy).getDeviceTypes();
1065         doReturn(Arrays.asList(new HdmiProperties.cec_device_types_values[]{}))
1066                 .when(mHdmiControlServiceSpy).getCecDeviceTypes();
1067 
1068         assertThat(mHdmiControlServiceSpy.readDeviceTypes())
1069                 .containsExactly(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM);
1070     }
1071 
1072     @Test
setSoundbarMode_enabled_addAudioSystemLocalDevice()1073     public void setSoundbarMode_enabled_addAudioSystemLocalDevice() {
1074         mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
1075         // Initialize the local devices excluding the audio system.
1076         mHdmiControlServiceSpy.clearCecLocalDevices();
1077         mLocalDevices.remove(mAudioSystemDeviceSpy);
1078         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
1079         mTestLooper.dispatchAll();
1080         assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
1081 
1082         // Enable the setting and check if the audio system local device is found in the network.
1083         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1084                 HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
1085                 HdmiControlManager.SOUNDBAR_MODE_ENABLED);
1086         mTestLooper.dispatchAll();
1087         assertThat(mHdmiControlServiceSpy.audioSystem()).isNotNull();
1088     }
1089 
1090     @Test
setSoundbarMode_disabled_removeAudioSystemLocalDevice()1091     public void setSoundbarMode_disabled_removeAudioSystemLocalDevice() {
1092         mHdmiControlServiceSpy.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
1093         // Initialize the local devices excluding the audio system.
1094         mHdmiControlServiceSpy.clearCecLocalDevices();
1095         mLocalDevices.remove(mAudioSystemDeviceSpy);
1096         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
1097         mTestLooper.dispatchAll();
1098         assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
1099 
1100         // Enable the setting and check if the audio system local device is found in the network.
1101         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1102                 HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
1103                 HdmiControlManager.SOUNDBAR_MODE_ENABLED);
1104         mTestLooper.dispatchAll();
1105         assertThat(mHdmiControlServiceSpy.audioSystem()).isNotNull();
1106 
1107         // Disable the setting and check if the audio system local device is removed from the
1108         // network.
1109         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1110                 HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
1111                 HdmiControlManager.SOUNDBAR_MODE_DISABLED);
1112         mTestLooper.dispatchAll();
1113 
1114         // Wait for ArcTerminationActionFromAvr timeout for the logical address allocation to start.
1115         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
1116         mTestLooper.dispatchAll();
1117         assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
1118     }
1119 
1120     @Test
disableEarc_clearEarcLocalDevice()1121     public void disableEarc_clearEarcLocalDevice() {
1122         mHdmiControlServiceSpy.clearEarcLocalDevice();
1123         mHdmiControlServiceSpy.addEarcLocalDevice(
1124                 new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy));
1125         assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNotNull();
1126 
1127         mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
1128         mTestLooper.dispatchAll();
1129         assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNull();
1130     }
1131 
1132     @Test
disableEarc_noEarcLocalDevice_enableArc()1133     public void disableEarc_noEarcLocalDevice_enableArc() {
1134         mHdmiControlServiceSpy.clearEarcLocalDevice();
1135         mHdmiControlServiceSpy.addEarcLocalDevice(
1136                 new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy));
1137         mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
1138         mTestLooper.dispatchAll();
1139         assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNull();
1140 
1141         Mockito.clearInvocations(mHdmiControlServiceSpy);
1142         mHdmiControlServiceSpy.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING,
1143                 PORT_ID_EARC_SUPPORTED);
1144         verify(mHdmiControlServiceSpy, times(1))
1145                 .notifyEarcStatusToAudioService(eq(false), eq(new ArrayList<>()));
1146         verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(true), any());
1147     }
1148 
1149     @Test
disableCec_doNotClearEarcLocalDevice()1150     public void disableCec_doNotClearEarcLocalDevice() {
1151         mHdmiControlServiceSpy.clearEarcLocalDevice();
1152         mHdmiControlServiceSpy.addEarcLocalDevice(
1153                 new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy));
1154         assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNotNull();
1155 
1156         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
1157         mTestLooper.dispatchAll();
1158         assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNotNull();
1159     }
1160 
1161     @Test
enableCec_initializeCecLocalDevices()1162     public void enableCec_initializeCecLocalDevices() {
1163         Mockito.clearInvocations(mHdmiControlServiceSpy);
1164         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
1165         mTestLooper.dispatchAll();
1166         mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
1167         mTestLooper.dispatchAll();
1168         verify(mHdmiControlServiceSpy, times(1)).initializeCecLocalDevices(anyInt());
1169         verify(mHdmiControlServiceSpy, times(0)).initializeEarcLocalDevice(anyInt());
1170     }
1171 
1172     @Test
enableEarc_initializeEarcLocalDevices()1173     public void enableEarc_initializeEarcLocalDevices() {
1174         Mockito.clearInvocations(mHdmiControlServiceSpy);
1175         mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
1176         mTestLooper.dispatchAll();
1177         mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1178         mTestLooper.dispatchAll();
1179         verify(mHdmiControlServiceSpy, times(0)).initializeCecLocalDevices(anyInt());
1180         verify(mHdmiControlServiceSpy, times(1)).initializeEarcLocalDevice(anyInt());
1181     }
1182 
1183     @Test
disableCec_DoNotInformHalAboutEarc()1184     public void disableCec_DoNotInformHalAboutEarc() {
1185         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1186                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
1187                 HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
1188         mTestLooper.dispatchAll();
1189         Mockito.clearInvocations(mHdmiControlServiceSpy);
1190         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1191                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
1192                 HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
1193         mTestLooper.dispatchAll();
1194         verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean(), anyBoolean());
1195     }
1196 
1197     @Test
disableEarc_informHalAboutEarc()1198     public void disableEarc_informHalAboutEarc() {
1199         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1200                 HdmiControlManager.SETTING_NAME_EARC_ENABLED,
1201                 HdmiControlManager.EARC_FEATURE_ENABLED);
1202         mTestLooper.dispatchAll();
1203         Mockito.clearInvocations(mHdmiControlServiceSpy);
1204         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1205                 HdmiControlManager.SETTING_NAME_EARC_ENABLED,
1206                 HdmiControlManager.EARC_FEATURE_DISABLED);
1207         mTestLooper.dispatchAll();
1208         verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false, false);
1209         verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(true), anyBoolean());
1210     }
1211 
1212     @Test
enableCec_DoNotInformHalAboutEarc()1213     public void enableCec_DoNotInformHalAboutEarc() {
1214         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1215                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
1216                 HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
1217         mTestLooper.dispatchAll();
1218         Mockito.clearInvocations(mHdmiControlServiceSpy);
1219         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1220                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
1221                 HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
1222         mTestLooper.dispatchAll();
1223         verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(anyBoolean(), anyBoolean());
1224     }
1225 
1226     @Test
enableEarc_informHalAboutEarc()1227     public void enableEarc_informHalAboutEarc() {
1228         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1229                 HdmiControlManager.SETTING_NAME_EARC_ENABLED,
1230                 HdmiControlManager.EARC_FEATURE_DISABLED);
1231         mTestLooper.dispatchAll();
1232         Mockito.clearInvocations(mHdmiControlServiceSpy);
1233         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1234                 HdmiControlManager.SETTING_NAME_EARC_ENABLED,
1235                 HdmiControlManager.EARC_FEATURE_ENABLED);
1236         mTestLooper.dispatchAll();
1237         verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true, true);
1238         verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(false), anyBoolean());
1239     }
1240 
1241     @Test
bootWithEarcEnabled_informHalAboutEarc()1242     public void bootWithEarcEnabled_informHalAboutEarc() {
1243         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1244                 HdmiControlManager.SETTING_NAME_EARC_ENABLED,
1245                 HdmiControlManager.EARC_FEATURE_ENABLED);
1246         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1247                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
1248                 HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
1249         mTestLooper.dispatchAll();
1250         Mockito.clearInvocations(mHdmiControlServiceSpy);
1251         mHdmiControlServiceSpy.initService();
1252         mTestLooper.dispatchAll();
1253         verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true, false);
1254         verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(false), anyBoolean());
1255     }
1256 
1257     @Test
bootWithEarcDisabled_informHalAboutEarc()1258     public void bootWithEarcDisabled_informHalAboutEarc() {
1259         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1260                 HdmiControlManager.SETTING_NAME_EARC_ENABLED,
1261                 HdmiControlManager.EARC_FEATURE_DISABLED);
1262         mTestLooper.dispatchAll();
1263         Mockito.clearInvocations(mHdmiControlServiceSpy);
1264         mHdmiControlServiceSpy.initService();
1265         mTestLooper.dispatchAll();
1266         verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false, false);
1267         verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(true), anyBoolean());
1268     }
1269 
1270     @Test
wakeUpWithEarcEnabled_informHalAboutEarc()1271     public void wakeUpWithEarcEnabled_informHalAboutEarc() {
1272         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1273                 HdmiControlManager.SETTING_NAME_EARC_ENABLED,
1274                 HdmiControlManager.EARC_FEATURE_ENABLED);
1275         mTestLooper.dispatchAll();
1276         Mockito.clearInvocations(mHdmiControlServiceSpy);
1277         mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON);
1278         mTestLooper.dispatchAll();
1279         verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(true, false);
1280         verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(false), anyBoolean());
1281     }
1282 
1283     @Test
wakeUpWithEarcDisabled_informHalAboutEarc()1284     public void wakeUpWithEarcDisabled_informHalAboutEarc() {
1285         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
1286                 HdmiControlManager.SETTING_NAME_EARC_ENABLED,
1287                 HdmiControlManager.EARC_FEATURE_DISABLED);
1288         mTestLooper.dispatchAll();
1289         Mockito.clearInvocations(mHdmiControlServiceSpy);
1290         mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON);
1291         mTestLooper.dispatchAll();
1292         verify(mHdmiControlServiceSpy, times(1)).setEarcEnabledInHal(false, false);
1293         verify(mHdmiControlServiceSpy, times(0)).setEarcEnabledInHal(eq(true), anyBoolean());
1294     }
1295 
1296     @Test
earcIdle_blocksArcConnection()1297     public void earcIdle_blocksArcConnection() {
1298         mHdmiControlServiceSpy.clearEarcLocalDevice();
1299         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1300         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_IDLE);
1301         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1302         assertThat(mHdmiControlServiceSpy.earcBlocksArcConnection()).isTrue();
1303     }
1304 
1305     @Test
earcPending_blocksArcConnection()1306     public void earcPending_blocksArcConnection() {
1307         mHdmiControlServiceSpy.clearEarcLocalDevice();
1308         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1309         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_PENDING);
1310         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1311         assertThat(mHdmiControlServiceSpy.earcBlocksArcConnection()).isTrue();
1312     }
1313 
1314     @Test
earcEnabled_blocksArcConnection()1315     public void earcEnabled_blocksArcConnection() {
1316         mHdmiControlServiceSpy.clearEarcLocalDevice();
1317         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1318         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_CONNECTED);
1319         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1320         assertThat(mHdmiControlServiceSpy.earcBlocksArcConnection()).isTrue();
1321     }
1322 
1323     @Test
arcPending_doesNotBlockArcConnection()1324     public void arcPending_doesNotBlockArcConnection() {
1325         mHdmiControlServiceSpy.clearEarcLocalDevice();
1326         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1327         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING);
1328         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1329         assertThat(mHdmiControlServiceSpy.earcBlocksArcConnection()).isFalse();
1330     }
1331 
1332     @Test
earcStatusBecomesIdle_terminateArc()1333     public void earcStatusBecomesIdle_terminateArc() {
1334         mHdmiControlServiceSpy.clearEarcLocalDevice();
1335         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1336         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1337         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_IDLE);
1338         verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(false), any());
1339     }
1340 
1341     @Test
earcStatusBecomesEnabled_doNothing()1342     public void earcStatusBecomesEnabled_doNothing() {
1343         mHdmiControlServiceSpy.clearEarcLocalDevice();
1344         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1345         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1346         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_CONNECTED);
1347         verify(mHdmiControlServiceSpy, times(0)).startArcAction(anyBoolean(), any());
1348     }
1349 
1350     @Test
earcStatusBecomesPending_doNothing()1351     public void earcStatusBecomesPending_doNothing() {
1352         mHdmiControlServiceSpy.clearEarcLocalDevice();
1353         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1354         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1355         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_PENDING);
1356         verify(mHdmiControlServiceSpy, times(0)).startArcAction(anyBoolean(), any());
1357     }
1358 
1359     @Test
earcStatusBecomesNotEnabled_initiateArc()1360     public void earcStatusBecomesNotEnabled_initiateArc() {
1361         mHdmiControlServiceSpy.clearEarcLocalDevice();
1362         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1363         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1364         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING);
1365         verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(true), any());
1366     }
1367 
1368     @Test
earcStateWasArcPending_becomesEarcPending_terminateArc()1369     public void earcStateWasArcPending_becomesEarcPending_terminateArc() {
1370         mHdmiControlServiceSpy.clearEarcLocalDevice();
1371         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1372         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1373         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING);
1374         mTestLooper.dispatchAll();
1375         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_PENDING);
1376         verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(false), any());
1377     }
1378 
1379     @Test
earcStateWasArcPending_becomesEarcEnabled_terminateArc()1380     public void earcStateWasArcPending_becomesEarcEnabled_terminateArc() {
1381         mHdmiControlServiceSpy.clearEarcLocalDevice();
1382         HdmiEarcLocalDeviceTx localDeviceTx = new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy);
1383         mHdmiControlServiceSpy.addEarcLocalDevice(localDeviceTx);
1384         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING);
1385         mTestLooper.dispatchAll();
1386         localDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_CONNECTED);
1387         verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(false), any());
1388     }
1389 
1390     protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {
1391 
1392         private boolean mCanGoToStandby;
1393         private boolean mIsStandby;
1394         private boolean mIsDisabled;
1395 
MockPlaybackDevice(HdmiControlService service)1396         MockPlaybackDevice(HdmiControlService service) {
1397             super(service);
1398         }
1399 
1400         @Override
onAddressAllocated(int logicalAddress, int reason)1401         protected void onAddressAllocated(int logicalAddress, int reason) {
1402         }
1403 
1404         @Override
getPreferredAddress()1405         protected int getPreferredAddress() {
1406             return 0;
1407         }
1408 
1409         @Override
setPreferredAddress(int addr)1410         protected void setPreferredAddress(int addr) {
1411         }
1412 
1413         @Override
canGoToStandby()1414         protected boolean canGoToStandby() {
1415             return mCanGoToStandby;
1416         }
1417 
1418         @Override
disableDevice( boolean initiatedByCec, final PendingActionClearedCallback originalCallback)1419         protected void disableDevice(
1420                 boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
1421             mIsDisabled = true;
1422             originalCallback.onCleared(this);
1423         }
1424 
1425         @Override
onStandby(boolean initiatedByCec, int standbyAction)1426         protected void onStandby(boolean initiatedByCec, int standbyAction) {
1427             mIsStandby = true;
1428         }
1429 
isStandby()1430         protected boolean isStandby() {
1431             return mIsStandby;
1432         }
1433 
isDisabled()1434         protected boolean isDisabled() {
1435             return mIsDisabled;
1436         }
1437 
setCanGoToStandby(boolean canGoToStandby)1438         protected void setCanGoToStandby(boolean canGoToStandby) {
1439             mCanGoToStandby = canGoToStandby;
1440         }
1441     }
1442 
1443     protected static class MockAudioSystemDevice extends HdmiCecLocalDeviceAudioSystem {
1444 
1445         private boolean mCanGoToStandby;
1446         private boolean mIsStandby;
1447         private boolean mIsDisabled;
1448 
MockAudioSystemDevice(HdmiControlService service)1449         MockAudioSystemDevice(HdmiControlService service) {
1450             super(service);
1451         }
1452 
1453         @Override
onAddressAllocated(int logicalAddress, int reason)1454         protected void onAddressAllocated(int logicalAddress, int reason) {
1455         }
1456 
1457         @Override
getPreferredAddress()1458         protected int getPreferredAddress() {
1459             return 0;
1460         }
1461 
1462         @Override
setPreferredAddress(int addr)1463         protected void setPreferredAddress(int addr) {
1464         }
1465 
1466         @Override
canGoToStandby()1467         protected boolean canGoToStandby() {
1468             return mCanGoToStandby;
1469         }
1470 
1471         @Override
disableDevice( boolean initiatedByCec, final PendingActionClearedCallback originalCallback)1472         protected void disableDevice(
1473                 boolean initiatedByCec, final PendingActionClearedCallback originalCallback) {
1474             mIsDisabled = true;
1475             originalCallback.onCleared(this);
1476         }
1477 
1478         @Override
onStandby(boolean initiatedByCec, int standbyAction)1479         protected void onStandby(boolean initiatedByCec, int standbyAction) {
1480             mIsStandby = true;
1481         }
1482 
isStandby()1483         protected boolean isStandby() {
1484             return mIsStandby;
1485         }
1486 
isDisabled()1487         protected boolean isDisabled() {
1488             return mIsDisabled;
1489         }
1490 
setCanGoToStandby(boolean canGoToStandby)1491         protected void setCanGoToStandby(boolean canGoToStandby) {
1492             mCanGoToStandby = canGoToStandby;
1493         }
1494     }
1495 
1496     private static class HdmiControlStatusCallback extends IHdmiControlStatusChangeListener.Stub {
1497         boolean mCecEnabled = false;
1498         boolean mCecAvailable = false;
1499 
1500         @Override
onStatusChange(int isCecEnabled, boolean isCecAvailable)1501         public void onStatusChange(int isCecEnabled, boolean isCecAvailable)
1502                 throws RemoteException {
1503             mCecEnabled = isCecEnabled == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
1504             mCecAvailable = isCecAvailable;
1505         }
1506     }
1507 
1508     private static class VolumeControlFeatureCallback extends
1509             IHdmiCecVolumeControlFeatureListener.Stub {
1510         boolean mCallbackReceived = false;
1511         int mVolumeControlEnabled = -1;
1512 
1513         @Override
onHdmiCecVolumeControlFeature(int enabled)1514         public void onHdmiCecVolumeControlFeature(int enabled) throws RemoteException {
1515             this.mCallbackReceived = true;
1516             this.mVolumeControlEnabled = enabled;
1517         }
1518     }
1519 
1520 }
1521