1 /*
2  * Copyright (C) 2020 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 com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
19 import static com.android.server.hdmi.Constants.ABORT_UNRECOGNIZED_OPCODE;
20 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
21 import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
22 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
23 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
24 import static com.android.server.hdmi.Constants.ADDR_RECORDER_1;
25 import static com.android.server.hdmi.Constants.ADDR_TV;
26 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
27 
28 import static com.google.common.truth.Truth.assertThat;
29 
30 import static org.junit.Assert.assertFalse;
31 import static org.junit.Assert.assertTrue;
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.ArgumentMatchers.anyInt;
34 import static org.mockito.Mockito.eq;
35 import static org.mockito.Mockito.never;
36 import static org.mockito.Mockito.spy;
37 import static org.mockito.Mockito.times;
38 import static org.mockito.Mockito.verify;
39 
40 import android.content.Context;
41 import android.hardware.hdmi.HdmiControlManager;
42 import android.hardware.hdmi.HdmiDeviceInfo;
43 import android.hardware.hdmi.HdmiPortInfo;
44 import android.hardware.hdmi.IHdmiControlCallback;
45 import android.hardware.tv.cec.V1_0.SendMessageResult;
46 import android.media.AudioManager;
47 import android.os.Looper;
48 import android.os.test.TestLooper;
49 import android.platform.test.annotations.Presubmit;
50 
51 import androidx.test.InstrumentationRegistry;
52 import androidx.test.filters.SmallTest;
53 
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.junit.runners.JUnit4;
58 
59 import java.util.ArrayList;
60 import java.util.Collections;
61 import java.util.List;
62 import java.util.concurrent.TimeUnit;
63 
64 @SmallTest
65 @Presubmit
66 @RunWith(JUnit4.class)
67 /** Tests for {@link HdmiCecLocalDeviceTv} class. */
68 public class HdmiCecLocalDeviceTvTest {
69     private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
70     private static final int PORT_1 = 1;
71 
72     private static final String[] SADS_NOT_TO_QUERY = new String[]{
73             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1,
74             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_AAC,
75             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTS,
76             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ATRAC,
77             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO,
78             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DDP,
79             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTSHD,
80             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
81             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST,
82             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
83             HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX};
84     private static final HdmiCecMessage SAD_QUERY =
85             HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(ADDR_TV, ADDR_AUDIO_SYSTEM,
86                     new int[]{Constants.AUDIO_CODEC_LPCM, Constants.AUDIO_CODEC_DD,
87                             Constants.AUDIO_CODEC_MP3, Constants.AUDIO_CODEC_MPEG2});
88 
89     private HdmiControlService mHdmiControlService;
90     private HdmiCecController mHdmiCecController;
91     private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
92     private FakeNativeWrapper mNativeWrapper;
93     private HdmiEarcController mHdmiEarcController;
94     private FakeEarcNativeWrapper mEarcNativeWrapper;
95     private FakePowerManagerWrapper mPowerManager;
96     private Looper mMyLooper;
97     private TestLooper mTestLooper = new TestLooper();
98     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
99     private int mTvPhysicalAddress;
100     private int mTvLogicalAddress;
101     private boolean mWokenUp;
102     private boolean mEarcBlocksArc;
103     private List<DeviceEventListener> mDeviceEventListeners = new ArrayList<>();
104 
105     private class DeviceEventListener {
106         private HdmiDeviceInfo mDevice;
107         private int mStatus;
108 
DeviceEventListener(HdmiDeviceInfo device, int status)109         DeviceEventListener(HdmiDeviceInfo device, int status) {
110             this.mDevice = device;
111             this.mStatus = status;
112         }
113 
getStatus()114         int getStatus() {
115             return mStatus;
116         }
117 
getDeviceInfo()118         HdmiDeviceInfo getDeviceInfo() {
119             return mDevice;
120         }
121     }
122 
123     private FakeAudioFramework mAudioFramework;
124     private AudioManagerWrapper mAudioManager;
125 
126     @Before
setUp()127     public void setUp() {
128         Context context = InstrumentationRegistry.getTargetContext();
129         mMyLooper = mTestLooper.getLooper();
130 
131         mAudioFramework = new FakeAudioFramework();
132         mAudioManager = spy(mAudioFramework.getAudioManager());
133 
134         mHdmiControlService =
135                 new HdmiControlService(InstrumentationRegistry.getTargetContext(),
136                         Collections.singletonList(HdmiDeviceInfo.DEVICE_TV),
137                         mAudioManager, mAudioFramework.getAudioDeviceVolumeManager()) {
138                     @Override
139                     void wakeUp() {
140                         mWokenUp = true;
141                         super.wakeUp();
142                     }
143                     @Override
144                     boolean isCecControlEnabled() {
145                         return true;
146                     }
147 
148                     @Override
149                     boolean isTvDevice() {
150                         return true;
151                     }
152 
153                     @Override
154                     protected void writeStringSystemProperty(String key, String value) {
155                         // do nothing
156                     }
157 
158                     @Override
159                     boolean isPowerStandby() {
160                         return false;
161                     }
162 
163                     @Override
164                     boolean isPowerStandbyOrTransient() {
165                         return false;
166                     }
167 
168                     @Override
169                     void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) {
170                         mDeviceEventListeners.add(new DeviceEventListener(device, status));
171                     }
172 
173                     @Override
174                     protected boolean earcBlocksArcConnection() {
175                         return mEarcBlocksArc;
176                     }
177                 };
178 
179         mHdmiControlService.setIoLooper(mMyLooper);
180         mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
181         mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper());
182         mNativeWrapper = new FakeNativeWrapper();
183         mHdmiCecController = HdmiCecController.createWithNativeWrapper(
184                 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
185         mHdmiControlService.setCecController(mHdmiCecController);
186         mEarcNativeWrapper = new FakeEarcNativeWrapper();
187         mHdmiEarcController = HdmiEarcController.createWithNativeWrapper(
188                 mHdmiControlService, mEarcNativeWrapper);
189         mHdmiControlService.setEarcController(mHdmiEarcController);
190         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
191         HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[2];
192         hdmiPortInfos[0] = new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_INPUT, 0x1000)
193                 .setCecSupported(true)
194                 .setMhlSupported(false)
195                 .setArcSupported(false)
196                 .setEarcSupported(false)
197                 .build();
198         hdmiPortInfos[1] =
199                 new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, 0x2000)
200                         .setCecSupported(true)
201                         .setMhlSupported(false)
202                         .setArcSupported(true)
203                         .setEarcSupported(true)
204                         .build();
205         mNativeWrapper.setPortInfo(hdmiPortInfos);
206         mHdmiControlService.initService();
207         mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
208         mPowerManager = new FakePowerManagerWrapper(context);
209         mHdmiControlService.setPowerManager(mPowerManager);
210         mTvPhysicalAddress = 0x0000;
211         mEarcBlocksArc = false;
212         mNativeWrapper.setPhysicalAddress(mTvPhysicalAddress);
213         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
214         mTestLooper.dispatchAll();
215         mHdmiCecLocalDeviceTv = mHdmiControlService.tv();
216         mTvLogicalAddress = mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress();
217         mLocalDevices.add(mHdmiCecLocalDeviceTv);
218         for (String sad : SADS_NOT_TO_QUERY) {
219             mHdmiControlService.getHdmiCecConfig().setIntValue(
220                     sad, HdmiControlManager.QUERY_SAD_DISABLED);
221         }
222         mNativeWrapper.clearResultMessages();
223     }
224 
225     private static class TestCallback extends IHdmiControlCallback.Stub {
226         private final ArrayList<Integer> mCallbackResult = new ArrayList<Integer>();
227 
228         @Override
onComplete(int result)229         public void onComplete(int result) {
230             mCallbackResult.add(result);
231         }
232 
getResult()233         private int getResult() {
234             assertThat(mCallbackResult.size()).isEqualTo(1);
235             return mCallbackResult.get(0);
236         }
237     }
238 
239 
initiateArcAndValidate()240     private void initiateArcAndValidate() {
241         HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
242                 ADDR_AUDIO_SYSTEM,
243                 ADDR_TV);
244 
245         mNativeWrapper.onCecMessage(initiateArc);
246         mTestLooper.dispatchAll();
247 
248         HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
249                 ADDR_TV,
250                 ADDR_AUDIO_SYSTEM);
251         // <Report ARC Initiated> should only be sent after SAD querying is done
252         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
253 
254         // Finish querying SADs
255         assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
256         mNativeWrapper.clearResultMessages();
257         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
258         mTestLooper.dispatchAll();
259         assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
260         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
261         mTestLooper.dispatchAll();
262 
263         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
264         mNativeWrapper.clearResultMessages();
265     }
266 
initateSamAndValidate()267     private void initateSamAndValidate() {
268         // Record that previous system audio mode is on.
269         mHdmiCecLocalDeviceTv.setSystemAudioControlFeatureEnabled(true);
270 
271         HdmiCecFeatureAction action = new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv,
272                 ADDR_AUDIO_SYSTEM);
273         mHdmiCecLocalDeviceTv.addAndStartAction(action);
274         mTestLooper.dispatchAll();
275 
276         HdmiCecMessage giveSystemAudioModeStatus =
277                 HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(
278                         mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
279                         ADDR_AUDIO_SYSTEM);
280 
281         assertThat(mNativeWrapper.getResultMessages()).contains(giveSystemAudioModeStatus);
282 
283         HdmiCecMessage reportSystemAudioMode =
284                 HdmiCecMessageBuilder.buildReportSystemAudioMode(
285                         ADDR_AUDIO_SYSTEM,
286                         mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
287                         true);
288         mHdmiControlService.handleCecCommand(reportSystemAudioMode);
289         mTestLooper.dispatchAll();
290 
291         assertThat(mHdmiControlService.isSystemAudioActivated()).isTrue();
292     }
293 
294     @Test
initialPowerStateIsStandby()295     public void initialPowerStateIsStandby() {
296         assertThat(mHdmiCecLocalDeviceTv.getPowerStatus()).isEqualTo(
297                 HdmiControlManager.POWER_STATUS_STANDBY);
298     }
299 
300     @Test
onAddressAllocated_invokesDeviceDiscovery()301     public void onAddressAllocated_invokesDeviceDiscovery() {
302         mHdmiControlService.getHdmiCecNetwork().clearLocalDevices();
303         mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
304         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
305 
306         mTestLooper.dispatchAll();
307 
308         // Check for for <Give Physical Address> being sent to available device (ADDR_PLAYBACK_1).
309         // This message is sent as part of the DeviceDiscoveryAction to available devices.
310         HdmiCecMessage givePhysicalAddress = HdmiCecMessageBuilder.buildGivePhysicalAddress(ADDR_TV,
311                 ADDR_PLAYBACK_1);
312         assertThat(mNativeWrapper.getResultMessages()).contains(givePhysicalAddress);
313     }
314 
315     @Test
getActiveSource_noActiveSource()316     public void getActiveSource_noActiveSource() {
317         mHdmiControlService.setActiveSource(Constants.ADDR_UNREGISTERED,
318                 Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
319         mHdmiCecLocalDeviceTv.setActivePath(HdmiDeviceInfo.PATH_INVALID);
320 
321         assertThat(mHdmiControlService.getActiveSource()).isNull();
322     }
323 
324     @Test
getActiveSource_deviceInNetworkIsActiveSource()325     public void getActiveSource_deviceInNetworkIsActiveSource() {
326         HdmiDeviceInfo externalDevice = HdmiDeviceInfo.cecDeviceBuilder()
327                 .setLogicalAddress(Constants.ADDR_PLAYBACK_3)
328                 .setPhysicalAddress(0x3000)
329                 .setPortId(0)
330                 .setDeviceType(Constants.ADDR_PLAYBACK_1)
331                 .setVendorId(0)
332                 .setDisplayName("Test Device")
333                 .build();
334         mHdmiControlService.getHdmiCecNetwork().addCecDevice(externalDevice);
335         mTestLooper.dispatchAll();
336 
337         mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
338                 externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
339 
340         assertThat(mHdmiControlService.getActiveSource()).isEqualTo(externalDevice);
341     }
342 
343     @Test
getActiveSource_unknownLogicalAddressInNetworkIsActiveSource()344     public void getActiveSource_unknownLogicalAddressInNetworkIsActiveSource() {
345         HdmiDeviceInfo externalDevice = HdmiDeviceInfo.hardwarePort(0x1000, 1);
346 
347         mHdmiControlService.setActiveSource(Constants.ADDR_UNREGISTERED,
348                 externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
349         mHdmiCecLocalDeviceTv.setActivePath(0x1000);
350 
351         assertThat(mHdmiControlService.getActiveSource()).isEqualTo(
352                 externalDevice);
353     }
354 
355     @Test
getActiveSource_unknownDeviceIsActiveSource()356     public void getActiveSource_unknownDeviceIsActiveSource() {
357         HdmiDeviceInfo externalDevice = HdmiDeviceInfo.cecDeviceBuilder()
358                 .setLogicalAddress(Constants.ADDR_PLAYBACK_3)
359                 .setPhysicalAddress(0x0000)
360                 .setPortId(0)
361                 .setDeviceType(ADDR_PLAYBACK_1)
362                 .setVendorId(0)
363                 .setDisplayName("Test Device")
364                 .build();
365 
366         mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
367                 externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
368         mHdmiCecLocalDeviceTv.setActivePath(0x1000);
369 
370         assertThat(mHdmiControlService.getActiveSource().getPhysicalAddress()).isEqualTo(
371                 externalDevice.getPhysicalAddress());
372     }
373 
374     @Test
shouldHandleTvPowerKey_CecEnabled_PowerControlModeTv()375     public void shouldHandleTvPowerKey_CecEnabled_PowerControlModeTv() {
376         mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
377                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
378                 HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
379         mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setStringValue(
380                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
381                 HdmiControlManager.POWER_CONTROL_MODE_TV);
382         assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isFalse();
383     }
384 
385     @Test
tvWakeOnOneTouchPlay_TextViewOn_Enabled()386     public void tvWakeOnOneTouchPlay_TextViewOn_Enabled() {
387         mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
388                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
389                 HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED);
390         mTestLooper.dispatchAll();
391         mPowerManager.setInteractive(false);
392         HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(ADDR_PLAYBACK_1,
393                 mTvLogicalAddress);
394         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(textViewOn)).isEqualTo(Constants.HANDLED);
395         mTestLooper.dispatchAll();
396         assertThat(mPowerManager.isInteractive()).isTrue();
397     }
398 
399     @Test
tvWakeOnOneTouchPlay_ImageViewOn_Enabled()400     public void tvWakeOnOneTouchPlay_ImageViewOn_Enabled() {
401         mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
402                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
403                 HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED);
404         mTestLooper.dispatchAll();
405         mPowerManager.setInteractive(false);
406         HdmiCecMessage imageViewOn = HdmiCecMessage.build(ADDR_PLAYBACK_1, mTvLogicalAddress,
407                 Constants.MESSAGE_IMAGE_VIEW_ON, HdmiCecMessage.EMPTY_PARAM);
408         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(imageViewOn)).isEqualTo(Constants.HANDLED);
409         mTestLooper.dispatchAll();
410         assertThat(mPowerManager.isInteractive()).isTrue();
411     }
412 
413     @Test
tvWakeOnOneTouchPlay_TextViewOn_Disabled()414     public void tvWakeOnOneTouchPlay_TextViewOn_Disabled() {
415         mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
416                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
417                 HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED);
418         mTestLooper.dispatchAll();
419         mPowerManager.setInteractive(false);
420         HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(ADDR_PLAYBACK_1,
421                 mTvLogicalAddress);
422         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(textViewOn)).isEqualTo(Constants.HANDLED);
423         mTestLooper.dispatchAll();
424         assertThat(mPowerManager.isInteractive()).isFalse();
425     }
426 
427     @Test
tvWakeOnOneTouchPlay_ImageViewOn_Disabled()428     public void tvWakeOnOneTouchPlay_ImageViewOn_Disabled() {
429         mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
430                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
431                 HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED);
432         mTestLooper.dispatchAll();
433         mPowerManager.setInteractive(false);
434         HdmiCecMessage imageViewOn = HdmiCecMessage.build(ADDR_PLAYBACK_1, mTvLogicalAddress,
435                 Constants.MESSAGE_IMAGE_VIEW_ON, HdmiCecMessage.EMPTY_PARAM);
436         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(imageViewOn)).isEqualTo(Constants.HANDLED);
437         mTestLooper.dispatchAll();
438         assertThat(mPowerManager.isInteractive()).isFalse();
439     }
440 
441     @Test
handleTextViewOn_Dreaming()442     public void handleTextViewOn_Dreaming() {
443         mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
444                 HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
445                 HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED);
446         mTestLooper.dispatchAll();
447         mPowerManager.setInteractive(true);
448         mWokenUp = false;
449         HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(ADDR_PLAYBACK_1,
450                 mTvLogicalAddress);
451         assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(textViewOn)).isEqualTo(Constants.HANDLED);
452         mTestLooper.dispatchAll();
453         assertThat(mPowerManager.isInteractive()).isTrue();
454         assertThat(mWokenUp).isTrue();
455     }
456 
457     @Test
tvSendStandbyOnSleep_Enabled()458     public void tvSendStandbyOnSleep_Enabled() {
459         mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
460                 HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
461                 HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
462         mTestLooper.dispatchAll();
463         mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
464         mTestLooper.dispatchAll();
465         HdmiCecMessage standby = HdmiCecMessageBuilder.buildStandby(ADDR_TV, ADDR_BROADCAST);
466         assertThat(mNativeWrapper.getResultMessages()).contains(standby);
467     }
468 
469     @Test
tvSendStandbyOnSleep_Disabled()470     public void tvSendStandbyOnSleep_Disabled() {
471         mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
472                 HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
473                 HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_DISABLED);
474         mTestLooper.dispatchAll();
475         mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
476         mTestLooper.dispatchAll();
477         HdmiCecMessage standby = HdmiCecMessageBuilder.buildStandby(ADDR_TV, ADDR_BROADCAST);
478         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standby);
479     }
480 
481     @Test
getRcFeatures()482     public void getRcFeatures() {
483         ArrayList<Integer> features = new ArrayList<>(mHdmiCecLocalDeviceTv.getRcFeatures());
484         assertThat(features.contains(Constants.RC_PROFILE_TV_NONE)).isTrue();
485         assertThat(features.contains(Constants.RC_PROFILE_TV_ONE)).isFalse();
486         assertThat(features.contains(Constants.RC_PROFILE_TV_TWO)).isFalse();
487         assertThat(features.contains(Constants.RC_PROFILE_TV_THREE)).isFalse();
488         assertThat(features.contains(Constants.RC_PROFILE_TV_FOUR)).isFalse();
489     }
490 
491     @Test
startArcAction_enable_noAudioDevice()492     public void startArcAction_enable_noAudioDevice() {
493         mHdmiCecLocalDeviceTv.startArcAction(true);
494 
495         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
496                 ADDR_TV,
497                 ADDR_AUDIO_SYSTEM);
498         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
499                 ADDR_TV,
500                 ADDR_AUDIO_SYSTEM);
501         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcInitiation);
502         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination);
503     }
504 
505 
506     @Test
startArcAction_disable_noAudioDevice()507     public void startArcAction_disable_noAudioDevice() {
508         mHdmiCecLocalDeviceTv.startArcAction(false);
509 
510         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
511                 ADDR_TV,
512                 ADDR_AUDIO_SYSTEM);
513         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
514                 ADDR_TV,
515                 ADDR_AUDIO_SYSTEM);
516         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcInitiation);
517         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination);
518     }
519 
520     @Test
startArcAction_enable_portDoesNotSupportArc()521     public void startArcAction_enable_portDoesNotSupportArc() {
522         // Emulate Audio device on port 0x1000 (does not support ARC)
523         mNativeWrapper.setPortConnectionStatus(1, true);
524         HdmiCecMessage reportPhysicalAddress =
525                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
526                         ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
527         mNativeWrapper.onCecMessage(reportPhysicalAddress);
528 
529         mHdmiCecLocalDeviceTv.startArcAction(true);
530         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
531                 ADDR_TV,
532                 ADDR_AUDIO_SYSTEM);
533         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
534                 ADDR_TV,
535                 ADDR_AUDIO_SYSTEM);
536         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcInitiation);
537         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination);
538     }
539 
540     @Test
startArcAction_disable_portDoesNotSupportArc()541     public void startArcAction_disable_portDoesNotSupportArc() {
542         // Emulate Audio device on port 0x1000 (does not support ARC)
543         mNativeWrapper.setPortConnectionStatus(1, true);
544         HdmiCecMessage reportPhysicalAddress =
545                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
546                         ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
547         mNativeWrapper.onCecMessage(reportPhysicalAddress);
548 
549         mHdmiCecLocalDeviceTv.startArcAction(false);
550         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
551                 ADDR_TV,
552                 ADDR_AUDIO_SYSTEM);
553         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
554                 ADDR_TV,
555                 ADDR_AUDIO_SYSTEM);
556         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcInitiation);
557         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination);
558     }
559 
560     @Test
startArcAction_enable_portSupportsArc()561     public void startArcAction_enable_portSupportsArc() {
562         // Emulate Audio device on port 0x2000 (supports ARC)
563         mNativeWrapper.setPortConnectionStatus(2, true);
564         HdmiCecMessage reportPhysicalAddress =
565                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
566                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
567         mNativeWrapper.onCecMessage(reportPhysicalAddress);
568         mTestLooper.dispatchAll();
569 
570         mHdmiCecLocalDeviceTv.startArcAction(true);
571         mTestLooper.dispatchAll();
572         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
573                 ADDR_TV,
574                 ADDR_AUDIO_SYSTEM);
575         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
576                 ADDR_TV,
577                 ADDR_AUDIO_SYSTEM);
578         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation);
579         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination);
580     }
581 
582     @Test
startArcAction_disable_portSupportsArc()583     public void startArcAction_disable_portSupportsArc() {
584         // Emulate Audio device on port 0x2000 (supports ARC)
585         mNativeWrapper.setPortConnectionStatus(2, true);
586         HdmiCecMessage reportPhysicalAddress =
587                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
588                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
589         mNativeWrapper.onCecMessage(reportPhysicalAddress);
590         mTestLooper.dispatchAll();
591 
592         mHdmiCecLocalDeviceTv.startArcAction(false);
593         mTestLooper.dispatchAll();
594         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
595                 ADDR_TV,
596                 ADDR_AUDIO_SYSTEM);
597         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
598                 ADDR_TV,
599                 ADDR_AUDIO_SYSTEM);
600         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcInitiation);
601         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
602     }
603 
604     @Test
handleInitiateArc_noAudioDevice()605     public void handleInitiateArc_noAudioDevice() {
606         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
607                 ADDR_AUDIO_SYSTEM,
608                 ADDR_TV);
609 
610         mNativeWrapper.onCecMessage(requestArcInitiation);
611         mTestLooper.dispatchAll();
612 
613         HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
614                 ADDR_TV,
615                 ADDR_AUDIO_SYSTEM);
616         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
617         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
618     }
619 
620     @Test
handleInitiateArc_portDoesNotSupportArc()621     public void handleInitiateArc_portDoesNotSupportArc() {
622         // Emulate Audio device on port 0x1000 (does not support ARC)
623         mNativeWrapper.setPortConnectionStatus(1, true);
624         HdmiCecMessage reportPhysicalAddress =
625                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
626                         ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
627         mNativeWrapper.onCecMessage(reportPhysicalAddress);
628 
629         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
630                 ADDR_AUDIO_SYSTEM,
631                 ADDR_TV);
632 
633         mNativeWrapper.onCecMessage(requestArcInitiation);
634         mTestLooper.dispatchAll();
635 
636         HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
637                 ADDR_TV,
638                 ADDR_AUDIO_SYSTEM);
639         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
640         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
641     }
642 
643     @Test
handleInitiateArc_portSupportsArc()644     public void handleInitiateArc_portSupportsArc() {
645         // Emulate Audio device on port 0x2000 (supports ARC)
646         mNativeWrapper.setPortConnectionStatus(2, true);
647         HdmiCecMessage reportPhysicalAddress =
648                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
649                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
650         mNativeWrapper.onCecMessage(reportPhysicalAddress);
651         mTestLooper.dispatchAll();
652 
653         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
654                 ADDR_AUDIO_SYSTEM,
655                 ADDR_TV);
656 
657         mNativeWrapper.onCecMessage(requestArcInitiation);
658         mTestLooper.dispatchAll();
659 
660         HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
661                 ADDR_TV,
662                 ADDR_AUDIO_SYSTEM);
663         // <Report ARC Initiated> should only be sent after SAD querying is done
664         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
665 
666         // Finish querying SADs
667         assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
668         mNativeWrapper.clearResultMessages();
669         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
670         mTestLooper.dispatchAll();
671         assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
672         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
673         mTestLooper.dispatchAll();
674 
675         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
676     }
677 
678     @Test
handleTerminateArc_noAudioDevice()679     public void handleTerminateArc_noAudioDevice() {
680         HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
681                 ADDR_AUDIO_SYSTEM,
682                 ADDR_TV);
683 
684         mNativeWrapper.onCecMessage(terminateArc);
685         mTestLooper.dispatchAll();
686 
687         HdmiCecMessage reportArcTerminated = HdmiCecMessageBuilder.buildReportArcTerminated(
688                 ADDR_TV,
689                 ADDR_AUDIO_SYSTEM);
690         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcTerminated);
691     }
692 
693     @Test
handleTerminateArc_portDoesNotSupportArc()694     public void handleTerminateArc_portDoesNotSupportArc() {
695         // Emulate Audio device on port 0x1000 (does not support ARC)
696         mNativeWrapper.setPortConnectionStatus(1, true);
697         HdmiCecMessage reportPhysicalAddress =
698                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
699                         ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
700         mNativeWrapper.onCecMessage(reportPhysicalAddress);
701 
702         HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
703                 ADDR_AUDIO_SYSTEM,
704                 ADDR_TV);
705 
706         mNativeWrapper.onCecMessage(terminateArc);
707         mTestLooper.dispatchAll();
708 
709         HdmiCecMessage reportArcTerminated = HdmiCecMessageBuilder.buildReportArcTerminated(
710                 ADDR_TV,
711                 ADDR_AUDIO_SYSTEM);
712         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcTerminated);
713     }
714 
715     @Test
handleTerminateArc_portSupportsArc()716     public void handleTerminateArc_portSupportsArc() {
717         // Emulate Audio device on port 0x2000 (supports ARC)
718         mNativeWrapper.setPortConnectionStatus(2, true);
719         HdmiCecMessage reportPhysicalAddress =
720                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
721                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
722         mNativeWrapper.onCecMessage(reportPhysicalAddress);
723         mTestLooper.dispatchAll();
724 
725         HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
726                 ADDR_AUDIO_SYSTEM,
727                 ADDR_TV);
728 
729         mNativeWrapper.onCecMessage(terminateArc);
730         mTestLooper.dispatchAll();
731 
732         HdmiCecMessage reportArcTerminated = HdmiCecMessageBuilder.buildReportArcTerminated(
733                 ADDR_TV,
734                 ADDR_AUDIO_SYSTEM);
735         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcTerminated);
736     }
737 
738     @Test
supportsRecordTvScreen()739     public void supportsRecordTvScreen() {
740         HdmiCecMessage recordTvScreen = HdmiCecMessage.build(ADDR_RECORDER_1, mTvLogicalAddress,
741                 Constants.MESSAGE_RECORD_TV_SCREEN, HdmiCecMessage.EMPTY_PARAM);
742 
743         mNativeWrapper.onCecMessage(recordTvScreen);
744         mTestLooper.dispatchAll();
745 
746         HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
747                 mTvLogicalAddress, ADDR_RECORDER_1, Constants.MESSAGE_RECORD_TV_SCREEN,
748                 ABORT_UNRECOGNIZED_OPCODE);
749         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbort);
750     }
751 
752     @Test
handleReportAudioStatus_SamOnArcOff_setStreamVolumeNotCalled()753     public void handleReportAudioStatus_SamOnArcOff_setStreamVolumeNotCalled() {
754         mHdmiControlService.getHdmiCecConfig().setIntValue(
755                 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
756                 HdmiControlManager.SYSTEM_AUDIO_CONTROL_ENABLED);
757         // Emulate Audio device on port 0x1000 (does not support ARC)
758         mNativeWrapper.setPortConnectionStatus(1, true);
759         HdmiCecMessage reportPhysicalAddress =
760                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
761                         ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
762         mNativeWrapper.onCecMessage(reportPhysicalAddress);
763         mTestLooper.dispatchAll();
764 
765         HdmiCecFeatureAction systemAudioAutoInitiationAction =
766                 new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM);
767         mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction);
768         HdmiCecMessage reportSystemAudioMode =
769                 HdmiCecMessageBuilder.buildReportSystemAudioMode(
770                         ADDR_AUDIO_SYSTEM,
771                         mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress(),
772                         true);
773         mHdmiControlService.handleCecCommand(reportSystemAudioMode);
774 
775         mTestLooper.dispatchAll();
776 
777         // SAM must be on; ARC must be off
778         assertTrue(mHdmiCecLocalDeviceTv.isSystemAudioActivated());
779         assertFalse(mHdmiCecLocalDeviceTv.isArcEstablished());
780 
781         HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus(
782                 ADDR_AUDIO_SYSTEM,
783                 ADDR_TV,
784                 50, // Volume of incoming message does not affect HDMI-CEC logic
785                 false);
786         mNativeWrapper.onCecMessage(reportAudioStatus);
787 
788         mTestLooper.dispatchAll();
789 
790         verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt());
791     }
792 
793     /**
794      * Tests that receiving a message from a device does not prevent it from being discovered
795      * by HotplugDetectionAction.
796      */
797     @Test
hotplugDetectionAction_discoversDeviceAfterMessageReceived()798     public void hotplugDetectionAction_discoversDeviceAfterMessageReceived() {
799         // Playback 1 sends a message before ACKing a poll
800         mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.NACK);
801         HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
802                 ADDR_PLAYBACK_1, ADDR_TV);
803         mNativeWrapper.onCecMessage(activeSource);
804         mTestLooper.dispatchAll();
805 
806         // Playback 1 begins ACKing polls, allowing detection by HotplugDetectionAction
807         mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
808         for (int pollCount = 0; pollCount < HotplugDetectionAction.TIMEOUT_COUNT; pollCount++) {
809             mTestLooper.moveTimeForward(
810                     TimeUnit.SECONDS.toMillis(HotplugDetectionAction.POLLING_INTERVAL_MS_FOR_TV));
811             mTestLooper.dispatchAll();
812         }
813 
814         // Device sends <Give Physical Address> to Playback 1 after detecting it
815         HdmiCecMessage givePhysicalAddress = HdmiCecMessageBuilder.buildGivePhysicalAddress(
816                 ADDR_TV, ADDR_PLAYBACK_1);
817         assertThat(mNativeWrapper.getResultMessages()).contains(givePhysicalAddress);
818     }
819 
820     @Test
hotplugDetectionActionClearsDevices()821     public void hotplugDetectionActionClearsDevices() {
822         mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
823         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
824                 .isEmpty();
825         // Add a device to the network and assert that this device is included in the list of
826         // devices.
827         HdmiDeviceInfo infoPlayback = HdmiDeviceInfo.cecDeviceBuilder()
828                 .setLogicalAddress(Constants.ADDR_PLAYBACK_2)
829                 .setPhysicalAddress(0x1000)
830                 .setPortId(PORT_1)
831                 .setDeviceType(HdmiDeviceInfo.DEVICE_PLAYBACK)
832                 .setVendorId(0x1000)
833                 .setDisplayName("Playback 2")
834                 .build();
835         mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoPlayback);
836         mTestLooper.dispatchAll();
837         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
838                 .hasSize(1);
839         mDeviceEventListeners.clear();
840         assertThat(mDeviceEventListeners.size()).isEqualTo(0);
841 
842         // HAL detects a hotplug out. Assert that this device stays in the list of devices.
843         mHdmiControlService.onHotplug(PORT_1, false);
844         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
845                 .hasSize(1);
846         assertThat(mDeviceEventListeners).isEmpty();
847         mTestLooper.dispatchAll();
848         // Make the device not acknowledge the poll message sent by the HotplugDetectionAction.
849         // Assert that this device is removed from the list of devices.
850         mNativeWrapper.setPollAddressResponse(Constants.ADDR_PLAYBACK_2, SendMessageResult.NACK);
851         for (int pollCount = 0; pollCount < HotplugDetectionAction.TIMEOUT_COUNT; pollCount++) {
852             mTestLooper.moveTimeForward(HotplugDetectionAction.POLLING_INTERVAL_MS_FOR_TV);
853             mTestLooper.dispatchAll();
854         }
855 
856         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
857                 .isEmpty();
858         assertThat(mDeviceEventListeners.size()).isEqualTo(1);
859         assertThat(mDeviceEventListeners.get(0).getStatus())
860                 .isEqualTo(HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
861         HdmiDeviceInfo removedDeviceInfo = mDeviceEventListeners.get(0).getDeviceInfo();
862         assertThat(removedDeviceInfo.getPortId()).isEqualTo(PORT_1);
863         assertThat(removedDeviceInfo.getLogicalAddress()).isEqualTo(Constants.ADDR_PLAYBACK_2);
864         assertThat(removedDeviceInfo.getPhysicalAddress()).isEqualTo(0x1000);
865         assertThat(removedDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_PLAYBACK);
866     }
867 
868     @Test
hotplugDetectionActionClearsDevices_AudioSystem()869     public void hotplugDetectionActionClearsDevices_AudioSystem() {
870         mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
871         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
872                 .isEmpty();
873         // Add a device to the network and assert that this device is included in the list of
874         // devices.
875         HdmiDeviceInfo infoAudioSystem = HdmiDeviceInfo.cecDeviceBuilder()
876                 .setLogicalAddress(ADDR_AUDIO_SYSTEM)
877                 .setPhysicalAddress(0x1000)
878                 .setPortId(PORT_1)
879                 .setDeviceType(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)
880                 .setVendorId(0x1000)
881                 .setDisplayName("Audio System")
882                 .build();
883         mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoAudioSystem);
884         mTestLooper.dispatchAll();
885         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
886                 .hasSize(1);
887         mDeviceEventListeners.clear();
888         assertThat(mDeviceEventListeners.size()).isEqualTo(0);
889 
890         // HAL detects a hotplug out. Assert that this device stays in the list of devices.
891         mHdmiControlService.onHotplug(PORT_1, false);
892         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
893                 .hasSize(1);
894         assertThat(mDeviceEventListeners).isEmpty();
895         mTestLooper.dispatchAll();
896         // Make the device not acknowledge the poll message sent by the HotplugDetectionAction.
897         // Assert that this device is removed from the list of devices.
898         mNativeWrapper.setPollAddressResponse(ADDR_AUDIO_SYSTEM, SendMessageResult.NACK);
899         for (int pollCount = 0; pollCount < HotplugDetectionAction.TIMEOUT_COUNT; pollCount++) {
900             mTestLooper.moveTimeForward(HotplugDetectionAction.POLLING_INTERVAL_MS_FOR_TV);
901             mTestLooper.dispatchAll();
902         }
903 
904         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
905                 .isEmpty();
906         assertThat(mDeviceEventListeners.size()).isEqualTo(1);
907         assertThat(mDeviceEventListeners.get(0).getStatus())
908                 .isEqualTo(HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
909         HdmiDeviceInfo removedDeviceInfo = mDeviceEventListeners.get(0).getDeviceInfo();
910         assertThat(removedDeviceInfo.getPortId()).isEqualTo(PORT_1);
911         assertThat(removedDeviceInfo.getLogicalAddress()).isEqualTo(Constants.ADDR_AUDIO_SYSTEM);
912         assertThat(removedDeviceInfo.getPhysicalAddress()).isEqualTo(0x1000);
913         assertThat(removedDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
914     }
915 
916     @Test
listenerInvokedIfPhysicalAddressReported()917     public void listenerInvokedIfPhysicalAddressReported() {
918         mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
919         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
920                 .isEmpty();
921         HdmiCecMessage reportPhysicalAddress =
922                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
923                 ADDR_PLAYBACK_2, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
924         mNativeWrapper.onCecMessage(reportPhysicalAddress);
925         mTestLooper.dispatchAll();
926 
927         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
928                 .hasSize(1);
929         assertThat(mDeviceEventListeners.size()).isEqualTo(1);
930         assertThat(mDeviceEventListeners.get(0).getStatus())
931                 .isEqualTo(HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
932     }
933 
934     @Test
listenerNotInvokedIfPhysicalAddressUnknown()935     public void listenerNotInvokedIfPhysicalAddressUnknown() {
936         mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
937         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
938                 .isEmpty();
939         HdmiCecMessage setOsdName = HdmiCecMessageBuilder.buildSetOsdNameCommand(
940                 ADDR_PLAYBACK_2, ADDR_TV, "Playback 2");
941         mNativeWrapper.onCecMessage(setOsdName);
942         mTestLooper.dispatchAll();
943 
944         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
945                 .hasSize(1);
946         assertThat(mDeviceEventListeners).isEmpty();
947 
948         // When the device reports its physical address, the listener eventually is invoked.
949         HdmiCecMessage reportPhysicalAddress =
950                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
951                         ADDR_PLAYBACK_2, 0x1000, HdmiDeviceInfo.DEVICE_PLAYBACK);
952         mNativeWrapper.onCecMessage(reportPhysicalAddress);
953         mTestLooper.dispatchAll();
954 
955         assertThat(mHdmiControlService.getHdmiCecNetwork().getDeviceInfoList(false))
956                 .hasSize(1);
957         assertThat(mDeviceEventListeners.size()).isEqualTo(1);
958         assertThat(mDeviceEventListeners.get(0).getStatus())
959                 .isEqualTo(HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
960     }
961 
962     @Test
receiveSetAudioVolumeLevel_samNotActivated_noFeatureAbort_volumeChanges()963     public void receiveSetAudioVolumeLevel_samNotActivated_noFeatureAbort_volumeChanges() {
964         mAudioFramework.setStreamMaxVolume(AudioManager.STREAM_MUSIC, 25);
965 
966         // Max volume of STREAM_MUSIC is retrieved on boot
967         mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY);
968         mTestLooper.dispatchAll();
969 
970         mNativeWrapper.onCecMessage(SetAudioVolumeLevelMessage.build(
971                 ADDR_PLAYBACK_1,
972                 ADDR_TV,
973                 20));
974         mTestLooper.dispatchAll();
975 
976         // <Feature Abort>[Not in correct mode] not sent
977         HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
978                 ADDR_TV,
979                 ADDR_PLAYBACK_1,
980                 Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL,
981                 Constants.ABORT_NOT_IN_CORRECT_MODE);
982         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbort);
983 
984         // <Set Audio Volume Level> uses volume range [0, 100]; STREAM_MUSIC uses range [0, 25]
985         verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(5), anyInt());
986     }
987 
988     @Test
receiveSetAudioVolumeLevel_samActivated_respondsFeatureAbort_noVolumeChange()989     public void receiveSetAudioVolumeLevel_samActivated_respondsFeatureAbort_noVolumeChange() {
990         mHdmiControlService.getHdmiCecConfig().setIntValue(
991                 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
992                 HdmiControlManager.SYSTEM_AUDIO_CONTROL_ENABLED);
993 
994         mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildSetSystemAudioMode(
995                 ADDR_AUDIO_SYSTEM, ADDR_TV, true));
996         mTestLooper.dispatchAll();
997 
998         mNativeWrapper.onCecMessage(SetAudioVolumeLevelMessage.build(
999                 ADDR_PLAYBACK_1, ADDR_TV, 50));
1000         mTestLooper.dispatchAll();
1001 
1002         // <Feature Abort>[Not in correct mode] sent
1003         HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
1004                 ADDR_TV,
1005                 ADDR_PLAYBACK_1,
1006                 Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL,
1007                 Constants.ABORT_NOT_IN_CORRECT_MODE);
1008         assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort);
1009 
1010         // AudioManager not notified of volume change
1011         verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(),
1012                 anyInt());
1013     }
1014 
1015     @Test
tvSendRequestArcTerminationOnSleep()1016     public void tvSendRequestArcTerminationOnSleep() {
1017         // Emulate Audio device on port 0x2000 (supports ARC)
1018         mNativeWrapper.setPortConnectionStatus(2, true);
1019         HdmiCecMessage reportPhysicalAddress =
1020                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1021                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1022         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1023         mTestLooper.dispatchAll();
1024 
1025         mHdmiCecLocalDeviceTv.startArcAction(true);
1026         mTestLooper.dispatchAll();
1027         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
1028                 ADDR_TV,
1029                 ADDR_AUDIO_SYSTEM);
1030         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1031                 ADDR_TV,
1032                 ADDR_AUDIO_SYSTEM);
1033         HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
1034                 ADDR_AUDIO_SYSTEM,
1035                 ADDR_TV);
1036         HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
1037                 ADDR_TV,
1038                 ADDR_AUDIO_SYSTEM);
1039 
1040         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation);
1041         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination);
1042 
1043         mNativeWrapper.onCecMessage(initiateArc);
1044         mTestLooper.dispatchAll();
1045 
1046         // Finish querying SADs
1047         assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
1048         mNativeWrapper.clearResultMessages();
1049         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
1050         mTestLooper.dispatchAll();
1051         assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
1052         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
1053         mTestLooper.dispatchAll();
1054 
1055         // ARC should be established after RequestSadAction is finished
1056         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
1057 
1058         mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF);
1059         mTestLooper.dispatchAll();
1060         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
1061     }
1062 
1063     @Test
startArcAction_enable_earcBlocksArc()1064     public void startArcAction_enable_earcBlocksArc() {
1065         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1066         mTestLooper.dispatchAll();
1067 
1068         mEarcBlocksArc = true;
1069 
1070         // Emulate Audio device on port 0x2000 (supports ARC and eARC)
1071         mNativeWrapper.setPortConnectionStatus(2, true);
1072         HdmiCecMessage reportPhysicalAddress =
1073                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1074                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1075         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1076         mTestLooper.dispatchAll();
1077 
1078         mHdmiCecLocalDeviceTv.startArcAction(true);
1079         mTestLooper.dispatchAll();
1080         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
1081                 ADDR_TV,
1082                 ADDR_AUDIO_SYSTEM);
1083         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1084                 ADDR_TV,
1085                 ADDR_AUDIO_SYSTEM);
1086         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcInitiation);
1087         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination);
1088     }
1089 
1090     @Test
startArcAction_enable_earcDoesNotBlockArc()1091     public void startArcAction_enable_earcDoesNotBlockArc() {
1092         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1093         mTestLooper.dispatchAll();
1094 
1095         mEarcBlocksArc = false;
1096 
1097         // Emulate Audio device on port 0x2000 (supports ARC and eARC)
1098         mNativeWrapper.setPortConnectionStatus(2, true);
1099         HdmiCecMessage reportPhysicalAddress =
1100                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1101                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1102         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1103         mTestLooper.dispatchAll();
1104 
1105         mHdmiCecLocalDeviceTv.startArcAction(true);
1106         mTestLooper.dispatchAll();
1107         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
1108                 ADDR_TV,
1109                 ADDR_AUDIO_SYSTEM);
1110         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1111                 ADDR_TV,
1112                 ADDR_AUDIO_SYSTEM);
1113         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation);
1114         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcTermination);
1115     }
1116 
1117     @Test
startArcAction_disable_earcBlocksArc()1118     public void startArcAction_disable_earcBlocksArc() {
1119         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1120         mTestLooper.dispatchAll();
1121 
1122         mEarcBlocksArc = true;
1123 
1124         // Emulate Audio device on port 0x2000 (supports ARC and eARC)
1125         mNativeWrapper.setPortConnectionStatus(2, true);
1126         HdmiCecMessage reportPhysicalAddress =
1127                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1128                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1129         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1130         mTestLooper.dispatchAll();
1131 
1132         mHdmiCecLocalDeviceTv.startArcAction(false);
1133         mTestLooper.dispatchAll();
1134         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
1135                 ADDR_TV,
1136                 ADDR_AUDIO_SYSTEM);
1137         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1138                 ADDR_TV,
1139                 ADDR_AUDIO_SYSTEM);
1140         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(requestArcInitiation);
1141         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
1142     }
1143 
1144     @Test
handleInitiateArc_earcBlocksArc()1145     public void handleInitiateArc_earcBlocksArc() {
1146         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1147         mTestLooper.dispatchAll();
1148 
1149         mEarcBlocksArc = true;
1150 
1151         // Emulate Audio device on port 0x2000 (supports ARC and eARC)
1152         mNativeWrapper.setPortConnectionStatus(2, true);
1153         HdmiCecMessage reportPhysicalAddress =
1154                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1155                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1156         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1157         mTestLooper.dispatchAll();
1158 
1159         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
1160                 ADDR_AUDIO_SYSTEM,
1161                 ADDR_TV);
1162 
1163         mNativeWrapper.onCecMessage(requestArcInitiation);
1164         mTestLooper.dispatchAll();
1165 
1166         HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
1167                 ADDR_TV,
1168                 ADDR_AUDIO_SYSTEM,
1169                 Constants.MESSAGE_INITIATE_ARC,
1170                 Constants.ABORT_NOT_IN_CORRECT_MODE);
1171         assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort);
1172     }
1173 
1174     @Test
handleInitiateArc_earcDoesNotBlockArc()1175     public void handleInitiateArc_earcDoesNotBlockArc() {
1176         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1177         mTestLooper.dispatchAll();
1178 
1179         mEarcBlocksArc = false;
1180 
1181         // Emulate Audio device on port 0x2000 (supports ARC and eARC)
1182         mNativeWrapper.setPortConnectionStatus(2, true);
1183         HdmiCecMessage reportPhysicalAddress =
1184                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1185                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1186         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1187         mTestLooper.dispatchAll();
1188 
1189         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
1190                 ADDR_AUDIO_SYSTEM,
1191                 ADDR_TV);
1192 
1193         mNativeWrapper.onCecMessage(requestArcInitiation);
1194         mTestLooper.dispatchAll();
1195 
1196         HdmiCecMessage reportArcInitiated = HdmiCecMessageBuilder.buildReportArcInitiated(
1197                 ADDR_TV,
1198                 ADDR_AUDIO_SYSTEM);
1199         // <Report ARC Initiated> should only be sent after SAD querying is done
1200         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
1201 
1202         // Finish querying SADs
1203         assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
1204         mNativeWrapper.clearResultMessages();
1205         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
1206         mTestLooper.dispatchAll();
1207         assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
1208         mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
1209         mTestLooper.dispatchAll();
1210 
1211         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
1212     }
1213 
1214     @Test
handleTerminateArc_earcBlocksArc()1215     public void handleTerminateArc_earcBlocksArc() {
1216         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1217         mTestLooper.dispatchAll();
1218 
1219         mEarcBlocksArc = true;
1220 
1221         // Emulate Audio device on port 0x2000 (supports ARC and eARC)
1222         mNativeWrapper.setPortConnectionStatus(2, true);
1223         HdmiCecMessage reportPhysicalAddress =
1224                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1225                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1226         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1227         mTestLooper.dispatchAll();
1228 
1229         HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
1230                 ADDR_AUDIO_SYSTEM,
1231                 ADDR_TV);
1232 
1233         mNativeWrapper.onCecMessage(terminateArc);
1234         mTestLooper.dispatchAll();
1235 
1236         HdmiCecMessage reportArcTerminated = HdmiCecMessageBuilder.buildReportArcTerminated(
1237                 ADDR_TV,
1238                 ADDR_AUDIO_SYSTEM);
1239         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcTerminated);
1240     }
1241 
1242     @Test
startArcAction_initiation_noAvr()1243     public void startArcAction_initiation_noAvr() {
1244         TestCallback callback = new TestCallback();
1245 
1246         mHdmiCecLocalDeviceTv.startArcAction(true, callback);
1247         mTestLooper.dispatchAll();
1248 
1249         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
1250     }
1251 
1252     @Test
startArcAction_initiation_portNotConnected()1253     public void startArcAction_initiation_portNotConnected() {
1254         // Emulate Audio device on port 0x2000 (supports ARC)
1255         HdmiCecMessage reportPhysicalAddress =
1256                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1257                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1258         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1259         mTestLooper.dispatchAll();
1260         // Emulate port disconnect
1261         mNativeWrapper.setPortConnectionStatus(2, false);
1262 
1263         TestCallback callback = new TestCallback();
1264 
1265         mHdmiCecLocalDeviceTv.startArcAction(true, callback);
1266         mTestLooper.dispatchAll();
1267 
1268         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE);
1269     }
1270 
1271     @Test
startArcAction_initiation_portDoesNotSupportArc()1272     public void startArcAction_initiation_portDoesNotSupportArc() {
1273         // Emulate Audio device on port 0x1000 (Doesn´t support ARC)
1274         mNativeWrapper.setPortConnectionStatus(1, true);
1275         HdmiCecMessage reportPhysicalAddress =
1276                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1277                         ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1278         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1279         mTestLooper.dispatchAll();
1280 
1281         TestCallback callback = new TestCallback();
1282 
1283         mHdmiCecLocalDeviceTv.startArcAction(true, callback);
1284         mTestLooper.dispatchAll();
1285 
1286         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE);
1287     }
1288 
1289     @Test
startArcAction_initiation_indirectPhysicalAddress()1290     public void startArcAction_initiation_indirectPhysicalAddress() {
1291         // Emulate Audio device on port 0x2000 (Supports ARC)
1292         mNativeWrapper.setPortConnectionStatus(2, true);
1293         HdmiCecMessage reportPhysicalAddress =
1294                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1295                         ADDR_AUDIO_SYSTEM, 0x2320, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1296         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1297         mTestLooper.dispatchAll();
1298 
1299         TestCallback callback = new TestCallback();
1300 
1301         mHdmiCecLocalDeviceTv.startArcAction(true, callback);
1302         mTestLooper.dispatchAll();
1303 
1304         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE);
1305     }
1306 
1307     @Test
startArcAction_initiation_earcBlocksArc()1308     public void startArcAction_initiation_earcBlocksArc() {
1309         // Emulate Audio device on port 0x2000 (Supports ARC)
1310         mNativeWrapper.setPortConnectionStatus(2, true);
1311         HdmiCecMessage reportPhysicalAddress =
1312                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1313                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1314         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1315         mTestLooper.dispatchAll();
1316 
1317         mEarcBlocksArc = true;
1318 
1319         TestCallback callback = new TestCallback();
1320 
1321         mHdmiCecLocalDeviceTv.startArcAction(true, callback);
1322         mTestLooper.dispatchAll();
1323 
1324         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE);
1325     }
1326 
1327     @Test
startArcAction_initiation_messageNotAcked()1328     public void startArcAction_initiation_messageNotAcked() {
1329         // Emulate Audio device on port 0x2000 (Supports ARC)
1330         mNativeWrapper.setPortConnectionStatus(2, true);
1331         HdmiCecMessage reportPhysicalAddress =
1332                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1333                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1334         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1335         mTestLooper.dispatchAll();
1336 
1337         mNativeWrapper.setMessageSendResult(
1338                 Constants.MESSAGE_REQUEST_ARC_INITIATION, SendMessageResult.NACK);
1339         mTestLooper.dispatchAll();
1340 
1341         TestCallback callback = new TestCallback();
1342 
1343         mHdmiCecLocalDeviceTv.startArcAction(true, callback);
1344         mTestLooper.dispatchAll();
1345 
1346         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
1347                 ADDR_TV,
1348                 ADDR_AUDIO_SYSTEM);
1349         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation);
1350         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
1351     }
1352 
1353     @Test
startArcAction_initiation_timeout()1354     public void startArcAction_initiation_timeout() {
1355         // Emulate Audio device on port 0x2000 (Supports ARC)
1356         mNativeWrapper.setPortConnectionStatus(2, true);
1357         HdmiCecMessage reportPhysicalAddress =
1358                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1359                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1360         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1361         mTestLooper.dispatchAll();
1362 
1363         TestCallback callback = new TestCallback();
1364 
1365         mHdmiCecLocalDeviceTv.startArcAction(true, callback);
1366         mTestLooper.dispatchAll();
1367 
1368         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
1369                 ADDR_TV,
1370                 ADDR_AUDIO_SYSTEM);
1371         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation);
1372         mTestLooper.moveTimeForward(TIMEOUT_MS);
1373         mTestLooper.dispatchAll();
1374         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TIMEOUT);
1375     }
1376 
1377     @Test
startArcAction_initiation_featureAbort()1378     public void startArcAction_initiation_featureAbort() {
1379         // Emulate Audio device on port 0x2000 (Supports ARC)
1380         mNativeWrapper.setPortConnectionStatus(2, true);
1381         HdmiCecMessage reportPhysicalAddress =
1382                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1383                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1384         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1385         mTestLooper.dispatchAll();
1386 
1387         TestCallback callback = new TestCallback();
1388 
1389         mHdmiCecLocalDeviceTv.startArcAction(true, callback);
1390         mTestLooper.dispatchAll();
1391 
1392         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
1393                 ADDR_TV,
1394                 ADDR_AUDIO_SYSTEM);
1395         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation);
1396 
1397         HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
1398                 ADDR_AUDIO_SYSTEM,
1399                 ADDR_TV,
1400                 Constants.MESSAGE_REQUEST_ARC_INITIATION,
1401                 Constants.ABORT_NOT_IN_CORRECT_MODE);
1402         mNativeWrapper.onCecMessage(featureAbort);
1403         mTestLooper.dispatchAll();
1404 
1405         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
1406     }
1407 
1408     @Test
startArcAction_initiation_success()1409     public void startArcAction_initiation_success() {
1410         // Emulate Audio device on port 0x2000 (Supports ARC)
1411         mNativeWrapper.setPortConnectionStatus(2, true);
1412         HdmiCecMessage reportPhysicalAddress =
1413                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1414                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1415         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1416         mTestLooper.dispatchAll();
1417 
1418         TestCallback callback = new TestCallback();
1419 
1420         mHdmiCecLocalDeviceTv.startArcAction(true, callback);
1421         mTestLooper.dispatchAll();
1422 
1423         HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildRequestArcInitiation(
1424                 ADDR_TV,
1425                 ADDR_AUDIO_SYSTEM);
1426         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcInitiation);
1427 
1428         HdmiCecMessage initiateArc = HdmiCecMessageBuilder.buildInitiateArc(
1429                 ADDR_AUDIO_SYSTEM,
1430                 ADDR_TV);
1431         mNativeWrapper.onCecMessage(initiateArc);
1432         mTestLooper.dispatchAll();
1433 
1434         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
1435     }
1436 
1437     @Test
startArcAction_termination_noAvr()1438     public void startArcAction_termination_noAvr() {
1439         TestCallback callback = new TestCallback();
1440 
1441         mHdmiCecLocalDeviceTv.startArcAction(false, callback);
1442         mTestLooper.dispatchAll();
1443 
1444         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
1445     }
1446 
1447     @Test
startArcAction_termination_portDoesNotSupportArc()1448     public void startArcAction_termination_portDoesNotSupportArc() {
1449         // Emulate Audio device on port 0x1000 (Doesn´t support ARC)
1450         mNativeWrapper.setPortConnectionStatus(1, true);
1451         HdmiCecMessage reportPhysicalAddress =
1452                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1453                         ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1454         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1455         mTestLooper.dispatchAll();
1456 
1457         TestCallback callback = new TestCallback();
1458 
1459         mHdmiCecLocalDeviceTv.startArcAction(false, callback);
1460         mTestLooper.dispatchAll();
1461 
1462         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_INCORRECT_MODE);
1463     }
1464 
1465     @Test
startArcAction_termination_messageNotAcked()1466     public void startArcAction_termination_messageNotAcked() {
1467         // Emulate Audio device on port 0x2000 (Supports ARC)
1468         mNativeWrapper.setPortConnectionStatus(2, true);
1469         HdmiCecMessage reportPhysicalAddress =
1470                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1471                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1472         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1473         mTestLooper.dispatchAll();
1474 
1475         mNativeWrapper.setMessageSendResult(
1476                 Constants.MESSAGE_REQUEST_ARC_TERMINATION, SendMessageResult.NACK);
1477         mTestLooper.dispatchAll();
1478 
1479         TestCallback callback = new TestCallback();
1480 
1481         mHdmiCecLocalDeviceTv.startArcAction(false, callback);
1482         mTestLooper.dispatchAll();
1483 
1484         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1485                 ADDR_TV,
1486                 ADDR_AUDIO_SYSTEM);
1487         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
1488         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
1489     }
1490 
1491     @Test
startArcAction_termination_timeout()1492     public void startArcAction_termination_timeout() {
1493         // Emulate Audio device on port 0x2000 (Supports ARC)
1494         mNativeWrapper.setPortConnectionStatus(2, true);
1495         HdmiCecMessage reportPhysicalAddress =
1496                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1497                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1498         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1499         mTestLooper.dispatchAll();
1500 
1501         TestCallback callback = new TestCallback();
1502 
1503         mHdmiCecLocalDeviceTv.startArcAction(false, callback);
1504         mTestLooper.dispatchAll();
1505 
1506         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1507                 ADDR_TV,
1508                 ADDR_AUDIO_SYSTEM);
1509         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
1510         mTestLooper.moveTimeForward(TIMEOUT_MS);
1511         mTestLooper.dispatchAll();
1512         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TIMEOUT);
1513     }
1514 
1515     @Test
startArcAction_termination_featureAbort()1516     public void startArcAction_termination_featureAbort() {
1517         // Emulate Audio device on port 0x2000 (Supports ARC)
1518         mNativeWrapper.setPortConnectionStatus(2, true);
1519         HdmiCecMessage reportPhysicalAddress =
1520                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1521                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1522         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1523         mTestLooper.dispatchAll();
1524 
1525         TestCallback callback = new TestCallback();
1526 
1527         mHdmiCecLocalDeviceTv.startArcAction(false, callback);
1528         mTestLooper.dispatchAll();
1529 
1530         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1531                 ADDR_TV,
1532                 ADDR_AUDIO_SYSTEM);
1533         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
1534 
1535         HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
1536                 ADDR_AUDIO_SYSTEM,
1537                 ADDR_TV,
1538                 Constants.MESSAGE_REQUEST_ARC_TERMINATION,
1539                 Constants.ABORT_NOT_IN_CORRECT_MODE);
1540         mNativeWrapper.onCecMessage(featureAbort);
1541         mTestLooper.dispatchAll();
1542 
1543         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
1544     }
1545 
1546     @Test
startArcAction_termination_success()1547     public void startArcAction_termination_success() {
1548         // Emulate Audio device on port 0x2000 (Supports ARC)
1549         mNativeWrapper.setPortConnectionStatus(2, true);
1550         HdmiCecMessage reportPhysicalAddress =
1551                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1552                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1553         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1554         mTestLooper.dispatchAll();
1555 
1556         TestCallback callback = new TestCallback();
1557 
1558         mHdmiCecLocalDeviceTv.startArcAction(false, callback);
1559         mTestLooper.dispatchAll();
1560 
1561         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1562                 ADDR_TV,
1563                 ADDR_AUDIO_SYSTEM);
1564         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
1565 
1566         HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
1567                 ADDR_AUDIO_SYSTEM,
1568                 ADDR_TV);
1569         mNativeWrapper.onCecMessage(terminateArc);
1570         mTestLooper.dispatchAll();
1571 
1572         assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
1573     }
1574 
1575     @Test
enableEarc_terminateArc()1576     public void enableEarc_terminateArc() {
1577         // Emulate Audio device on port 0x2000 (supports ARC and eARC)
1578         mNativeWrapper.setPortConnectionStatus(2, true);
1579         HdmiCecMessage reportPhysicalAddress =
1580                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1581                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1582         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1583         mTestLooper.dispatchAll();
1584 
1585         initiateArcAndValidate();
1586 
1587         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1588         mTestLooper.dispatchAll();
1589 
1590         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1591                 ADDR_TV,
1592                 ADDR_AUDIO_SYSTEM);
1593 
1594         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
1595     }
1596 
1597     @Test
fromArcToEarc_SamRemainsOn()1598     public void fromArcToEarc_SamRemainsOn() {
1599         initateSamAndValidate();
1600 
1601         // Emulate Audio device on port 0x2000 (supports ARC and eARC)
1602         mNativeWrapper.setPortConnectionStatus(2, true);
1603         HdmiCecMessage reportPhysicalAddress =
1604                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1605                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1606         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1607         mTestLooper.dispatchAll();
1608 
1609         initiateArcAndValidate();
1610 
1611         assertThat(mHdmiControlService.isSystemAudioActivated()).isTrue();
1612 
1613         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1614         mTestLooper.dispatchAll();
1615 
1616         HdmiCecMessage requestArcTermination = HdmiCecMessageBuilder.buildRequestArcTermination(
1617                 ADDR_TV,
1618                 ADDR_AUDIO_SYSTEM);
1619 
1620         assertThat(mNativeWrapper.getResultMessages()).contains(requestArcTermination);
1621         assertThat(mHdmiControlService.isSystemAudioActivated()).isTrue();
1622     }
1623 
1624     @Test
disableEarc_SamRemainsOn()1625     public void disableEarc_SamRemainsOn() {
1626         initateSamAndValidate();
1627 
1628         // Emulate Audio device on port 0x2000 (supports ARC and eARC)
1629         mNativeWrapper.setPortConnectionStatus(2, true);
1630         HdmiCecMessage reportPhysicalAddress =
1631                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
1632                         ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1633         mNativeWrapper.onCecMessage(reportPhysicalAddress);
1634         mTestLooper.dispatchAll();
1635 
1636         mHdmiControlService.setEarcEnabled(HdmiControlManager.EARC_FEATURE_ENABLED);
1637         mTestLooper.dispatchAll();
1638         assertThat(mHdmiControlService.isSystemAudioActivated()).isTrue();
1639 
1640         mHdmiControlService.initializeEarcLocalDevice(HdmiControlService.INITIATED_BY_BOOT_UP);
1641         HdmiEarcLocalDevice mHdmiEarcLocalDeviceTx = mHdmiControlService.getEarcLocalDevice();
1642         mHdmiEarcLocalDeviceTx.handleEarcStateChange(Constants.HDMI_EARC_STATUS_EARC_CONNECTED);
1643         mTestLooper.moveTimeForward(HdmiEarcLocalDeviceTx.REPORT_CAPS_MAX_DELAY_MS + 1);
1644         mTestLooper.dispatchAll();
1645         verify(mAudioManager, times(1)).setWiredDeviceConnectionState(
1646                 any(), eq(1));
1647 
1648         assertThat(mHdmiControlService.isSystemAudioActivated()).isTrue();
1649 
1650     }
1651 }
1652