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 17 package android.hdmicec.cts.tv; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import android.hdmicec.cts.BaseHdmiCecCtsTest; 23 import android.hdmicec.cts.CecMessage; 24 import android.hdmicec.cts.CecOperand; 25 import android.hdmicec.cts.HdmiCecConstants; 26 import android.hdmicec.cts.LogicalAddress; 27 import android.hdmicec.cts.error.CecClientWrapperException; 28 import android.hdmicec.cts.error.ErrorCodes; 29 30 import com.android.tradefed.device.ITestDevice; 31 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 32 33 import org.junit.Before; 34 import org.junit.Rule; 35 import org.junit.Test; 36 import org.junit.rules.RuleChain; 37 import org.junit.runner.RunWith; 38 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.HashMap; 42 import java.util.List; 43 import java.util.concurrent.TimeUnit; 44 45 /** HDMI CEC test to check Remote Control Pass Through behaviour (Sections 11.1.13) */ 46 @RunWith(DeviceJUnit4ClassRunner.class) 47 public final class HdmiCecRemoteControlPassThroughTest extends BaseHdmiCecCtsTest { 48 49 private static final int WAIT_TIME_MS = 1000; 50 51 private HashMap<String, Integer> remoteControlKeys = new HashMap<String, Integer>(); 52 private HashMap<String, Integer> remoteControlAudioKeys = new HashMap<String, Integer>(); 53 54 @Rule 55 public RuleChain ruleChain = 56 RuleChain.outerRule(CecRules.requiresCec(this)) 57 .around(CecRules.requiresLeanback(this)) 58 .around(CecRules.requiresPhysicalDevice(this)) 59 .around(CecRules.requiresDeviceType(this, HdmiCecConstants.CEC_DEVICE_TYPE_TV)) 60 .around(hdmiCecClient); 61 HdmiCecRemoteControlPassThroughTest()62 public HdmiCecRemoteControlPassThroughTest() { 63 super(HdmiCecConstants.CEC_DEVICE_TYPE_TV, "-t", "r", "-t", "p", "-t", "t", "-t", "a"); 64 mapRemoteControlKeys(); 65 } 66 67 @Before checkForInitialActiveSourceMessage()68 public void checkForInitialActiveSourceMessage() throws CecClientWrapperException { 69 try { 70 /* 71 * Check for the broadcasted <ACTIVE_SOURCE> message from Recorder_1, which was sent as 72 * a response to <SET_STREAM_PATH> message from the TV. 73 */ 74 String message = 75 hdmiCecClient.checkExpectedMessageFromClient( 76 LogicalAddress.RECORDER_1, CecOperand.ACTIVE_SOURCE); 77 } catch (CecClientWrapperException e) { 78 if (e.getErrorCode() != ErrorCodes.CecMessageNotFound) { 79 throw e; 80 } else { 81 /* 82 * In case the TV does not send <Set Stream Path> to CEC adapter, or the client does 83 * not make recorder active source, broadcast an <Active Source> message from the 84 * adapter. 85 */ 86 hdmiCecClient.broadcastActiveSource( 87 LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress()); 88 try { 89 TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS); 90 } catch (InterruptedException ex) { 91 // Do nothing 92 } 93 } 94 } 95 } 96 97 /** 98 * Test 11.1.13-1 99 * 100 * <p>Tests that the DUT sends the appropriate messages for remote control pass through to a 101 * Recording Device. 102 */ 103 @Test cect_11_1_13_1_RemoteControlMessagesToRecorder()104 public void cect_11_1_13_1_RemoteControlMessagesToRecorder() throws Exception { 105 hdmiCecClient.broadcastActiveSource( 106 LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress()); 107 TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS); 108 validateKeyeventToUserControlPress(LogicalAddress.RECORDER_1, remoteControlKeys); 109 } 110 111 /** 112 * Test 11.1.13-2 113 * 114 * <p>Tests that the DUT sends the appropriate messages for remote control pass through to a 115 * Playback Device. 116 */ 117 @Test cect_11_1_13_2_RemoteControlMessagesToPlayback()118 public void cect_11_1_13_2_RemoteControlMessagesToPlayback() throws Exception { 119 hdmiCecClient.broadcastActiveSource( 120 LogicalAddress.PLAYBACK_1, hdmiCecClient.getPhysicalAddress()); 121 TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS); 122 validateKeyeventToUserControlPress(LogicalAddress.PLAYBACK_1, remoteControlKeys); 123 } 124 125 /** 126 * Test 11.1.13-3 127 * 128 * <p>Tests that the DUT sends the appropriate messages for remote control pass through to a 129 * Tuner Device. 130 */ 131 @Test cect_11_1_13_3_RemoteControlMessagesToTuner()132 public void cect_11_1_13_3_RemoteControlMessagesToTuner() throws Exception { 133 hdmiCecClient.broadcastActiveSource( 134 LogicalAddress.TUNER_1, hdmiCecClient.getPhysicalAddress()); 135 TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS); 136 validateKeyeventToUserControlPress(LogicalAddress.TUNER_1, remoteControlKeys); 137 } 138 139 /** 140 * Test 11.1.13-4 141 * 142 * <p>Tests that the DUT sends the appropriate messages for remote control pass through to an 143 * Audio System. 144 */ 145 @Test cect_11_1_13_4_RemoteControlMessagesToAudioSystem()146 public void cect_11_1_13_4_RemoteControlMessagesToAudioSystem() throws Exception { 147 hdmiCecClient.broadcastActiveSource( 148 LogicalAddress.AUDIO_SYSTEM, hdmiCecClient.getPhysicalAddress()); 149 TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS); 150 validateKeyeventToUserControlPress(LogicalAddress.AUDIO_SYSTEM, remoteControlAudioKeys); 151 } 152 153 /** 154 * Test 11.1.13-5 155 * 156 * <p>Tests that the DUT behaves sensibly when the remote control pass through feature is 157 * invoked in a system with multiple devices of the same type. 158 */ 159 @Test cect_11_1_13_5_RemoteControlPassthroughWithMultipleDevices()160 public void cect_11_1_13_5_RemoteControlPassthroughWithMultipleDevices() throws Exception { 161 hdmiCecClient.broadcastReportPhysicalAddress(LogicalAddress.RECORDER_1); 162 hdmiCecClient.broadcastReportPhysicalAddress(LogicalAddress.RECORDER_2, 0x2100); 163 validateMultipleKeyeventToUserControlPress( 164 LogicalAddress.RECORDER_1, LogicalAddress.RECORDER_2); 165 } 166 mapRemoteControlKeys()167 private void mapRemoteControlKeys() { 168 remoteControlKeys.put("DPAD_UP", HdmiCecConstants.CEC_KEYCODE_UP); 169 remoteControlKeys.put("DPAD_DOWN", HdmiCecConstants.CEC_KEYCODE_DOWN); 170 remoteControlKeys.put("DPAD_LEFT", HdmiCecConstants.CEC_KEYCODE_LEFT); 171 remoteControlKeys.put("DPAD_RIGHT", HdmiCecConstants.CEC_KEYCODE_RIGHT); 172 remoteControlAudioKeys.put("VOLUME_UP", HdmiCecConstants.CEC_KEYCODE_VOLUME_UP); 173 remoteControlAudioKeys.put("VOLUME_DOWN", HdmiCecConstants.CEC_KEYCODE_VOLUME_DOWN); 174 remoteControlAudioKeys.put("VOLUME_MUTE", HdmiCecConstants.CEC_KEYCODE_MUTE); 175 } 176 validateKeyeventToUserControlPress(LogicalAddress toDevice , HashMap<String, Integer> keyMaps)177 private void validateKeyeventToUserControlPress(LogicalAddress toDevice 178 , HashMap<String, Integer> keyMaps) throws Exception { 179 ITestDevice device = getDevice(); 180 for (String remoteKey : keyMaps.keySet()) { 181 device.executeShellCommand("input keyevent KEYCODE_" + remoteKey); 182 String message = 183 hdmiCecClient.checkExpectedOutput(toDevice, CecOperand.USER_CONTROL_PRESSED); 184 assertThat(CecMessage.getParams(message)).isEqualTo(keyMaps.get(remoteKey)); 185 hdmiCecClient.checkExpectedOutput(toDevice, CecOperand.USER_CONTROL_RELEASED); 186 } 187 } 188 validateMultipleKeyeventToUserControlPress( LogicalAddress device1, LogicalAddress device2)189 private void validateMultipleKeyeventToUserControlPress( 190 LogicalAddress device1, LogicalAddress device2) throws Exception { 191 ITestDevice device = getDevice(); 192 for (String remoteKey : remoteControlKeys.keySet()) { 193 List<LogicalAddress> destinationAddresses = new ArrayList<>(); 194 device.executeShellCommand("input keyevent KEYCODE_" + remoteKey); 195 destinationAddresses = 196 hdmiCecClient.getAllDestLogicalAddresses( 197 CecOperand.USER_CONTROL_PRESSED, 198 CecMessage.formatParams(remoteControlKeys.get(remoteKey)), 199 4); 200 assertWithMessage("UCP message forwarded to more than one device.") 201 .that(destinationAddresses.containsAll(Arrays.asList(device1, device2))) 202 .isFalse(); 203 assertWithMessage("UCP message was not forwarded to any of the device.") 204 .that(destinationAddresses) 205 .containsAnyIn(Arrays.asList(device1, device2)); 206 } 207 } 208 } 209