1 /*
2  * Copyright 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 
17 package android.hdmicec.cts.tv;
18 
19 import static com.google.common.truth.Truth.assertWithMessage;
20 
21 import android.hdmicec.cts.BaseHdmiCecCtsTest;
22 import android.hdmicec.cts.CecMessage;
23 import android.hdmicec.cts.CecOperand;
24 import android.hdmicec.cts.HdmiCecConstants;
25 import android.hdmicec.cts.HdmiControlManagerUtility;
26 import android.hdmicec.cts.LogicalAddress;
27 
28 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
29 
30 import org.junit.Rule;
31 import org.junit.Test;
32 import org.junit.rules.RuleChain;
33 import org.junit.runner.RunWith;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.concurrent.TimeUnit;
38 
39 /** HDMI CEC test to test One Touch Play features (Section 11.1.1) */
40 @RunWith(DeviceJUnit4ClassRunner.class)
41 public class HdmiCecTvOneTouchPlayTest extends BaseHdmiCecCtsTest {
42 
43     private static final int WAIT_TIME_MS = 1000;
44 
45     private static final int SLEEP_TIMESTEP_SECONDS = 1;
46     private static final int POWER_TRANSITION_WAIT_TIME = 10;
47     private static final int MAX_POWER_TRANSITION_WAIT_TIME = 15;
48 
49     List<LogicalAddress> testDevices = new ArrayList<>();
50 
HdmiCecTvOneTouchPlayTest()51     public HdmiCecTvOneTouchPlayTest() {
52         /* Start the client as recorder, tuner and playback devices */
53         super(HdmiCecConstants.CEC_DEVICE_TYPE_TV, "-t", "r", "-t", "t", "-t", "p");
54         testDevices.add(LogicalAddress.RECORDER_1);
55         testDevices.add(LogicalAddress.TUNER_1);
56         testDevices.add(LogicalAddress.PLAYBACK_1);
57     }
58 
59     @Rule
60     public RuleChain ruleChain =
61             RuleChain.outerRule(CecRules.requiresCec(this))
62                     .around(CecRules.requiresLeanback(this))
63                     .around(CecRules.requiresPhysicalDevice(this))
64                     .around(CecRules.requiresDeviceType(this, HdmiCecConstants.CEC_DEVICE_TYPE_TV))
65                     .around(hdmiCecClient);
66 
67     /**
68      * Test 11.1.1-1
69      *
70      * <p>Tests that the DUT responds to {@code <Image View On>} message correctly when the message
71      * is sent from logical addresses 0x1, 0x3 and 0x4
72      */
73     @Test
cect_11_1_1_1_RespondToImageViewOn()74     public void cect_11_1_1_1_RespondToImageViewOn() throws Exception {
75         for (LogicalAddress testDevice : testDevices) {
76             hdmiCecClient.sendCecMessage(testDevice, LogicalAddress.TV, CecOperand.IMAGE_VIEW_ON);
77             TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
78             hdmiCecClient.broadcastActiveSource(testDevice, hdmiCecClient.getPhysicalAddress());
79             hdmiCecClient.checkOutputDoesNotContainMessage(testDevice, CecOperand.FEATURE_ABORT);
80             assertWithMessage(
81                             "Device has not registered expected logical address as active source.")
82                     .that(getDumpsysActiveSourceLogicalAddress())
83                     .isEqualTo(testDevice);
84         }
85     }
86 
87     /**
88      * Test 11.1.1-2
89      *
90      * <p>Tests that the DUT responds to {@code <Text View On>} message correctly when the message
91      * is sent from logical addresses 0x1, 0x3 and 0x4
92      */
93     @Test
cect_11_1_1_2_RespondToTextViewOn()94     public void cect_11_1_1_2_RespondToTextViewOn() throws Exception {
95         for (LogicalAddress testDevice : testDevices) {
96             hdmiCecClient.sendCecMessage(testDevice, LogicalAddress.TV, CecOperand.TEXT_VIEW_ON);
97             TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
98             hdmiCecClient.broadcastActiveSource(testDevice, hdmiCecClient.getPhysicalAddress());
99             hdmiCecClient.checkOutputDoesNotContainMessage(testDevice, CecOperand.FEATURE_ABORT);
100             assertWithMessage(
101                             "Device has not registered expected logical address as active source.")
102                     .that(getDumpsysActiveSourceLogicalAddress())
103                     .isEqualTo(testDevice);
104         }
105     }
106 
107     /**
108      * Test 11.1.1-5
109      *
110      * <p>Tests that the DUT broadcasts an {@code <Active Source>} message when changing to an
111      * internal source from previously displaying an external source.
112      */
113     @Test
cect_11_1_1_5_DutBroadcastsActiveSourceWhenChangingToInternal()114     public void cect_11_1_1_5_DutBroadcastsActiveSourceWhenChangingToInternal() throws Exception {
115         // Ensure that an external source is the active source.
116         try {
117             /*
118              * Check for the broadcasted <ACTIVE_SOURCE> message from Recorder_1, which was sent as
119              * a response to <SET_STREAM_PATH> message from the TV.
120              */
121             String message =
122                     hdmiCecClient.checkExpectedMessageFromClient(
123                             LogicalAddress.RECORDER_1, CecOperand.ACTIVE_SOURCE);
124         } catch (Exception e) {
125             /*
126              * In case the TV does not send <Set Stream Path> to CEC adapter, or the client does
127              * not make recorder active source, broadcast an <Active Source> message from the
128              * adapter.
129              */
130             hdmiCecClient.broadcastActiveSource(
131                     LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
132             TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
133         }
134         // Make the TV device the active source.
135         HdmiControlManagerUtility.selectDevice(this, getDevice(), LogicalAddress.TV.toString());
136         hdmiCecClient.checkExpectedOutput(LogicalAddress.BROADCAST, CecOperand.ACTIVE_SOURCE);
137     }
138 
139     /**
140      * Test 11.1.1-3
141      *
142      * <p>Tests that the DUT powers on in response to an {@code <Image View On>} message when in
143      * standby
144      */
145     @Test
cect_11_1_1_3_ImageViewOnWhenInStandby()146     public void cect_11_1_1_3_ImageViewOnWhenInStandby() throws Exception {
147         try {
148             getDevice().reboot();
149             sendDeviceToSleep();
150             assertDevicePowerStatus(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
151             /* Get the first device the client has started as */
152             LogicalAddress testDevice = testDevices.get(0);
153             hdmiCecClient.sendCecMessage(testDevice, LogicalAddress.TV, CecOperand.IMAGE_VIEW_ON);
154             assertDevicePowerStatus(HdmiCecConstants.CEC_POWER_STATUS_ON);
155         } finally {
156             wakeUpDevice();
157         }
158     }
159 
160     /**
161      * Test 11.1.1-4
162      *
163      * <p>Tests that the DUT powers on in response to an {@code <Text View On>} message when in
164      * standby
165      */
166     @Test
cect_11_1_1_4_TextViewOnWhenInStandby()167     public void cect_11_1_1_4_TextViewOnWhenInStandby() throws Exception {
168         try {
169             getDevice().reboot();
170             sendDeviceToSleep();
171             assertDevicePowerStatus(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
172             /* Get the first device the client has started as */
173             LogicalAddress testDevice = testDevices.get(0);
174             hdmiCecClient.sendCecMessage(testDevice, LogicalAddress.TV, CecOperand.TEXT_VIEW_ON);
175             assertDevicePowerStatus(HdmiCecConstants.CEC_POWER_STATUS_ON);
176         } finally {
177             wakeUpDevice();
178         }
179     }
180 
assertDevicePowerStatus(int powerStatus)181     private void assertDevicePowerStatus(int powerStatus) throws Exception {
182         String[] powerStatusNames = {"ON", "OFF", "IN_TRANSITION_TO_ON", "IN_TRANSITION_TO_OFF"};
183         LogicalAddress cecClientDevice = hdmiCecClient.getSelfDevice();
184         int actualPowerStatus;
185         int waitTimeSeconds = POWER_TRANSITION_WAIT_TIME;
186 
187         /* Wait for the device to transition */
188         TimeUnit.SECONDS.sleep(waitTimeSeconds);
189 
190         do {
191             TimeUnit.SECONDS.sleep(SLEEP_TIMESTEP_SECONDS);
192             waitTimeSeconds += SLEEP_TIMESTEP_SECONDS;
193             hdmiCecClient.sendCecMessage(cecClientDevice, CecOperand.GIVE_POWER_STATUS);
194             actualPowerStatus =
195                     CecMessage.getParams(
196                             hdmiCecClient.checkExpectedOutput(
197                                     cecClientDevice, CecOperand.REPORT_POWER_STATUS));
198             /* Compare with (powerStatus + 2) to check if it is transitioning to the expected power
199              * status.
200              */
201         } while (actualPowerStatus == (powerStatus + 2)
202                 && waitTimeSeconds <= MAX_POWER_TRANSITION_WAIT_TIME);
203         assertWithMessage(
204                         "Device power status is "
205                                 + powerStatusNames[actualPowerStatus]
206                                 + " but expected to be "
207                                 + powerStatusNames[powerStatus])
208                 .that(actualPowerStatus)
209                 .isEqualTo(powerStatus);
210     }
211 }
212