diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2020-08-05 18:33:59 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-08-05 18:33:59 +0000 |
commit | bdfcae86ab29c4facb7d074674320e02383b385f (patch) | |
tree | 3688b8f06dbf961901b7e55c4310f54d27008eaa | |
parent | 4900a6dfee56818938b875be0e3fb76199dcac4d (diff) | |
parent | a87e239055a3b8a33122cf2ace4949c9b2f86c91 (diff) | |
download | cts-bdfcae86ab29c4facb7d074674320e02383b385f.tar.gz |
Merge "Update HDMI CEC CTS tests" into stage-aosp-rvc-ts-dev
35 files changed, 2691 insertions, 564 deletions
diff --git a/hostsidetests/hdmicec/Android.bp b/hostsidetests/hdmicec/Android.bp index 66d0e0a3de4..4268ff190cb 100644 --- a/hostsidetests/hdmicec/Android.bp +++ b/hostsidetests/hdmicec/Android.bp @@ -28,6 +28,6 @@ java_test_host { "compatibility-host-util", ], data: [ - ":HdmiCecKeyEventCaptureApp", + ":HdmiCecHelperApp", ], } diff --git a/hostsidetests/hdmicec/AndroidTest.xml b/hostsidetests/hdmicec/AndroidTest.xml index f4f5281efeb..a0a4350a663 100644 --- a/hostsidetests/hdmicec/AndroidTest.xml +++ b/hostsidetests/hdmicec/AndroidTest.xml @@ -22,7 +22,7 @@ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" /> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> - <option name="test-file-name" value="HdmiCecKeyEventCaptureApp.apk" /> + <option name="test-file-name" value="HdmiCecHelperApp.apk" /> </target_preparer> <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > <option name="jar" value="CtsHdmiCecHostTestCases.jar" /> diff --git a/hostsidetests/hdmicec/README.md b/hostsidetests/hdmicec/README.md new file mode 100644 index 00000000000..3d5b003b449 --- /dev/null +++ b/hostsidetests/hdmicec/README.md @@ -0,0 +1,28 @@ +# CEC CTS testing for Android TV devices + +NOTE: CTS has two meanings here. HDMI defines a set of tests in **Compliance +Test Specification** in HDMI 1.4b *HDMI Compliance Test Specification 1.4b and +**Android Compatibility Test Suite**. + +Android Compatibility Test Suite include specific tests from HDMI Compliance +Test Specification and other Android specific tests. + +## Setup + +### Playback devices (aka Set Top Boxes) + +Running these CTS tests requires a specific HDMI layout with a CEC adapter. + +* Android TV playback device +* CEC adapter see [External CEC Adapter instructions](cec_adapter.md) +* HDMI Display (aka a TV) + +![drawing](setup.png) + +### Automation + +Given the setup described above you can run all of these tests with the command + +``` +atest CtsHdmiCecHostTestCases +``` diff --git a/hostsidetests/hdmicec/app/Android.bp b/hostsidetests/hdmicec/app/Android.bp index 910aa306f0e..ed41e1a6b64 100644 --- a/hostsidetests/hdmicec/app/Android.bp +++ b/hostsidetests/hdmicec/app/Android.bp @@ -13,8 +13,13 @@ // limitations under the License. android_test_helper_app { - name: "HdmiCecKeyEventCaptureApp", + name: "HdmiCecHelperApp", defaults: ["cts_defaults"], srcs: ["src/**/*.java"], - sdk_version: "current", + static_libs: [ + "services.core", + "guava", + "androidx.test.runner", + ], + min_sdk_version: "28", } diff --git a/hostsidetests/hdmicec/app/AndroidManifest.xml b/hostsidetests/hdmicec/app/AndroidManifest.xml index ce9fff74743..603445e6ae3 100644 --- a/hostsidetests/hdmicec/app/AndroidManifest.xml +++ b/hostsidetests/hdmicec/app/AndroidManifest.xml @@ -16,16 +16,30 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="android.hdmicec.app"> + package="android.hdmicec.app"> <uses-feature android:name="android.software.leanback" - android:required="false" /> - <application > - <activity android:name=".HdmiCecKeyEventCapture" > + android:required="false"/> + <application> + <activity android:name=".HdmiCecKeyEventCapture" + android:exported="true"> <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LEANBACK_LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name=".HdmiCecAudioManager" + android:exported="true"> + <intent-filter> + <action android:name="android.hdmicec.app.MUTE"/> + <action android:name="android.hdmicec.app.UNMUTE"/> + <action android:name="android.hdmicec.app.REPORT_VOLUME"/> + <action android:name="android.hdmicec.app.SET_VOLUME"/> + <action android:name="android.hdmicec.app.GET_SUPPORTED_SAD_FORMATS"/> + <category android:name="android.intent.category.LEANBACK_LAUNCHER"/> </intent-filter> </activity> </application> + <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" /> + </manifest> diff --git a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecAudioManager.java b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecAudioManager.java new file mode 100644 index 00000000000..f04490fc68a --- /dev/null +++ b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiCecAudioManager.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.app; + +import android.app.Activity; +import android.content.Context; +import android.media.AudioManager; +import android.os.Bundle; +import android.util.Log; + +import com.android.server.hdmi.SadConfigurationReaderTest; + +import org.junit.runner.JUnitCore; + +/** + * A simple app that can be used to mute, unmute, set volume or get the volume status of a device. + * The actions supported are: + * + * 1. android.hdmicec.app.MUTE: Mutes the STREAM_MUSIC of the device, + * irrespective of the previous state. + * Usage: START_COMMAND -a android.hdmicec.app.MUTE + * 2. android.hdmicec.app.UNMUTE: Unmutes the STREAM_MUSIC of the device, + * irrespective of the previous state. + * Usage: START_COMMAND -a android.hdmicec.app.UNMUTE + * 3. android.hdmicec.app.REPORT_VOLUME: Reports if the STREAM_MUSIC of the device is muted and + * if not muted, the current volume level in percent. + * Usage: START_COMMAND -a android.hdmicec.app.REPORT_VOLUME + * 4. android.hdmicec.app.SET_VOLUME: Sets the volume of STREAM_MUSIC to a particular level. + * Has to be used with --ei "volumePercent" x. + * Usage: START_COMMAND -a android.hdmicec.app.SET_VOLUME --ei "volumePercent" x + * + * where START_COMMAND is + * adb shell am start -n "android.hdmicec.app/android.hdmicec.app.HdmiCecAudioManager" + */ +public class HdmiCecAudioManager extends Activity { + + private static final String TAG = HdmiCecAudioManager.class.getSimpleName(); + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + + switch(getIntent().getAction()) { + case "android.hdmicec.app.MUTE": + audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, + AudioManager.ADJUST_MUTE, 0); + break; + case "android.hdmicec.app.UNMUTE": + audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, + AudioManager.ADJUST_UNMUTE, 0); + break; + case "android.hdmicec.app.REPORT_VOLUME": + if (audioManager.isStreamMute(AudioManager.STREAM_MUSIC)) { + Log.i(TAG, "Device muted."); + } else { + int minVolume = audioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC); + int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int volume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); + int percentVolume = 100 * volume / (maxVolume - minVolume); + Log.i(TAG, "Volume at " + percentVolume + "%"); + } + break; + case "android.hdmicec.app.SET_VOLUME": + int percentVolume = getIntent().getIntExtra("volumePercent", 50); + int minVolume = audioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC); + int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + int volume = minVolume + ((maxVolume - minVolume) * percentVolume / 100); + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0); + Log.i(TAG, "Set volume to " + volume + " (" + percentVolume + "%)"); + break; + case "android.hdmicec.app.GET_SUPPORTED_SAD_FORMATS": + JUnitCore junit = new JUnitCore(); + junit.run(SadConfigurationReaderTest.class); + break; + default: + Log.w(TAG, "Unknown intent!"); + } + finishAndRemoveTask(); + } +} + diff --git a/hostsidetests/hdmicec/app/src/com/android/server/hdmi/SadConfigurationReaderTest.java b/hostsidetests/hdmicec/app/src/com/android/server/hdmi/SadConfigurationReaderTest.java new file mode 100644 index 00000000000..48665acfeac --- /dev/null +++ b/hostsidetests/hdmicec/app/src/com/android/server/hdmi/SadConfigurationReaderTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import android.util.Log; + +import com.android.server.hdmi.HdmiUtils.CodecSad; +import com.android.server.hdmi.HdmiUtils.DeviceConfig; +import com.google.common.hash.HashCode; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +@RunWith(JUnit4.class) +/** + * Reads short audio descriptors from a configuration file and outputs to a log + * for use by host side tests. + */ +public class SadConfigurationReaderTest { + + private static final String TAG = "SadConfigurationReaderTest"; + + // Variable should be copy of SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH in + // frameworks/base/services/core/java/com/android/server/hdmi/ + // HdmiCecLocalDeviceAudioSystem.java + private final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml"; + + @Test + public void parseSadConfigXML() { + List<DeviceConfig> deviceConfigs = null; + File file = new File(SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH); + if (file.exists()) { + try { + InputStream in = new FileInputStream(file); + deviceConfigs = HdmiUtils.ShortAudioDescriptorXmlParser.parse(in); + in.close(); + } catch (IOException e) { + Log.e(TAG, "Error reading file: " + file.getAbsolutePath(), e); + } catch (XmlPullParserException e) { + Log.e(TAG, "Unable to parse file: " + file.getAbsolutePath(), e); + } + } else { + Log.e(TAG, "No config file present at " + file.getAbsolutePath()); + return; + } + DeviceConfig deviceConfigToUse = null; + if (deviceConfigs != null && deviceConfigs.size() > 0) { + for (DeviceConfig deviceConfig : deviceConfigs) { + if (deviceConfig.name.equals("VX_AUDIO_DEVICE_IN_HDMI_ARC")) { + deviceConfigToUse = deviceConfig; + break; + } + } + if (deviceConfigToUse == null) { + Log.w(TAG, "sadConfig.xml does not have required device info for " + + "VX_AUDIO_DEVICE_IN_HDMI_ARC"); + return; + } + List<Integer> audioCodecFormats = new ArrayList<>(); + List<String> shortAudioDescriptors = new ArrayList<>(); + for (CodecSad codecSad : deviceConfigToUse.supportedCodecs) { + audioCodecFormats.add(codecSad.audioCodec); + shortAudioDescriptors.add(HashCode.fromBytes(codecSad.sad).toString()); + } + String audioCodecFormatsString = audioCodecFormats.toString(); + String shortAudioDescriptorsString = shortAudioDescriptors.toString(); + Log.i(TAG, "Supported Audio Formats"); + Log.i(TAG, audioCodecFormatsString.substring(1, audioCodecFormatsString.length() - 1)); + Log.i(TAG, shortAudioDescriptorsString + .substring(1, shortAudioDescriptorsString.length() - 1)); + } + } +} diff --git a/hostsidetests/hdmicec/cec_adapter.md b/hostsidetests/hdmicec/cec_adapter.md new file mode 100644 index 00000000000..3a325d7e325 --- /dev/null +++ b/hostsidetests/hdmicec/cec_adapter.md @@ -0,0 +1,221 @@ +# External CEC adapter + +## USB - CEC Adapter from Pulse-Eight + +![Picture of USB - CEC Adapter](https://www.pulse-eight.com/generated-assets/products/0000237_555.jpeg) + +## Get the hardware + +* [Order from Pulse-Eight](https://www.pulse-eight.com/p/104/usb-hdmi-cec-adapter#) +* [Pulse-Eight USB CEC adapter on Amazon](https://www.amazon.com/s/ref=nb_sb_ss_i_1_22?url=search-alias%3Daps&field-keywords=pulse+eight+usb+cec+adapter&sprefix=usb+cec+adapter+pulse+%2Caps%2C218&crid=UK4LY390M5H2) + +## Get the software {#software} + +1. Connect "TV" port on the adapter to your TV +2. Connect USB mini port to you computer +3. Install the cec-client + + * Linux + + ```shell + sudo apt-get install cec-utils + ``` + + * mac (using [MacPorts](https://guide.macports.org/#installing)) + + ```shell + sudo /opt/local/bin/port install libcec + ``` + +4. run the client + + ```shell + $ cec-client + No device type given. Using 'recording device' + CEC Parser created - libCEC version 4.0.2 + no serial port given. trying autodetect: + path: /dev/cu.usbmodemv1 + com port: /dev/cu.usbmodemv1 + + opening a connection to the CEC adapter... + DEBUG: [ 1] Broadcast (F): osd name set to 'Broadcast' + DEBUG: [ 3] connection opened, clearing any previous input and waiting for active transmissions to end before starting + DEBUG: [ 10] communication thread started + DEBUG: [ 70] turning controlled mode on + NOTICE: [ 255] connection opened + DEBUG: [ 255] processor thread started + DEBUG: [ 255] << Broadcast (F) -> TV (0): POLL + TRAFFIC: [ 255] << f0 + DEBUG: [ 255] setting the line timeout to 3 + DEBUG: [ 403] >> POLL sent + DEBUG: [ 403] TV (0): device status changed into 'present' + ``` + +## Add timestamps + +Use the `ts` command to add timestamps. + +```shell +$ cec-client | ts +Nov 18 16:15:46 No device type given. Using 'recording device' +Nov 18 16:15:46 CEC Parser created - libCEC version 4.0.4 +Nov 18 16:15:46 no serial port given. trying autodetect: +Nov 18 16:15:46 path: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-9 +Nov 18 16:15:46 com port: /dev/ttyACM0 +Nov 18 16:15:46 +Nov 18 16:15:46 opening a connection to the CEC adapter... +Nov 18 16:15:46 DEBUG: [ 386] Broadcast (F): osd name set to 'Broadcast' +``` + +### ts is part of the moreutils package + +```shell +sudo apt-get install moreutils +``` + +## cheat sheets + +* Show all connected devices + + ```shell + $ echo scan | cec-client -s -d 1 + + ``` + +## Available Commands + +[tx] \{bytes\} +: transfer bytes over the CEC line. + +[txn] \{bytes\} +: transfer bytes but don't wait for transmission ACK. + +[on] \{address\} +: power on the device with the given logical address. + +[standby] \{address\} +: put the device with the given address in standby mode. + +[la] \{logical address\} +: change the logical address of the CEC adapter. + +[p] \{device\} \{port\} +: change the HDMI port number of the CEC adapter. + +[pa] \{physical address\} +: change the physical address of the CEC adapter. + +[as] +: make the CEC adapter the active source. + +[is] +: mark the CEC adapter as inactive source. + +[osd] \{addr\} \{string\} +: set OSD message on the specified device. + +[ver] \{addr\} +: get the CEC version of the specified device. + +[ven] \{addr\} +: get the vendor ID of the specified device. + +[lang] \{addr\} +: get the menu language of the specified device. + +[pow] \{addr\} +: get the power status of the specified device. + +[name] \{addr\} +: get the OSD name of the specified device. + +[poll] \{addr\} +: poll the specified device. + +[lad] +: lists active devices on the bus + +[ad] \{addr\} +: checks whether the specified device is active. + +[at] \{type\} +: checks whether the specified device type is active. + +[sp] \{addr\} +: makes the specified physical address active. + +[spl] \{addr\} +: makes the specified logical address active. + +[volup] +: send a volume up command to the amp if present + +[voldown] +: send a volume down command to the amp if present + +[mute] +: send a mute/unmute command to the amp if present + +[self] +: show the list of addresses controlled by libCEC + +[scan] +: scan the CEC bus and display device info + +## Sending Remote Control Events + +You can send CEC remote events using the `tx` command above. The format is as +follows: + +``` +tx <source id><destination id>:<command id>:<param value> +``` + +where all of the above parameters should be filled in with a single HEX digit +(except `<command id>`, which requires 2 digits). Here, we want to send commands +to the Android TV, so we will place its ID in `<destination id>`. The scan +command above will give you the IDs for each device that the CEC adapter is +aware of. + +In the examples below the DUT is a CEC player device with a logical address of +4. Here are some useful commands to execute remote actions: + +* Press home + + ``` + tx 04:44:09 + ``` + +* Press select + + ``` + tx 04:44:00 + ``` + +* Press d-pad up + + ``` + tx 04:44:01 + ``` + +* Press d-pad down + + ``` + tx 04:44:02 + ``` + +* Press d-pad left + + ``` + tx 04:44:03 + ``` + +* Press d-pad right + + ``` + tx 04:44:04 + ``` + +You can check out [https://www.cec-o-matic.com/](https]://www.cec-o-matic.com/) +for more info on formatting your request and a full list of commands and their +respective parameters. diff --git a/hostsidetests/hdmicec/setup.png b/hostsidetests/hdmicec/setup.png Binary files differnew file mode 100644 index 00000000000..e89417e46f9 --- /dev/null +++ b/hostsidetests/hdmicec/setup.png diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java index 8d4ece13ef0..bce34e1d461 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,56 +16,36 @@ package android.hdmicec.cts; -import java.util.HashMap; -import java.util.Map; - -public enum CecMessage { - FEATURE_ABORT(0x00), - TEXT_VIEW_ON(0x0d), - SET_MENU_LANGUAGE(0x32), - STANDBY(0x36), - USER_CONTROL_PRESSED(0x44), - USER_CONTROL_RELEASED(0x45), - GIVE_OSD_NAME(0x46), - SET_OSD_NAME(0x47), - SYSTEM_AUDIO_MODE_REQUEST(0x70), - SET_SYSTEM_AUDIO_MODE(0x72), - GIVE_SYSTEM_AUDIO_MODE_STATUS(0x7d), - ACTIVE_SOURCE(0x82), - GIVE_PHYSICAL_ADDRESS(0x83), - REPORT_PHYSICAL_ADDRESS(0x84), - REQUEST_ACTIVE_SOURCE(0x85), - SET_STREAM_PATH(0x86), - DEVICE_VENDOR_ID(0x87), - GIVE_DEVICE_VENDOR_ID(0x8c), - GIVE_POWER_STATUS(0x8f), - REPORT_POWER_STATUS(0x90), - GET_MENU_LANGUAGE(0x91), - INACTIVE_SOURCE(0x9d), - CEC_VERSION(0x9e), - GET_CEC_VERSION(0x9f), - ABORT(0xff); - - private final int messageId; - private static Map messageMap = new HashMap<>(); - - static { - for (CecMessage message : CecMessage.values()) { - messageMap.put(message.messageId, message); +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CecMessage { + + private static final int HEXADECIMAL_RADIX = 16; + + /** Gets the hexadecimal ASCII character values of a string. */ + public static String getHexAsciiString(String string) { + String asciiString = ""; + byte[] ascii = string.trim().getBytes(); + + for (byte b : ascii) { + asciiString.concat(Integer.toHexString(b)); } - } - public static CecMessage getMessage(int messageId) { - return (CecMessage) messageMap.get(messageId); + return asciiString; } - @Override - public String toString() { - return String.format("%02x", messageId); - } + public static String formatParams(String rawParams) { + StringBuilder params = new StringBuilder(""); + int position = 0; + int endPosition = 2; - private CecMessage(int messageId) { - this.messageId = messageId; + do { + params.append(":" + rawParams.substring(position, endPosition)); + position = endPosition; + endPosition += 2; + } while (endPosition <= rawParams.length()); + return params.toString(); } public static String formatParams(long rawParam) { @@ -78,4 +58,110 @@ public enum CecMessage { return params.toString(); } + + /** + * Formats the rawParam into CEC message parameters. The parameters will be at least + * minimumNibbles long. + */ + public static String formatParams(long rawParam, int minimumNibbles) { + StringBuilder params = new StringBuilder(""); + + do { + params.insert(0, ":" + String.format("%02x", rawParam % 256)); + rawParam >>= 8; + minimumNibbles -= 2; + } while (rawParam > 0 || minimumNibbles > 0); + + return params.toString(); + } + + public static int hexStringToInt(String message) { + return Integer.parseInt(message, HEXADECIMAL_RADIX); + } + + public static String getAsciiString(String message) { + String params = getNibbles(message).substring(4); + StringBuilder builder = new StringBuilder(); + + for (int i = 2; i <= params.length(); i += 2) { + builder.append((char) hexStringToInt(params.substring(i - 2, i))); + } + + return builder.toString(); + } + + public static String getParamsAsString(String message) { + return getNibbles(message).substring(4); + } + + /** Gets the params from a CEC message. */ + public static int getParams(String message) { + return hexStringToInt(getNibbles(message).substring(4)); + } + + /** Gets the first 'numNibbles' number of param nibbles from a CEC message. */ + public static int getParams(String message, int numNibbles) { + int paramStart = 4; + int end = numNibbles + paramStart; + return hexStringToInt(getNibbles(message).substring(paramStart, end)); + } + + /** + * From the params of a CEC message, gets the nibbles from position start to position end. + * The start and end are relative to the beginning of the params. For example, in the following + * message - 4F:82:10:00:04, getParamsFromMessage(message, 0, 4) will return 0x1000 and + * getParamsFromMessage(message, 4, 6) will return 0x04. + */ + public static int getParams(String message, int start, int end) { + return hexStringToInt(getNibbles(message).substring(4).substring(start, end)); + } + + /** + * Gets the source logical address from a CEC message. + */ + public static LogicalAddress getSource(String message) { + String param = getNibbles(message).substring(0, 1); + return LogicalAddress.getLogicalAddress(hexStringToInt(param)); + } + + /** Gets the destination logical address from a CEC message. */ + public static LogicalAddress getDestination(String message) { + String param = getNibbles(message).substring(1, 2); + return LogicalAddress.getLogicalAddress(hexStringToInt(param)); + } + + /** Gets the operand from a CEC message. */ + public static CecOperand getOperand(String message) { + String param = getNibbles(message).substring(2, 4); + return CecOperand.getOperand(hexStringToInt(param)); + } + + /** + * Converts ascii characters to hexadecimal numbers that can be appended to a CEC message as + * params. For example, "spa" will be converted to ":73:70:61" + */ + public static String convertStringToHexParams(String rawParams) { + StringBuilder params = new StringBuilder(""); + for (int i = 0; i < rawParams.length(); i++) { + params.append(String.format(":%02x", (int) rawParams.charAt(i))); + } + return params.toString(); + } + + private static String getNibbles(String message) { + final String tag1 = "group1"; + final String tag2 = "group2"; + String paramsPattern = "(?:.*[>>|<<].*?)" + + "(?<" + tag1 + ">[\\p{XDigit}{2}:]+)" + + "(?<" + tag2 + ">\\p{XDigit}{2})" + + "(?:.*?)"; + String nibbles = ""; + + Pattern p = Pattern.compile(paramsPattern); + Matcher m = p.matcher(message); + if (m.matches()) { + nibbles = m.group(tag1).replace(":", "") + m.group(tag2); + } + return nibbles; + } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java new file mode 100644 index 00000000000..5aa547ee4a1 --- /dev/null +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecOperand.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.cts; + +import java.util.HashMap; +import java.util.Map; + +public enum CecOperand { + FEATURE_ABORT(0x00), + TEXT_VIEW_ON(0x0d), + SET_MENU_LANGUAGE(0x32), + STANDBY(0x36), + USER_CONTROL_PRESSED(0x44), + USER_CONTROL_RELEASED(0x45), + GIVE_OSD_NAME(0x46), + SET_OSD_NAME(0x47), + SYSTEM_AUDIO_MODE_REQUEST(0x70), + GIVE_AUDIO_STATUS(0x71), + SET_SYSTEM_AUDIO_MODE(0x72), + REPORT_AUDIO_STATUS(0x7a), + GIVE_SYSTEM_AUDIO_MODE_STATUS(0x7d), + SYSTEM_AUDIO_MODE_STATUS(0x7e), + ACTIVE_SOURCE(0x82), + GIVE_PHYSICAL_ADDRESS(0x83), + REPORT_PHYSICAL_ADDRESS(0x84), + REQUEST_ACTIVE_SOURCE(0x85), + SET_STREAM_PATH(0x86), + DEVICE_VENDOR_ID(0x87), + VENDOR_COMMAND(0x89), + GIVE_DEVICE_VENDOR_ID(0x8c), + GIVE_POWER_STATUS(0x8f), + REPORT_POWER_STATUS(0x90), + GET_MENU_LANGUAGE(0x91), + INACTIVE_SOURCE(0x9d), + CEC_VERSION(0x9e), + GET_CEC_VERSION(0x9f), + REPORT_SHORT_AUDIO_DESCRIPTOR(0xa3), + REQUEST_SHORT_AUDIO_DESCRIPTOR(0xa4), + INITIATE_ARC(0xc0), + ARC_INITIATED(0xc1), + REQUEST_ARC_INITIATION(0xc3), + REQUEST_ARC_TERMINATION(0xc4), + TERMINATE_ARC(0xc5), + ABORT(0xff); + + private final int operandCode; + private static Map operandMap = new HashMap<>(); + + static { + for (CecOperand operand : CecOperand.values()) { + operandMap.put(operand.operandCode, operand); + } + } + + public static CecOperand getOperand(int messageId) { + return (CecOperand) operandMap.get(messageId); + } + + @Override + public String toString() { + return String.format("%02x", operandCode); + } + + private CecOperand(int operandCode) { + this.operandCode = operandCode; + } +} diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java index f9b1899cb11..51da28007ea 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java @@ -16,10 +16,6 @@ package android.hdmicec.cts; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assume.assumeTrue; - -import com.android.tradefed.device.ITestDevice; import com.android.tradefed.log.LogUtil.CLog; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import com.android.tradefed.util.RunUtil; @@ -32,10 +28,8 @@ import java.util.concurrent.TimeUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.junit.Rule; import org.junit.rules.ExternalResource; /** Class that helps communicate with the cec-client */ @@ -44,8 +38,6 @@ public final class HdmiCecClientWrapper extends ExternalResource { private static final String CEC_CONSOLE_READY = "waiting for input"; private static final int MILLISECONDS_TO_READY = 10000; private static final int DEFAULT_TIMEOUT = 20000; - private static final String HDMI_CEC_FEATURE = "feature:android.hardware.hdmi.cec"; - private static final int HEXADECIMAL_RADIX = 16; private static final int BUFFER_SIZE = 1024; private Process mCecClient; @@ -53,29 +45,16 @@ public final class HdmiCecClientWrapper extends ExternalResource { private BufferedReader mInputConsole; private boolean mCecClientInitialised = false; - private CecDevice targetDevice; - private BaseHostJUnit4Test testObject; + private LogicalAddress targetDevice; private String clientParams[]; - public HdmiCecClientWrapper(CecDevice targetDevice, BaseHostJUnit4Test testObject, - String ...clientParams) { + public HdmiCecClientWrapper(LogicalAddress targetDevice, String ...clientParams) { this.targetDevice = targetDevice; - this.testObject = testObject; this.clientParams = clientParams; } @Override protected void before() throws Throwable { - ITestDevice testDevice; - testDevice = testObject.getDevice(); - assertNotNull("Device not set", testDevice); - - assumeTrue(isHdmiCecFeatureSupported(testDevice)); - - String deviceTypeCsv = testDevice.executeShellCommand("getprop ro.hdmi.device_type").trim(); - List<String> deviceType = Arrays.asList(deviceTypeCsv.replaceAll("\\s+", "").split(",")); - assumeTrue(deviceType.contains(CecDevice.getDeviceType(targetDevice))); - this.init(); }; @@ -84,24 +63,18 @@ public final class HdmiCecClientWrapper extends ExternalResource { this.killCecProcess(); }; - /** - * Checks if the HDMI CEC feature is running on the device. Call this function before running - * any HDMI CEC tests. - * This could throw a DeviceNotAvailableException. - */ - private static boolean isHdmiCecFeatureSupported(ITestDevice device) throws Exception { - return device.hasFeature(HDMI_CEC_FEATURE); - } - /** Initialise the client */ private void init() throws Exception { - boolean gotExpectedOut = false; List<String> commands = new ArrayList(); - int seconds = 0; commands.add("cec-client"); + /* "-p 2" starts the client as if it is connected to HDMI port 2, taking the physical + * address 2.0.0.0 */ commands.add("-p"); commands.add("2"); + /* "-t x" starts the client as a TV device */ + commands.add("-t"); + commands.add("x"); commands.addAll(Arrays.asList(clientParams)); mCecClient = RunUtil.getDefault().runCmdInBackground(commands); @@ -133,15 +106,15 @@ public final class HdmiCecClientWrapper extends ExternalResource { * Sends a CEC message with source marked as broadcast to the device passed in the constructor * through the output console of the cec-communication channel. */ - public void sendCecMessage(CecMessage message) throws Exception { - sendCecMessage(CecDevice.BROADCAST, targetDevice, message, ""); + public void sendCecMessage(CecOperand message) throws Exception { + sendCecMessage(LogicalAddress.BROADCAST, targetDevice, message, ""); } /** * Sends a CEC message from source device to the device passed in the constructor through the * output console of the cec-communication channel. */ - public void sendCecMessage(CecDevice source, CecMessage message) throws Exception { + public void sendCecMessage(LogicalAddress source, CecOperand message) throws Exception { sendCecMessage(source, targetDevice, message, ""); } @@ -149,8 +122,8 @@ public final class HdmiCecClientWrapper extends ExternalResource { * Sends a CEC message from source device to a destination device through the output console of * the cec-communication channel. */ - public void sendCecMessage(CecDevice source, CecDevice destination, - CecMessage message) throws Exception { + public void sendCecMessage(LogicalAddress source, LogicalAddress destination, + CecOperand message) throws Exception { sendCecMessage(source, destination, message, ""); } @@ -158,10 +131,11 @@ public final class HdmiCecClientWrapper extends ExternalResource { * Sends a CEC message from source device to a destination device through the output console of * the cec-communication channel with the appended params. */ - public void sendCecMessage(CecDevice source, CecDevice destination, - CecMessage message, String params) throws Exception { + public void sendCecMessage(LogicalAddress source, LogicalAddress destination, + CecOperand message, String params) throws Exception { checkCecClient(); mOutputConsole.write("tx " + source + destination + ":" + message + params); + mOutputConsole.newLine(); mOutputConsole.flush(); } @@ -169,13 +143,13 @@ public final class HdmiCecClientWrapper extends ExternalResource { * Sends a <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> from source to destination * through the output console of the cec-communication channel with the mentioned keycode. */ - public void sendUserControlPressAndRelease(CecDevice source, CecDevice destination, + public void sendUserControlPressAndRelease(LogicalAddress source, LogicalAddress destination, int keycode, boolean holdKey) throws Exception { sendUserControlPress(source, destination, keycode, holdKey); /* Sleep less than 200ms between press and release */ TimeUnit.MILLISECONDS.sleep(100); mOutputConsole.write("tx " + source + destination + ":" + - CecMessage.USER_CONTROL_RELEASED); + CecOperand.USER_CONTROL_RELEASED); mOutputConsole.flush(); } @@ -184,11 +158,11 @@ public final class HdmiCecClientWrapper extends ExternalResource { * cec-communication channel with the mentioned keycode. If holdKey is true, the method will * send multiple <UCP> messages to simulate a long press. No <UCR> will be sent. */ - public void sendUserControlPress(CecDevice source, CecDevice destination, + public void sendUserControlPress(LogicalAddress source, LogicalAddress destination, int keycode, boolean holdKey) throws Exception { String key = String.format("%02x", keycode); String command = "tx " + source + destination + ":" + - CecMessage.USER_CONTROL_PRESSED + ":" + key; + CecOperand.USER_CONTROL_PRESSED + ":" + key; if (holdKey) { /* Repeat once between 200ms and 450ms for at least 5 seconds. Since message will be @@ -212,7 +186,8 @@ public final class HdmiCecClientWrapper extends ExternalResource { * of the cec-communication channel immediately followed by <UCP> [secondKeycode]. No <UCR> * message is sent. */ - public void sendUserControlInterruptedPressAndHold(CecDevice source, CecDevice destination, + public void sendUserControlInterruptedPressAndHold( + LogicalAddress source, LogicalAddress destination, int firstKeycode, int secondKeycode, boolean holdKey) throws Exception { sendUserControlPress(source, destination, firstKeycode, holdKey); /* Sleep less than 200ms between press and release */ @@ -253,13 +228,40 @@ public final class HdmiCecClientWrapper extends ExternalResource { return false; } + /** Gets all the messages received from the given source device during a period of duration + * seconds. + */ + public List<CecOperand> getAllMessages(LogicalAddress source, int duration) throws Exception { + List<CecOperand> receivedOperands = new ArrayList<>(); + long startTime = System.currentTimeMillis(); + long endTime = startTime; + Pattern pattern = Pattern.compile("(.*>>)(.*?)" + + "(" + source + "\\p{XDigit}):(.*)", + Pattern.CASE_INSENSITIVE); + + while ((endTime - startTime <= duration)) { + if (mInputConsole.ready()) { + String line = mInputConsole.readLine(); + if (pattern.matcher(line).matches()) { + CecOperand operand = CecMessage.getOperand(line); + if (!receivedOperands.contains(operand)) { + receivedOperands.add(operand); + } + } + } + endTime = System.currentTimeMillis(); + } + return receivedOperands; + } + + /** * Looks for the CEC expectedMessage broadcast on the cec-client communication channel and * returns the first line that contains that message within default timeout. If the CEC message * is not found within the timeout, an exception is thrown. */ - public String checkExpectedOutput(CecMessage expectedMessage) throws Exception { - return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, DEFAULT_TIMEOUT); + public String checkExpectedOutput(CecOperand expectedMessage) throws Exception { + return checkExpectedOutput(LogicalAddress.BROADCAST, expectedMessage, DEFAULT_TIMEOUT); } /** @@ -267,8 +269,8 @@ public final class HdmiCecClientWrapper extends ExternalResource { * communication channel and returns the first line that contains that message within * default timeout. If the CEC message is not found within the timeout, an exception is thrown. */ - public String checkExpectedOutput(CecDevice toDevice, - CecMessage expectedMessage) throws Exception { + public String checkExpectedOutput(LogicalAddress toDevice, + CecOperand expectedMessage) throws Exception { return checkExpectedOutput(toDevice, expectedMessage, DEFAULT_TIMEOUT); } @@ -277,9 +279,9 @@ public final class HdmiCecClientWrapper extends ExternalResource { * returns the first line that contains that message within timeoutMillis. If the CEC message * is not found within the timeout, an exception is thrown. */ - public String checkExpectedOutput(CecMessage expectedMessage, + public String checkExpectedOutput(CecOperand expectedMessage, long timeoutMillis) throws Exception { - return checkExpectedOutput(CecDevice.BROADCAST, expectedMessage, timeoutMillis); + return checkExpectedOutput(LogicalAddress.BROADCAST, expectedMessage, timeoutMillis); } /** @@ -287,7 +289,7 @@ public final class HdmiCecClientWrapper extends ExternalResource { * communication channel and returns the first line that contains that message within * timeoutMillis. If the CEC message is not found within the timeout, an exception is thrown. */ - public String checkExpectedOutput(CecDevice toDevice, CecMessage expectedMessage, + public String checkExpectedOutput(LogicalAddress toDevice, CecOperand expectedMessage, long timeoutMillis) throws Exception { checkCecClient(); long startTime = System.currentTimeMillis(); @@ -316,8 +318,8 @@ public final class HdmiCecClientWrapper extends ExternalResource { * within the default timeout. If the CEC message is not found within the timeout, function * returns without error. */ - public void checkOutputDoesNotContainMessage(CecDevice toDevice, - CecMessage incorrectMessage) throws Exception { + public void checkOutputDoesNotContainMessage(LogicalAddress toDevice, + CecOperand incorrectMessage) throws Exception { checkOutputDoesNotContainMessage(toDevice, incorrectMessage, DEFAULT_TIMEOUT); } @@ -327,7 +329,7 @@ public final class HdmiCecClientWrapper extends ExternalResource { * within timeoutMillis. If the CEC message is not found within the timeout, function returns * without error. */ - public void checkOutputDoesNotContainMessage(CecDevice toDevice, CecMessage incorrectMessage, + public void checkOutputDoesNotContainMessage(LogicalAddress toDevice, CecOperand incorrectMessage, long timeoutMillis) throws Exception { checkCecClient(); @@ -344,146 +346,13 @@ public final class HdmiCecClientWrapper extends ExternalResource { if (pattern.matcher(line).matches()) { CLog.v("Found " + incorrectMessage.name() + " in " + line); throw new Exception("Found " + incorrectMessage.name() + " to " + toDevice + - " with params " + getParamsFromMessage(line)); + " with params " + CecMessage.getParamsAsString(line)); } } endTime = System.currentTimeMillis(); } } - /** Gets the hexadecimal ASCII character values of a string. */ - public String getHexAsciiString(String string) { - String asciiString = ""; - byte[] ascii = string.trim().getBytes(); - - for (byte b : ascii) { - asciiString.concat(Integer.toHexString(b)); - } - - return asciiString; - } - - public String formatParams(String rawParams) { - StringBuilder params = new StringBuilder(""); - int position = 0; - int endPosition = 2; - - do { - params.append(":" + rawParams.substring(position, endPosition)); - position = endPosition; - endPosition += 2; - } while (endPosition <= rawParams.length()); - return params.toString(); - } - - public String formatParams(long rawParam) { - StringBuilder params = new StringBuilder(""); - - do { - params.insert(0, ":" + String.format("%02x", rawParam % 256)); - rawParam >>= 8; - } while (rawParam > 0); - - return params.toString(); - } - - /** Formats a CEC message in the hex colon format (sd:op:xx:xx). */ - public String formatMessage(CecDevice source, CecDevice destination, CecMessage message, - int params) { - StringBuilder cecMessage = new StringBuilder("" + source + destination + ":" + message); - - cecMessage.append(formatParams(params)); - - return cecMessage.toString(); - } - - public static int hexStringToInt(String message) { - return Integer.parseInt(message, HEXADECIMAL_RADIX); - } - - public String getAsciiStringFromMessage(String message) { - String params = getNibbles(message).substring(4); - StringBuilder builder = new StringBuilder(); - - for (int i = 2; i <= params.length(); i += 2) { - builder.append((char) hexStringToInt(params.substring(i - 2, i))); - } - - return builder.toString(); - } - - /** - * Gets the params from a CEC message. - */ - public int getParamsFromMessage(String message) { - return hexStringToInt(getNibbles(message).substring(4)); - } - - /** - * Gets the first 'numNibbles' number of param nibbles from a CEC message. - */ - public int getParamsFromMessage(String message, int numNibbles) { - int paramStart = 4; - int end = numNibbles + paramStart; - return hexStringToInt(getNibbles(message).substring(paramStart, end)); - } - - /** - * From the params of a CEC message, gets the nibbles from position start to position end. - * The start and end are relative to the beginning of the params. For example, in the following - * message - 4F:82:10:00:04, getParamsFromMessage(message, 0, 4) will return 0x1000 and - * getParamsFromMessage(message, 4, 6) will return 0x04. - */ - public int getParamsFromMessage(String message, int start, int end) { - return hexStringToInt(getNibbles(message).substring(4).substring(start, end)); - } - - /** - * Gets the source logical address from a CEC message. - */ - public CecDevice getSourceFromMessage(String message) { - String param = getNibbles(message).substring(0, 1); - return CecDevice.getDevice(hexStringToInt(param)); - } - - /** - * Converts ascii characters to hexadecimal numbers that can be appended to a CEC message as - * params. For example, "spa" will be converted to ":73:70:61" - */ - public static String convertStringToHexParams(String rawParams) { - StringBuilder params = new StringBuilder(""); - for (int i = 0; i < rawParams.length(); i++) { - params.append(String.format(":%02x", (int) rawParams.charAt(i))); - } - return params.toString(); - } - - - /** - * Gets the destination logical address from a CEC message. - */ - public CecDevice getDestinationFromMessage(String message) { - String param = getNibbles(message).substring(1, 2); - return CecDevice.getDevice(hexStringToInt(param)); - } - - private String getNibbles(String message) { - final String tag1 = "group1"; - final String tag2 = "group2"; - String paramsPattern = "(?:.*[>>|<<].*?)" + - "(?<" + tag1 + ">[\\p{XDigit}{2}:]+)" + - "(?<" + tag2 + ">\\p{XDigit}{2})" + - "(?:.*?)"; - String nibbles = ""; - - Pattern p = Pattern.compile(paramsPattern); - Matcher m = p.matcher(message); - if (m.matches()) { - nibbles = m.group(tag1).replace(":", "") + m.group(tag2); - } - return nibbles; - } - /** * Kills the cec-client process that was created in init(). */ diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java index 0565eaefbfb..8af4a8b5c0d 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java @@ -47,4 +47,11 @@ public final class HdmiCecConstants { public static final int CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4; public static final int CEC_DEVICE_TYPE_AUDIO_SYSTEM = 5; + /** Feature Abort Reasons */ + public static final int ABORT_UNRECOGNIZED_MODE = 0; + public static final int ABORT_NOT_IN_CORRECT_MODE = 1; + public static final int ABORT_CANNOT_PROVIDE_SOURCE = 2; + public static final int ABORT_INVALID_OPERAND = 3; + public static final int ABORT_REFUSED = 4; + public static final int ABORT_UNABLE_TO_DETERMINE = 5; } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/LogHelper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/LogHelper.java new file mode 100644 index 00000000000..a7692f38104 --- /dev/null +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/LogHelper.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.cts; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assume.assumeTrue; + +import com.android.tradefed.device.ITestDevice; + +import com.google.common.collect.Lists; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.concurrent.TimeUnit; + +/** Helper class to get for device logcat. */ +public final class LogHelper { + + private static final int WAIT_TIME = 10; + + /** + * The tag of the SadConfigurationReaderTest launched by the APK. + */ + private static final String SAD_READER = "SadConfigurationReaderTest"; + + private static final String SAD_CONFIGURATION_MARKER = "Supported Audio Formats"; + + private static String getLog(ITestDevice device, String tag) throws Exception { + TimeUnit.SECONDS.sleep(WAIT_TIME); + String logs = device.executeAdbCommand("logcat", "-v", "brief", "-d", tag + ":I", "*:S"); + // Search for string. + String testString = ""; + Scanner in = new Scanner(logs); + while (in.hasNextLine()) { + String line = in.nextLine(); + if (line.startsWith("I/" + tag)) { + testString = line.split(":")[1].trim(); + } + } + device.executeAdbCommand("logcat", "-c"); + return testString; + } + + public static void assertLog(ITestDevice device, String tag, String ...expectedOutput) + throws Exception { + String testString = getLog(device, tag); + List<String> expectedOutputs = new ArrayList<>(Arrays.asList(expectedOutput)); + assertThat(testString).isIn(expectedOutputs); + } + + public static void assertLogDoesNotContain(ITestDevice device, String tag, + String expectedOutput) throws Exception { + String testString = getLog(device, tag); + assertThat(testString).doesNotContain(expectedOutput); + } + + public static List<Integer> getSupportedAudioFormats(ITestDevice device) throws Exception { + TimeUnit.SECONDS.sleep(WAIT_TIME); + String logs = + device.executeAdbCommand("logcat", "-v", "brief", "-d", SAD_READER + ":I", "*:S"); + // Search for string. + String testString = ""; + Scanner in = new Scanner(logs); + List<Integer> mSupportedAudioFormats = null; + while (in.hasNextLine()) { + String line = in.nextLine(); + if (line.startsWith("I/" + SAD_READER)) { + testString = line.split(":")[1].trim(); + if (testString.equals(SAD_CONFIGURATION_MARKER)) { + List<String> mFormatsLine = + Arrays.asList(in.nextLine().split(":")[1].trim().split(", ")); + List<String> mCodecSADsLine = + Arrays.asList(in.nextLine().split(":")[1].trim().split(", ")); + mSupportedAudioFormats = + Lists.transform(mFormatsLine, fl -> Integer.parseInt(fl)); + } + } + } + device.executeAdbCommand("logcat", "-c"); + assumeTrue(testString.equals(SAD_CONFIGURATION_MARKER)); + return mSupportedAudioFormats; + } +} diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/LogicalAddress.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/LogicalAddress.java new file mode 100644 index 00000000000..5bcf5d1c92f --- /dev/null +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/LogicalAddress.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.cts; + +import java.util.HashMap; +import java.util.Map; + +public enum LogicalAddress { + TV(0x0), + RECORDER_1(0x1), + RECORDER_2(0x2), + TUNER_1(0x3), + PLAYBACK_1(0x4), + AUDIO_SYSTEM(0x5), + TUNER_2(0x6), + TUNER_3(0x7), + PLAYBACK_2(0x8), + RECORDER_3(0x9), + TUNER_4(0xa), + PLAYBACK_3(0xb), + RESERVED_1(0xc), + RESERVED_2(0xd), + SPECIFIC_USE(0xe), + BROADCAST(0xf); + + private final int address; + private static Map deviceMap = new HashMap<>(); + + // CEC Device feature list + public static final String HDMI_CEC_FEATURE = "feature:android.hardware.hdmi.cec"; + public static final String LEANBACK_FEATURE = "feature:android.software.leanback"; + + // CEC Device property list + public static final String HDMI_DEVICE_TYPE_PROPERTY = "ro.hdmi.device_type"; + + @Override + public String toString() { + return Integer.toHexString(this.address); + } + + static { + for (LogicalAddress device : LogicalAddress.values()) { + deviceMap.put(device.address, device); + } + } + + public String getDeviceType() { + switch (this) { + case PLAYBACK_1: + case PLAYBACK_2: + case PLAYBACK_3: + return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE); + case TV: + return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_TV); + case AUDIO_SYSTEM: + return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM); + case RECORDER_1: + case RECORDER_2: + case RECORDER_3: + return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_RECORDER); + case TUNER_1: + case TUNER_2: + case TUNER_3: + case TUNER_4: + return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_TUNER); + default: + return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_RESERVED); + } + } + + public static LogicalAddress getLogicalAddress(int address) { + return (LogicalAddress) deviceMap.get(address); + } + + private LogicalAddress(int address) { + this.address = address; + } +} diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/RequiredFeatureRule.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/RequiredFeatureRule.java new file mode 100644 index 00000000000..8fb70ec025e --- /dev/null +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/RequiredFeatureRule.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.cts; + +import static org.junit.Assume.assumeTrue; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * Rule to check if the required device feature is available on device. + */ +public class RequiredFeatureRule implements TestRule { + + private final BaseHostJUnit4Test mTest; + private final String mFeature; + + public RequiredFeatureRule(BaseHostJUnit4Test test, String feature) { + mTest = test; + mFeature = feature; + } + + @Override + public Statement apply(final Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + ITestDevice testDevice = mTest.getDevice(); + // Checks if the device is available. + assumeTrue("Test device is not available", testDevice != null); + // Checks if the requested feature is available on the device. + assumeTrue(mFeature + " not present in DUT " + testDevice.getSerialNumber(), + testDevice.hasFeature(mFeature)); + base.evaluate(); + } + }; + } +} + diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/RequiredPropertyRule.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/RequiredPropertyRule.java new file mode 100644 index 00000000000..f3998adbe08 --- /dev/null +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/RequiredPropertyRule.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.cts; + +import static org.junit.Assume.assumeTrue; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import java.util.Arrays; +import java.util.List; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * Rule class that allows for checking device property value against required values. + * Static functions in this class can be used to check properties as a list or single value. + */ +public class RequiredPropertyRule implements TestRule { + + // Do not allow instantiation. + private RequiredPropertyRule(){} + + @Override + public Statement apply(final Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + base.evaluate(); + } + }; + } + + private static String getDevicePropertyValue(BaseHostJUnit4Test test, String propertyName) + throws Throwable { + ITestDevice testDevice = test.getDevice(); + // Checks if the device is available. + assumeTrue("Test device is not available", testDevice != null); + return testDevice.executeShellCommand("getprop " + propertyName).trim(); + + } + + public static RequiredPropertyRule isEqualTo(final BaseHostJUnit4Test test, + final String propertyName, final String propertyValue) { + return new RequiredPropertyRule() { + @Override + public Statement apply(final Statement base, final Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + String deviceProperty = getDevicePropertyValue(test, propertyName); + assumeTrue("Required property " + propertyName + " = " + propertyValue + + " is not present in " + deviceProperty + + " of device " + test.getDevice().getSerialNumber(), + deviceProperty.equals(propertyValue)); + base.evaluate(); + } + }; + } + }; + } + + public static RequiredPropertyRule asCsvContainsValue(final BaseHostJUnit4Test test, + final String propertyName, final String propertyValue) { + return new RequiredPropertyRule() { + @Override + public Statement apply(final Statement base, final Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + List<String> deviceProperties = + Arrays.asList(getDevicePropertyValue(test, propertyName) + .replaceAll("\\s+", "") + .split(",")); + assumeTrue( + "Required property " + propertyName + " = " + propertyValue + + " is not present in " + deviceProperties.toString() + + " of device " + test.getDevice().getSerialNumber(), + deviceProperties.contains(propertyValue)); + base.evaluate(); + } + }; + } + }; + } +} + + diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java new file mode 100644 index 00000000000..897a35e4adf --- /dev/null +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecAudioReturnChannelControlTest.java @@ -0,0 +1,134 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.cts.audio; + +import static org.junit.Assume.assumeNoException; + +import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; +import android.hdmicec.cts.HdmiCecClientWrapper; +import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.runner.RunWith; +import org.junit.Test; + +/** HDMI CEC test to test audio return channel control (Section 11.2.17) */ +@RunWith(DeviceJUnit4ClassRunner.class) +public final class HdmiCecAudioReturnChannelControlTest extends BaseHostJUnit4Test { + + private static final LogicalAddress AUDIO_DEVICE = LogicalAddress.AUDIO_SYSTEM; + + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(AUDIO_DEVICE); + + @Rule + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + AUDIO_DEVICE.getDeviceType())) + .around(hdmiCecClient); + + private void checkArcIsInitiated(){ + try { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.REQUEST_ARC_INITIATION); + hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.INITIATE_ARC); + } catch(Exception e) { + assumeNoException(e); + } + } + + /** + * Test 11.2.17-1 + * Tests that the device sends a directly addressed <Initiate ARC> message + * when it wants to initiate ARC. + */ + @Test + public void cect_11_2_17_1_InitiateArc() throws Exception { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, + CecOperand.REPORT_PHYSICAL_ADDRESS, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + getDevice().executeShellCommand("reboot"); + getDevice().waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); + hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.INITIATE_ARC); + } + + /** + * Test 11.2.17-2 + * Tests that the device sends a directly addressed <Terminate ARC> message + * when it wants to terminate ARC. + */ + @Test + public void cect_11_2_17_2_TerminateArc() throws Exception { + checkArcIsInitiated(); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, + CecOperand.REPORT_PHYSICAL_ADDRESS, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + getDevice().executeShellCommand("input keyevent KEYCODE_SLEEP"); + try { + hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.TERMINATE_ARC); + } finally { + getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP"); + } + } + + /** + * Test 11.2.17-3 + * Tests that the device sends a directly addressed <Initiate ARC> + * message when it is requested to initiate ARC. + */ + @Test + public void cect_11_2_17_3_RequestToInitiateArc() throws Exception { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, + CecOperand.REPORT_PHYSICAL_ADDRESS, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.REQUEST_ARC_INITIATION); + hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.INITIATE_ARC); + } + + /** + * Test 11.2.17-4 + * Tests that the device sends a directly addressed <Terminate ARC> message + * when it is requested to terminate ARC. + */ + @Test + public void cect_11_2_17_4_RequestToTerminateArc() throws Exception { + checkArcIsInitiated(); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, + CecOperand.REPORT_PHYSICAL_ADDRESS, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.REQUEST_ARC_TERMINATION); + hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.TERMINATE_ARC); + } +} diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java new file mode 100644 index 00000000000..a77573ebcd7 --- /dev/null +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecInvalidMessagesTest.java @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.cts.audio; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assume.assumeNoException; +import static org.junit.Assume.assumeTrue; + +import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; +import android.hdmicec.cts.HdmiCecClientWrapper; +import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogHelper; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.runner.RunWith; + +/** HDMI CEC test to verify that device ignores invalid messages (Section 12) */ +@RunWith(DeviceJUnit4ClassRunner.class) +public final class HdmiCecInvalidMessagesTest extends BaseHostJUnit4Test { + + private static final LogicalAddress AUDIO_DEVICE = LogicalAddress.AUDIO_SYSTEM; + private static final String PROPERTY_LOCALE = "persist.sys.locale"; + + /** The package name of the APK. */ + private static final String PACKAGE = "android.hdmicec.app"; + + /** The class name of the main activity in the APK. */ + private static final String CLASS = "HdmiCecKeyEventCapture"; + + /** The command to launch the main activity. */ + private static final String START_COMMAND = String.format( + "am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS); + + /** The command to clear the main activity. */ + private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE); + + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(AUDIO_DEVICE); + + @Rule + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + AUDIO_DEVICE.getDeviceType())) + .around(hdmiCecClient); + + private String getSystemLocale() throws Exception { + ITestDevice device = getDevice(); + return device.executeShellCommand("getprop " + PROPERTY_LOCALE).trim(); + } + + private void setSystemLocale(String locale) throws Exception { + ITestDevice device = getDevice(); + device.executeShellCommand("setprop " + PROPERTY_LOCALE + " " + locale); + } + + private boolean isLanguageEditable() throws Exception { + String val = getDevice().executeShellCommand("getprop ro.hdmi.set_menu_language"); + return val.trim().equals("true") ? true : false; + } + + private static String extractLanguage(String locale) { + return locale.split("[^a-zA-Z]")[0]; + } + + private void checkArcIsInitiated(){ + try { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.REQUEST_ARC_INITIATION); + hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.INITIATE_ARC); + } catch(Exception e) { + assumeNoException(e); + } + } + + /** + * Test 12-1 + * Tests that the device ignores every broadcast only message that is received as + * directly addressed. + */ + @Test + public void cect_12_1_BroadcastReceivedAsDirectlyAddressed() throws Exception { + /* <Set Menu Language> */ + assumeTrue(isLanguageEditable()); + final String locale = getSystemLocale(); + final String originalLanguage = extractLanguage(locale); + final String language = originalLanguage.equals("spa") ? "eng" : "spa"; + try { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + AUDIO_DEVICE, + CecOperand.SET_MENU_LANGUAGE, + CecMessage.convertStringToHexParams(language)); + assertThat(originalLanguage).isEqualTo(extractLanguage(getSystemLocale())); + } finally { + // If the language was incorrectly changed during the test, restore it. + setSystemLocale(locale); + } + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <GET_CEC_VERSION> if received as + * a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_getCecVersion() throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.GET_CEC_VERSION); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.TV, + CecOperand.CEC_VERSION); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <GIVE_PHYSICAL_ADDRESS> if received + * as a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_givePhysicalAddress() + throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.GIVE_PHYSICAL_ADDRESS); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.BROADCAST, + CecOperand.REPORT_PHYSICAL_ADDRESS); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <GIVE_AUDIO_STATUS> if received as + * a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_giveAudioStatus() throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.GIVE_AUDIO_STATUS); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.TV, + CecOperand.REPORT_AUDIO_STATUS); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <GIVE_POWER_STATUS> if received as + * a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_givePowerStatus() throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.GIVE_POWER_STATUS); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.TV, + CecOperand.REPORT_POWER_STATUS); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <GIVE_DEVICE_VENDOR_ID> if received + * as a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_giveDeviceVendorId() + throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.GIVE_DEVICE_VENDOR_ID); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.BROADCAST, + CecOperand.DEVICE_VENDOR_ID); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <GIVE_OSD_NAME> if received as + * a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_giveOsdName() throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.GIVE_OSD_NAME); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.TV, + CecOperand.SET_OSD_NAME); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <GIVE_SYSTEM_AUDIO_MODE_STATUS> if + * received as a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_giveSystemAudioModeStatus() + throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.TV, + CecOperand.SYSTEM_AUDIO_MODE_STATUS); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <REQUEST_SHORT_AUDIO_DESCRIPTOR> if + * received as a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_requestShortAudioDescriptor() + throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.REQUEST_SHORT_AUDIO_DESCRIPTOR, + CecMessage.formatParams("01020304")); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.TV, + CecOperand.REPORT_SHORT_AUDIO_DESCRIPTOR); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <SYSTEM_AUDIO_MODE_REQUEST> if + * received as a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_systemAudioModeRequest() + throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.SYSTEM_AUDIO_MODE_REQUEST); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.BROADCAST, + CecOperand.SET_SYSTEM_AUDIO_MODE); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <REQUEST_ARC_INITIATION> if + * received as a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_requestArcInitiation() + throws Exception { + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.REQUEST_ARC_INITIATION); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.BROADCAST, + CecOperand.INITIATE_ARC); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <REQUEST_ARC_TERMINATION> if + * received as a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_requestArcTermination() + throws Exception { + checkArcIsInitiated(); + hdmiCecClient.sendCecMessage( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + CecOperand.REQUEST_ARC_TERMINATION); + hdmiCecClient.checkOutputDoesNotContainMessage( + LogicalAddress.BROADCAST, + CecOperand.TERMINATE_ARC); + } + + /** + * Test 12-2 + * Tests that the device ignores directly addressed message <USER_CONTROL_PRESSED> if received + * as a broadcast message + */ + @Test + public void cect_12_2_DirectlyAddressedReceivedAsBroadcast_userControlPressed() + throws Exception { + ITestDevice device = getDevice(); + // Clear activity + device.executeShellCommand(CLEAR_COMMAND); + // Clear logcat. + device.executeAdbCommand("logcat", "-c"); + // Start the APK and wait for it to complete. + device.executeShellCommand(START_COMMAND); + hdmiCecClient.sendUserControlPressAndRelease( + LogicalAddress.TV, + LogicalAddress.BROADCAST, + HdmiCecConstants.CEC_CONTROL_UP, + false); + LogHelper.assertLogDoesNotContain(getDevice(), CLASS, "Short press KEYCODE_DPAD_UP"); + } +} diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java index 1305a2b50b8..d0f052d6d6a 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecLogicalAddressTest.java @@ -16,29 +16,43 @@ package android.hdmicec.cts.audio; -import static org.junit.Assert.assertThat; -import static org.hamcrest.CoreMatchers.is; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; /** HDMI CEC test to verify logical address after device reboot (Section 10.2.5) */ @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecLogicalAddressTest extends BaseHostJUnit4Test { - private static final CecDevice AUDIO_DEVICE = CecDevice.AUDIO_SYSTEM; + + private static final LogicalAddress AUDIO_DEVICE = LogicalAddress.AUDIO_SYSTEM; + + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(AUDIO_DEVICE); @Rule - public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(AUDIO_DEVICE, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + AUDIO_DEVICE.getDeviceType())) + .around(hdmiCecClient); /** * Test 10.2.5-1 @@ -50,7 +64,7 @@ public final class HdmiCecLogicalAddressTest extends BaseHostJUnit4Test { ITestDevice device = getDevice(); device.executeShellCommand("reboot"); device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS); - assertThat(hdmiCecClient.getSourceFromMessage(message), is(AUDIO_DEVICE)); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS); + assertThat(CecMessage.getSource(message)).isEqualTo(AUDIO_DEVICE); } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java index 9931e263dc1..d01b5063546 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java @@ -16,23 +16,22 @@ package android.hdmicec.cts.audio; -import static com.google.common.truth.Truth.assertThat; - -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogHelper; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; -import java.util.Scanner; -import java.util.concurrent.TimeUnit; - @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Test { @@ -49,29 +48,18 @@ public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Tes /** The command to clear the main activity. */ private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE); - private static final int WAIT_TIME = 10; + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.AUDIO_SYSTEM); @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.AUDIO_SYSTEM, this); - - private void lookForLog(String expectedOut) throws Exception { - ITestDevice device = getDevice(); - TimeUnit.SECONDS.sleep(WAIT_TIME); - String logs = device.executeAdbCommand("logcat", "-v", "brief", "-d", CLASS + ":I", "*:S"); - // Search for string. - String testString = ""; - Scanner in = new Scanner(logs); - while (in.hasNextLine()) { - String line = in.nextLine(); - if(line.startsWith("I/" + CLASS)) { - testString = line.split(":")[1].trim(); - break; - } - } - device.executeAdbCommand("logcat", "-c"); - assertThat(testString).isEqualTo(expectedOut); - } + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + LogicalAddress.AUDIO_SYSTEM.getDeviceType())) + .around(hdmiCecClient); /** * Test 11.2.13-1 @@ -87,24 +75,24 @@ public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Tes device.executeAdbCommand("logcat", "-c"); // Start the APK and wait for it to complete. device.executeShellCommand(START_COMMAND); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_UP, false); - lookForLog("Short press KEYCODE_DPAD_UP"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_UP"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_DOWN, false); - lookForLog("Short press KEYCODE_DPAD_DOWN"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_DOWN"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_LEFT, false); - lookForLog("Short press KEYCODE_DPAD_LEFT"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_LEFT"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_RIGHT, false); - lookForLog("Short press KEYCODE_DPAD_RIGHT"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_RIGHT"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_SELECT, false); - lookForLog("Short press KEYCODE_DPAD_CENTER"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_CENTER"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_BACK, false); - lookForLog("Short press KEYCODE_BACK"); + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_BACK"); } /** @@ -121,24 +109,24 @@ public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Tes device.executeAdbCommand("logcat", "-c"); // Start the APK and wait for it to complete. device.executeShellCommand(START_COMMAND); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_UP, true); - lookForLog("Long press KEYCODE_DPAD_UP"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_UP"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_DOWN, true); - lookForLog("Long press KEYCODE_DPAD_DOWN"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_DOWN"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_LEFT, true); - lookForLog("Long press KEYCODE_DPAD_LEFT"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_LEFT"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_RIGHT, true); - lookForLog("Long press KEYCODE_DPAD_RIGHT"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_RIGHT"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_SELECT, true); - lookForLog("Long press KEYCODE_DPAD_CENTER"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_CENTER"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_BACK, true); - lookForLog("Long press KEYCODE_BACK"); + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_BACK"); } /** @@ -155,24 +143,24 @@ public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Tes device.executeAdbCommand("logcat", "-c"); // Start the APK and wait for it to complete. device.executeShellCommand(START_COMMAND); - hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_UP, true); - lookForLog("Long press KEYCODE_DPAD_UP"); - hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_UP"); + hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_DOWN, true); - lookForLog("Long press KEYCODE_DPAD_DOWN"); - hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_DOWN"); + hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_LEFT, true); - lookForLog("Long press KEYCODE_DPAD_LEFT"); - hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_LEFT"); + hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_RIGHT, true); - lookForLog("Long press KEYCODE_DPAD_RIGHT"); - hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_RIGHT"); + hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_SELECT, true); - lookForLog("Long press KEYCODE_DPAD_CENTER"); - hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_CENTER"); + hdmiCecClient.sendUserControlPress(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_BACK, true); - lookForLog("Long press KEYCODE_BACK"); + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_BACK"); } /** @@ -190,29 +178,29 @@ public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Tes device.executeAdbCommand("logcat", "-c"); // Start the APK and wait for it to complete. device.executeShellCommand(START_COMMAND); - hdmiCecClient.sendUserControlInterruptedPressAndHold(CecDevice.TV, - CecDevice.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_UP, + hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV, + LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_UP, HdmiCecConstants.CEC_CONTROL_BACK, true); - lookForLog("Long press KEYCODE_DPAD_UP"); - hdmiCecClient.sendUserControlInterruptedPressAndHold(CecDevice.TV, - CecDevice.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_DOWN, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_UP"); + hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV, + LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_DOWN, HdmiCecConstants.CEC_CONTROL_UP, true); - lookForLog("Long press KEYCODE_DPAD_DOWN"); - hdmiCecClient.sendUserControlInterruptedPressAndHold(CecDevice.TV, - CecDevice.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_LEFT, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_DOWN"); + hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV, + LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_LEFT, HdmiCecConstants.CEC_CONTROL_DOWN, true); - lookForLog("Long press KEYCODE_DPAD_LEFT"); - hdmiCecClient.sendUserControlInterruptedPressAndHold(CecDevice.TV, - CecDevice.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_RIGHT, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_LEFT"); + hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV, + LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_RIGHT, HdmiCecConstants.CEC_CONTROL_LEFT, true); - lookForLog("Long press KEYCODE_DPAD_RIGHT"); - hdmiCecClient.sendUserControlInterruptedPressAndHold(CecDevice.TV, - CecDevice.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_SELECT, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_RIGHT"); + hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV, + LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_SELECT, HdmiCecConstants.CEC_CONTROL_RIGHT, true); - lookForLog("Long press KEYCODE_DPAD_CENTER"); - hdmiCecClient.sendUserControlInterruptedPressAndHold(CecDevice.TV, - CecDevice.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_BACK, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_CENTER"); + hdmiCecClient.sendUserControlInterruptedPressAndHold(LogicalAddress.TV, + LogicalAddress.AUDIO_SYSTEM, HdmiCecConstants.CEC_CONTROL_BACK, HdmiCecConstants.CEC_CONTROL_SELECT, true); - lookForLog("Long press KEYCODE_BACK"); + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_BACK"); } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java index 6f6e4dc11c6..ac21a0fa8ba 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java @@ -16,29 +16,206 @@ package android.hdmicec.cts.audio; -import static org.junit.Assert.assertThat; -import static org.hamcrest.CoreMatchers.is; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import com.google.common.collect.Range; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogHelper; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; +import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import org.junit.After; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + /** HDMI CEC test to test system audio mode (Section 11.2.15) */ @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecSystemAudioModeTest extends BaseHostJUnit4Test { - private static final CecDevice AUDIO_DEVICE = CecDevice.AUDIO_SYSTEM; + + /** The package name of the APK. */ + private static final String PACKAGE = "android.hdmicec.app"; + + /** The class name of the main activity in the APK. */ + private static final String CLASS = "HdmiCecAudioManager"; + + /** The command to launch the main activity. */ + private static final String START_COMMAND = String.format( + "am start -n %s/%s.%s -a ", PACKAGE, PACKAGE, CLASS); + + /** The command to clear the main activity. */ + private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE); + + private static final LogicalAddress AUDIO_DEVICE = LogicalAddress.AUDIO_SYSTEM; private static final int ON = 0x1; + private static final int OFF = 0x0; + private static final int MAX_AUDIO_FORMATS = 4; + private static final int MAX_VALID_AUDIO_FORMATS = 2; + + private List<Integer> mSupportedAudioFormats = null; + + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(AUDIO_DEVICE, "-t", "t"); @Rule - public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(AUDIO_DEVICE, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + AUDIO_DEVICE.getDeviceType())) + .around(hdmiCecClient); + + private String getRequestSadFormatsParams(boolean sendValidFormats) throws Exception { + ITestDevice device = getDevice(); + // Clear activity + device.executeShellCommand(CLEAR_COMMAND); + // Clear logcat. + device.executeAdbCommand("logcat", "-c"); + // Start the APK and wait for it to complete. + device.executeShellCommand(START_COMMAND + "android.hdmicec.app.GET_SUPPORTED_SAD_FORMATS"); + mSupportedAudioFormats = LogHelper.getSupportedAudioFormats(getDevice()); + + // Create a list of all the audio format codes according to CEA-861-D. Remove the supported + // audio format codes from it, to get the unsupported audio format codes. + List<Integer> mAllCodecFormats = + IntStream.range(1, 15).boxed().collect(Collectors.toList()); + List<Integer> unsupportedAudioFormats = new ArrayList<>(); + unsupportedAudioFormats.addAll(mAllCodecFormats); + unsupportedAudioFormats.removeAll(mSupportedAudioFormats); + // Create params message for REQUEST_SHORT_AUDIO_DESCRIPTOR + String messageParams = ""; + int i = 0; + int listIndex = 0; + if (sendValidFormats) { + while (i < Math.min(MAX_VALID_AUDIO_FORMATS, mSupportedAudioFormats.size())) { + messageParams += + CecMessage.formatParams(mSupportedAudioFormats.get(listIndex), 2); + i++; + listIndex++; + } + listIndex = 0; + } + while (i < Math.min(MAX_AUDIO_FORMATS, unsupportedAudioFormats.size())) { + messageParams += CecMessage.formatParams(unsupportedAudioFormats.get(listIndex), 2); + i++; + listIndex++; + } + return messageParams; + } + + private void muteDevice() throws Exception { + ITestDevice device = getDevice(); + // Clear activity + device.executeShellCommand(CLEAR_COMMAND); + // Clear logcat. + device.executeAdbCommand("logcat", "-c"); + // Start the APK and wait for it to complete. + device.executeShellCommand(START_COMMAND + "android.hdmicec.app.MUTE"); + } + + private void unmuteDevice() throws Exception { + ITestDevice device = getDevice(); + // Clear activity + device.executeShellCommand(CLEAR_COMMAND); + // Start the APK and wait for it to complete. + device.executeShellCommand(START_COMMAND + "android.hdmicec.app.UNMUTE"); + } + + public boolean isDeviceMuted() throws Exception { + ITestDevice device = getDevice(); + // Clear activity + device.executeShellCommand(CLEAR_COMMAND); + // Clear logcat. + device.executeAdbCommand("logcat", "-c"); + // Start the APK and wait for it to complete. + device.executeShellCommand(START_COMMAND + "android.hdmicec.app.REPORT_VOLUME"); + try { + LogHelper.assertLog(getDevice(), CLASS, "Device muted."); + return true; + } catch(Exception e) { + return false; + } + } + + public void setDeviceVolume(int percentVolume) throws Exception { + ITestDevice device = getDevice(); + // Clear activity + device.executeShellCommand(CLEAR_COMMAND); + // Start the APK and wait for it to complete. + device.executeShellCommand(START_COMMAND + "android.hdmicec.app.SET_VOLUME --ei " + + "\"volumePercent\" " + percentVolume); + } + + public void sendSystemAudioModeTermination() throws Exception { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.SYSTEM_AUDIO_MODE_REQUEST); + } + + public void sendSystemAudioModeInitiation() throws Exception { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.SYSTEM_AUDIO_MODE_REQUEST, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + } + + private int getDutAudioStatus() throws Exception { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, CecOperand.GIVE_AUDIO_STATUS); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, + CecOperand.REPORT_AUDIO_STATUS); + return CecMessage.getParams(message); + } + + private void initateSystemAudioModeFromTuner() throws Exception { + getDevice().reboot(); + hdmiCecClient.sendCecMessage(LogicalAddress.TUNER_1, AUDIO_DEVICE, + CecOperand.SYSTEM_AUDIO_MODE_REQUEST, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + handleSetSystemAudioModeOnToTv(); + } + + private void handleSetSystemAudioModeOnToTv() throws Exception { + hdmiCecClient.checkExpectedOutput(CecOperand.REQUEST_ACTIVE_SOURCE); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, CecOperand.ACTIVE_SOURCE, + CecMessage.formatParams("2000")); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, + CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); + } + + private void initiateSystemAudioModeFromDut() throws Exception { + getDevice().reboot(); + hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, + CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS); + hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.INITIATE_ARC); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM, + CecOperand.ARC_INITIATED); + handleSetSystemAudioModeOnToTv(); + } + + @After + public void resetVolume() throws Exception { + setDeviceVolume(20); + } /** * Test 11.2.15-1 @@ -47,17 +224,306 @@ public final class HdmiCecSystemAudioModeTest extends BaseHostJUnit4Test { */ @Test public void cect_11_2_15_1_SystemAudioModeRequestAsFollower() throws Exception { - hdmiCecClient.sendCecMessage(CecDevice.TV, AUDIO_DEVICE, - CecMessage.SYSTEM_AUDIO_MODE_REQUEST, - hdmiCecClient.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS)); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.SET_SYSTEM_AUDIO_MODE); - assertThat(hdmiCecClient.getParamsFromMessage(message), is(ON)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.SYSTEM_AUDIO_MODE_REQUEST, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); /* Repeat test for device 0x3 (TUNER_1) */ - hdmiCecClient.sendCecMessage(CecDevice.TUNER_1, AUDIO_DEVICE, - CecMessage.SYSTEM_AUDIO_MODE_REQUEST, - hdmiCecClient.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS)); - message = hdmiCecClient.checkExpectedOutput(CecMessage.SET_SYSTEM_AUDIO_MODE); - assertThat(hdmiCecClient.getParamsFromMessage(message), is(ON)); + hdmiCecClient.sendCecMessage(LogicalAddress.TUNER_1, AUDIO_DEVICE, + CecOperand.SYSTEM_AUDIO_MODE_REQUEST, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); + } + + /** + * Test 11.2.15-2 + * Tests that the device issues <Set System Audio Mode> + * message when the feature is initiated in the device . + */ + @Test + public void cect_11_2_15_2_SystemAudioModeWithFeatureInitiation() throws Exception { + initiateSystemAudioModeFromDut(); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); + } + + /** + * Test 11.2.15-3 + * Tests that the device doesn't broadcast any <Set System Audio Mode> + * messages when TV responds with a <Feature Abort> to a directly addressed + * <Set System Audio Mode> message. + */ + @Test + public void cect_11_2_15_3_SystemAudioModeWithFeatureAbort() throws Exception { + initiateSystemAudioModeFromDut(); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, CecOperand.FEATURE_ABORT, + CecMessage.formatParams(CecOperand.SET_SYSTEM_AUDIO_MODE + "04")); + hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.BROADCAST, + CecOperand.SET_SYSTEM_AUDIO_MODE); + //The DUT will need a reboot here so it'll forget the feature abort from the previous + // message. Else it may not respond correctly with a SET_SYSTEM_AUDIO_MODE message + // in future tests. + getDevice().reboot(); + } + + /** + * Test 11.2.15-4 + * Tests that the device responds correctly to a <Give System Audio Status> + * message when System Audio Mode is "On". + */ + @Test + public void cect_11_2_15_4_SystemAudioModeStatusOn() throws Exception { + sendSystemAudioModeInitiation(); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS); + message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, + CecOperand.SYSTEM_AUDIO_MODE_STATUS); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); + } + + /** + * Test 11.2.15-5 + * Tests that the device sends a <Set System Audio Mode> ["Off"] + * message when a <System Audio Mode Request> is received with no operands + */ + @Test + public void cect_11_2_15_5_SetSystemAudioModeOff() throws Exception { + sendSystemAudioModeInitiation(); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); + sendSystemAudioModeTermination(); + message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(OFF); + } + + /** + * Test 11.2.15-6 + * Tests that the device sends a <Set System Audio Mode> ["Off"] + * message before going into standby when System Audio Mode is on. + */ + @Test + public void cect_11_2_15_6_SystemAudioModeOffBeforeStandby() throws Exception { + try { + getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP"); + sendSystemAudioModeInitiation(); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); + getDevice().executeShellCommand("input keyevent KEYCODE_SLEEP"); + message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(OFF); + } finally { + getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP"); + } + } + + /** + * Test 11.2.15-7 + * Tests that the device responds correctly to a <Give System Audio Mode Status> + * message when the System Audio Mode is "Off". + */ + @Test + public void cect_11_2_15_7_SystemAudioModeStatusOff() throws Exception { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.SET_SYSTEM_AUDIO_MODE, CecMessage.formatParams(OFF)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, + CecOperand.SYSTEM_AUDIO_MODE_STATUS); + assertThat(CecMessage.getParams(message)).isEqualTo(OFF); + } + + /** + * Test 11.2.15-8 + * Tests that the device handles <User Controlled Pressed> ["Mute"] + * correctly when System Audio Mode is "On". + */ + @Test + public void cect_11_2_15_8_HandleUcpMute() throws Exception { + unmuteDevice(); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.SYSTEM_AUDIO_MODE_REQUEST, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, AUDIO_DEVICE, + HdmiCecConstants.CEC_CONTROL_MUTE, false); + assertWithMessage("Device is not muted").that(isDeviceMuted()).isTrue(); + } + + /** + * Test 11.2.15-9 + * Tests that the DUT responds with a <Report Audio Status> message with correct parameters + * to a <Give Audio Status> message when volume is set to 0% and not muted. + */ + @Test + public void cect_11_2_15_9_ReportAudioStatus_0_unmuted() throws Exception { + sendSystemAudioModeInitiation(); + unmuteDevice(); + setDeviceVolume(0); + int reportedVolume = getDutAudioStatus(); + assertThat(reportedVolume).isEqualTo(0); + } + + /** + * Test 11.2.15-9 + * Tests that the DUT responds with a <Report Audio Status> message with correct parameters + * to a <Give Audio Status> message when volume is set to 50% and not muted. + */ + @Test + public void cect_11_2_15_9_ReportAudioStatus_50_unmuted() throws Exception { + sendSystemAudioModeInitiation(); + unmuteDevice(); + setDeviceVolume(50); + int reportedVolume = getDutAudioStatus(); + /* Allow for a range of volume, since the actual volume set will depend on the device's + volume resolution. */ + assertThat(reportedVolume).isIn(Range.closed(46, 54)); + } + + /** + * Test 11.2.15-9 + * Tests that the DUT responds with a <Report Audio Status> message with correct parameters + * to a <Give Audio Status> message when volume is set to 100% and not muted. + */ + @Test + public void cect_11_2_15_9_ReportAudioStatus_100_unmuted() throws Exception { + sendSystemAudioModeInitiation(); + unmuteDevice(); + setDeviceVolume(100); + int reportedVolume = getDutAudioStatus(); + assertThat(reportedVolume).isEqualTo(100); + } + + /** + * Test 11.2.15-9 + * Tests that the DUT responds with a <Report Audio Status> message with correct parameters + * to a <Give Audio Status> message when volume is muted. + */ + @Test + public void cect_11_2_15_9_ReportAudioStatusMuted() throws Exception { + sendSystemAudioModeInitiation(); + muteDevice(); + int reportedVolume = getDutAudioStatus(); + /* If device is muted, the 8th bit of CEC message parameters is set and the volume will + be greater than 127. */ + assertWithMessage("Device not muted").that(reportedVolume).isGreaterThan(127); + } + + /** + * Test 11.2.15-13 + * Tests that the device responds to a <Request Short Audio Descriptor> message with a + * <Report Short Audio Descriptor> message with only those audio descriptors that are supported. + */ + @Test + public void cect_11_2_15_13_ValidShortAudioDescriptor() throws Exception { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.REQUEST_SHORT_AUDIO_DESCRIPTOR, getRequestSadFormatsParams(true)); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, + CecOperand.REPORT_SHORT_AUDIO_DESCRIPTOR); + /* Each Short Audio Descriptor is 3 bytes long. In the first byte of the params, bits 3-6 + * will have the audio format. Bit 7 will always 0 for audio format defined in CEA-861-D. + * Bits 0-2 represent (Max number of channels - 1). Discard bits 0-2 and check for the + * format. + * Iterate the params by 3 bytes(6 nibbles) and extract only the first byte(2 nibbles). + */ + for (int i = 0; i < Math.min(mSupportedAudioFormats.size(), MAX_VALID_AUDIO_FORMATS); i++) { + int audioFormat = + CecMessage.getParams(message, 6 * i, 6 * i + 2) >>> 3; + assertWithMessage("Could not find audio format " + audioFormat) + .that(mSupportedAudioFormats).contains(audioFormat); + } + } + + /** + * Test 11.2.15-14 + * Tests that the device responds to a <Request Short Audio Descriptor> message with a + * <Feature Abort> [“Invalid Operand”] when a <Request Short Audio Descriptor> message is + * received with a single [Audio Format ID][Audio Format Code] pair that is not supported. + */ + @Test + public void cect_11_2_15_14_InvalidShortAudioDescriptor() throws Exception { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.REQUEST_SHORT_AUDIO_DESCRIPTOR, getRequestSadFormatsParams(false)); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.FEATURE_ABORT); + assertThat(CecOperand.getOperand(CecMessage.getParams(message, 2))) + .isEqualTo(CecOperand.REQUEST_SHORT_AUDIO_DESCRIPTOR); + assertThat(CecMessage.getParams(message, 2, 4)) + .isEqualTo(HdmiCecConstants.ABORT_INVALID_OPERAND); + } + + /** + * Test 11.2.15-16 + * Tests that the device unmute its volume when it broadcasts a + * <Set System Audio Mode> ["On"] message + */ + @Test + public void cect_11_2_15_16_UnmuteForSystemAudioRequestOn() throws Exception { + muteDevice(); + sendSystemAudioModeTermination(); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(OFF); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.SYSTEM_AUDIO_MODE_REQUEST, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); + assertWithMessage("Device muted").that(isDeviceMuted()).isFalse(); + } + + /** + * Test 11.2.15-17 + * Tests that the device mute its volume when it broadcasts a + * <Set System Audio Mode> ["Off"] message + */ + @Test + public void cect_11_2_15_17_MuteForSystemAudioRequestOff() throws Exception { + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, + CecOperand.SYSTEM_AUDIO_MODE_REQUEST, + CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS, + HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH)); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); + sendSystemAudioModeTermination(); + message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE); + assertThat(CecMessage.getParams(message)).isEqualTo(OFF); + assertWithMessage("Device not muted").that(isDeviceMuted()).isTrue(); + } + + /** + * Test 11.2.15-18 + * Tests that the device doesn't broadcast <Set System Audio Mode> + * messages if TV responds with a <Feature Abort> message to directly addressed + * <Set System Audio Mode> message within the required maximum response time of 1 second. + */ + @Test + public void cect_11_2_15_18_SystemAudioModeWithFeatureAbortWithinTime() throws Exception { + initiateSystemAudioModeFromDut(); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, CecOperand.FEATURE_ABORT, + CecMessage.formatParams(CecOperand.SET_SYSTEM_AUDIO_MODE + "04")); + hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.BROADCAST, + CecOperand.SET_SYSTEM_AUDIO_MODE); + } + + /** + * Test 11.2.15-19 + * Tests that the device doesn't broadcast <Set System Audio Mode> + * messages if TV responds with a <Feature Abort> message to directly addressed + * <Set System Audio Mode> message within the required maximum response time of 1 second. + * The <Set System Audio Mode> message should be initiated from logical address 3. + */ + @Test + public void cect_11_2_15_19_SystemAudioModeWithFeatureAbortWithinTime() throws Exception { + initateSystemAudioModeFromTuner(); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, CecOperand.FEATURE_ABORT, + CecMessage.formatParams(CecOperand.SET_SYSTEM_AUDIO_MODE + "04")); + hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.BROADCAST, + CecOperand.SET_SYSTEM_AUDIO_MODE); } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecDeviceTypeTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecDeviceTypeTest.java new file mode 100644 index 00000000000..4c716cceb4b --- /dev/null +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecDeviceTypeTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.cts.common; + +import static com.google.common.truth.Truth.assertThat; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +/** Tests to see that a valid HDMI CEC device type is declared by the device. */ +@RunWith(DeviceJUnit4ClassRunner.class) +public final class HdmiCecDeviceTypeTest extends BaseHostJUnit4Test { + + private static List<String> validTypes = new ArrayList<>( + Arrays.asList("", "0", "4", "4,5", "5,4")); + /** + * Tests that the device declares a valid HDMI CEC device type. + */ + @Test + public void checkHdmiCecDeviceType() throws Exception { + ITestDevice device = getDevice(); + String logs = device.executeShellCommand("cmd package list features"); + Scanner in = new Scanner(logs); + while (in.hasNextLine()) { + String line = in.nextLine(); + if (line.equals("feature:android.software.leanback")) { + // Remove "" as valid device type if android.software.leanback feature is supported + validTypes.remove(""); + } + } + String deviceType = device.executeShellCommand("getprop ro.hdmi.device_type"); + assertThat(deviceType.trim()).isIn(validTypes); + } +} diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceOsdNameTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceOsdNameTest.java index cda29512f7f..ef1042596df 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceOsdNameTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecDeviceOsdNameTest.java @@ -16,28 +16,42 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; /** HDMI CEC tests related to the device reporting the device OSD name (Section 11.2.11) */ @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecDeviceOsdNameTest extends BaseHostJUnit4Test { - private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1; + + private static final LogicalAddress PLAYBACK_DEVICE = LogicalAddress.PLAYBACK_1; + + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + LogicalAddress.PLAYBACK_1.getDeviceType())) + .around(hdmiCecClient); /** * Test 11.2.11-1a @@ -53,9 +67,9 @@ public final class HdmiCecDeviceOsdNameTest extends BaseHostJUnit4Test { if (deviceName.length() > nameLength) { deviceName = deviceName.substring(0, nameLength).trim(); } - hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_OSD_NAME); - String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, CecMessage.SET_OSD_NAME); - assertEquals(deviceName, hdmiCecClient.getAsciiStringFromMessage(message)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.GIVE_OSD_NAME); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.SET_OSD_NAME); + assertThat(CecMessage.getAsciiString(message)).isEqualTo(deviceName); } /** @@ -70,10 +84,10 @@ public final class HdmiCecDeviceOsdNameTest extends BaseHostJUnit4Test { String originalName = device.executeShellCommand("settings get global device_name").trim(); try { device.executeShellCommand("settings put global device_name '" + testName + "'"); - hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_OSD_NAME); - String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, - CecMessage.SET_OSD_NAME); - assertEquals(testName, hdmiCecClient.getAsciiStringFromMessage(message)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.GIVE_OSD_NAME); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, + CecOperand.SET_OSD_NAME); + assertThat(CecMessage.getAsciiString(message)).isEqualTo(testName); } finally { device.executeShellCommand("settings put global device_name '" + originalName + "'"); } @@ -85,11 +99,11 @@ public final class HdmiCecDeviceOsdNameTest extends BaseHostJUnit4Test { */ @Test public void cect_11_2_11_2_UnregisteredDeviceGiveOsdNameTest() throws Exception { - hdmiCecClient.sendCecMessage(CecDevice.PLAYBACK_1, CecMessage.GIVE_OSD_NAME); - hdmiCecClient.checkOutputDoesNotContainMessage(CecDevice.PLAYBACK_1, - CecMessage.SET_OSD_NAME); - hdmiCecClient.sendCecMessage(CecDevice.BROADCAST, CecMessage.GIVE_OSD_NAME); - hdmiCecClient.checkOutputDoesNotContainMessage(CecDevice.BROADCAST, - CecMessage.SET_OSD_NAME); + hdmiCecClient.sendCecMessage(LogicalAddress.PLAYBACK_1, CecOperand.GIVE_OSD_NAME); + hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.PLAYBACK_1, + CecOperand.SET_OSD_NAME); + hdmiCecClient.sendCecMessage(LogicalAddress.BROADCAST, CecOperand.GIVE_OSD_NAME); + hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.BROADCAST, + CecOperand.SET_OSD_NAME); } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecLogicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecLogicalAddressTest.java index 83c9120d0ac..d48a6cd8b56 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecLogicalAddressTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecLogicalAddressTest.java @@ -16,29 +16,43 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; /** HDMI CEC test to verify physical address after device reboot (Section 10.2.3) */ @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecLogicalAddressTest extends BaseHostJUnit4Test { - private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1; + + private static final LogicalAddress PLAYBACK_DEVICE = LogicalAddress.PLAYBACK_1; + + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + LogicalAddress.PLAYBACK_1.getDeviceType())) + .around(hdmiCecClient); /** * Test 10.2.3-1 @@ -50,7 +64,7 @@ public final class HdmiCecLogicalAddressTest extends BaseHostJUnit4Test { ITestDevice device = getDevice(); device.executeShellCommand("reboot"); device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS); - assertEquals(PLAYBACK_DEVICE, hdmiCecClient.getSourceFromMessage(message)); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS); + assertThat(CecMessage.getSource(message)).isEqualTo(PLAYBACK_DEVICE); } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecOneTouchPlayTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecOneTouchPlayTest.java index a4ca3d246f6..56a7df25381 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecOneTouchPlayTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecOneTouchPlayTest.java @@ -16,17 +16,21 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; @@ -36,9 +40,32 @@ public final class HdmiCecOneTouchPlayTest extends BaseHostJUnit4Test { private static final int PHYSICAL_ADDRESS = 0x1000; + /** Intent to launch the remote pairing activity */ + private static final String ACTION_CONNECT_INPUT_NORMAL = + "com.google.android.intent.action.CONNECT_INPUT"; + + /** Package name of the Settings app */ + private static final String SETTINGS_PACKAGE = + "com.android.tv.settings"; + + /** The command to broadcast an intent. */ + private static final String START_COMMAND = "am start -a "; + + /** The command to stop an app. */ + private static final String FORCE_STOP_COMMAND = "am force-stop "; + + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); + @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + LogicalAddress.PLAYBACK_1.getDeviceType())) + .around(hdmiCecClient); /** * Test 11.2.1-1 @@ -48,9 +75,25 @@ public final class HdmiCecOneTouchPlayTest extends BaseHostJUnit4Test { @Test public void cect_11_2_1_1_OneTouchPlay() throws Exception { ITestDevice device = getDevice(); + device.reboot(); device.executeShellCommand("input keyevent KEYCODE_HOME"); - hdmiCecClient.checkExpectedOutput(CecDevice.TV, CecMessage.TEXT_VIEW_ON); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.ACTIVE_SOURCE); - assertEquals(PHYSICAL_ADDRESS, hdmiCecClient.getParamsFromMessage(message)); + hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.TEXT_VIEW_ON); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.ACTIVE_SOURCE); + assertThat(CecMessage.getParams(message)).isEqualTo(PHYSICAL_ADDRESS); + } + + /** + * Tests that the device sends a <TEXT_VIEW_ON> when the pairing activity is started on + * device, followed by a <ACTIVE_SOURCE> message. + */ + @Test + public void cect_PairingActivity_OneTouchPlay() throws Exception { + ITestDevice device = getDevice(); + device.reboot(); + device.executeShellCommand(START_COMMAND + ACTION_CONNECT_INPUT_NORMAL); + hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.TEXT_VIEW_ON); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.ACTIVE_SOURCE); + assertThat(CecMessage.getParams(message)).isEqualTo(PHYSICAL_ADDRESS); + device.executeShellCommand(FORCE_STOP_COMMAND + SETTINGS_PACKAGE); } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPhysicalAddressTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPhysicalAddressTest.java index 91280e7204b..bae84906ef0 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPhysicalAddressTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPhysicalAddressTest.java @@ -16,18 +16,22 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; @@ -35,9 +39,18 @@ import org.junit.Test; @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecPhysicalAddressTest extends BaseHostJUnit4Test { + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); + @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + LogicalAddress.PLAYBACK_1.getDeviceType())) + .around(hdmiCecClient); /** * Test 10.1.2-1 @@ -49,9 +62,9 @@ public final class HdmiCecPhysicalAddressTest extends BaseHostJUnit4Test { ITestDevice device = getDevice(); device.executeShellCommand("reboot"); device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS); - int physicalAddress = hdmiCecClient.getParamsFromMessage(message, + String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS); + int physicalAddress = CecMessage.getParams(message, HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH); - assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, physicalAddress); + assertThat(HdmiCecConstants.PHYSICAL_ADDRESS).isEqualTo(physicalAddress); } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java index 911d2335846..2d8d3ac7313 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java @@ -16,18 +16,22 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; @@ -39,12 +43,24 @@ public final class HdmiCecPowerStatusTest extends BaseHostJUnit4Test { private static final int ON = 0x0; private static final int OFF = 0x1; + private static final int IN_TRANSITION_TO_STANDBY = 0x3; + private static final int SLEEP_TIMESTEP_SECONDS = 1; private static final int WAIT_TIME = 5; + private static final int MAX_SLEEP_TIME = 8; + + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + LogicalAddress.PLAYBACK_1.getDeviceType())) + .around(hdmiCecClient); /** * Test 11.2.14-1 @@ -56,10 +72,10 @@ public final class HdmiCecPowerStatusTest extends BaseHostJUnit4Test { ITestDevice device = getDevice(); /* Make sure the device is not booting up/in standby */ device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); - hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS); - String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, - CecMessage.REPORT_POWER_STATUS); - assertEquals(ON, hdmiCecClient.getParamsFromMessage(message)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, + CecOperand.REPORT_POWER_STATUS); + assertThat(CecMessage.getParams(message)).isEqualTo(ON); } /** @@ -73,12 +89,20 @@ public final class HdmiCecPowerStatusTest extends BaseHostJUnit4Test { try { /* Make sure the device is not booting up/in standby */ device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); + /* Home Key to prevent device from going to deep suspend state */ + device.executeShellCommand("input keyevent KEYCODE_HOME"); device.executeShellCommand("input keyevent KEYCODE_SLEEP"); TimeUnit.SECONDS.sleep(WAIT_TIME); - hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GIVE_POWER_STATUS); - String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, - CecMessage.REPORT_POWER_STATUS); - assertEquals(OFF, hdmiCecClient.getParamsFromMessage(message)); + int waitTimeSeconds = WAIT_TIME; + int powerStatus; + do { + TimeUnit.SECONDS.sleep(SLEEP_TIMESTEP_SECONDS); + waitTimeSeconds += SLEEP_TIMESTEP_SECONDS; + hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.GIVE_POWER_STATUS); + powerStatus = CecMessage.getParams(hdmiCecClient.checkExpectedOutput( + LogicalAddress.TV, CecOperand.REPORT_POWER_STATUS)); + } while (powerStatus == IN_TRANSITION_TO_STANDBY && waitTimeSeconds <= MAX_SLEEP_TIME); + assertThat(powerStatus).isEqualTo(OFF); } finally { /* Wake up the device */ device.executeShellCommand("input keyevent KEYCODE_WAKEUP"); diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java index 9ac7eaba6ba..b0d927dcb7b 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java @@ -16,23 +16,22 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; - -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogHelper; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; -import java.util.Scanner; -import java.util.concurrent.TimeUnit; - /** HDMI CEC test to check if the device reports power status correctly (Section 11.2.13) */ @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Test { @@ -55,29 +54,18 @@ public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Tes */ private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE); - private static final int WAIT_TIME = 10; + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); - - private void lookForLog(String expectedOut) throws Exception { - ITestDevice device = getDevice(); - TimeUnit.SECONDS.sleep(WAIT_TIME); - String logs = device.executeAdbCommand("logcat", "-v", "brief", "-d", CLASS + ":I", "*:S"); - // Search for string. - String testString = ""; - Scanner in = new Scanner(logs); - while (in.hasNextLine()) { - String line = in.nextLine(); - if(line.startsWith("I/" + CLASS)) { - testString = line.split(":")[1].trim(); - break; - } - } - device.executeAdbCommand("logcat", "-c"); - assertEquals(expectedOut, testString); - } + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + LogicalAddress.PLAYBACK_1.getDeviceType())) + .around(hdmiCecClient); /** * Test 11.2.13-1 @@ -93,24 +81,25 @@ public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Tes device.executeAdbCommand("logcat", "-c"); // Start the APK and wait for it to complete. device.executeShellCommand(START_COMMAND); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_UP, false); - lookForLog("Short press KEYCODE_DPAD_UP"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_UP"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_DOWN, false); - lookForLog("Short press KEYCODE_DPAD_DOWN"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_DOWN"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_LEFT, false); - lookForLog("Short press KEYCODE_DPAD_LEFT"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_LEFT"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_RIGHT, false); - lookForLog("Short press KEYCODE_DPAD_RIGHT"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_DPAD_RIGHT"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_SELECT, false); - lookForLog("Short press KEYCODE_DPAD_CENTER"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, + "Short press KEYCODE_DPAD_CENTER", "Short press KEYCODE_ENTER"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_BACK, false); - lookForLog("Short press KEYCODE_BACK"); + LogHelper.assertLog(getDevice(), CLASS, "Short press KEYCODE_BACK"); } /** @@ -127,23 +116,24 @@ public final class HdmiCecRemoteControlPassThroughTest extends BaseHostJUnit4Tes device.executeAdbCommand("logcat", "-c"); // Start the APK and wait for it to complete. device.executeShellCommand(START_COMMAND); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_UP, true); - lookForLog("Long press KEYCODE_DPAD_UP"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_UP"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_DOWN, true); - lookForLog("Long press KEYCODE_DPAD_DOWN"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_DOWN"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_LEFT, true); - lookForLog("Long press KEYCODE_DPAD_LEFT"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_LEFT"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_RIGHT, true); - lookForLog("Long press KEYCODE_DPAD_RIGHT"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_DPAD_RIGHT"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_SELECT, true); - lookForLog("Long press KEYCODE_DPAD_CENTER"); - hdmiCecClient.sendUserControlPressAndRelease(CecDevice.TV, CecDevice.PLAYBACK_1, + LogHelper.assertLog(getDevice(), CLASS, + "Long press KEYCODE_DPAD_CENTER", "Long press KEYCODE_ENTER"); + hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, LogicalAddress.PLAYBACK_1, HdmiCecConstants.CEC_CONTROL_BACK, true); - lookForLog("Long press KEYCODE_BACK"); + LogHelper.assertLog(getDevice(), CLASS, "Long press KEYCODE_BACK"); } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java index 4fd2a8968ce..8bec365451a 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java @@ -16,18 +16,22 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; @@ -39,9 +43,18 @@ public final class HdmiCecRoutingControlTest extends BaseHostJUnit4Test { private static final int PHYSICAL_ADDRESS = 0x1000; + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); + @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + LogicalAddress.PLAYBACK_1.getDeviceType())) + .around(hdmiCecClient); /** * Test 11.2.2-1 @@ -52,15 +65,14 @@ public final class HdmiCecRoutingControlTest extends BaseHostJUnit4Test { public void cect_11_2_2_1_SetStreamPathToDut() throws Exception { final long hdmi2Address = 0x2000; /* Switch to HDMI2. Setup assumes DUT is connected to HDMI1. */ - hdmiCecClient.sendCecMessage(CecDevice.PLAYBACK_2, CecDevice.BROADCAST, - CecMessage.ACTIVE_SOURCE, hdmiCecClient.formatParams(hdmi2Address)); + hdmiCecClient.sendCecMessage(LogicalAddress.PLAYBACK_2, LogicalAddress.BROADCAST, + CecOperand.ACTIVE_SOURCE, CecMessage.formatParams(hdmi2Address)); TimeUnit.SECONDS.sleep(3); - hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST, - CecMessage.SET_STREAM_PATH, - hdmiCecClient.formatParams(HdmiCecConstants.PHYSICAL_ADDRESS)); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.ACTIVE_SOURCE); - assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, - hdmiCecClient.getParamsFromMessage(message)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, + CecOperand.SET_STREAM_PATH, + CecMessage.formatParams(HdmiCecConstants.PHYSICAL_ADDRESS)); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.ACTIVE_SOURCE); + assertThat(CecMessage.getParams(message)).isEqualTo(PHYSICAL_ADDRESS); } /** @@ -72,10 +84,10 @@ public final class HdmiCecRoutingControlTest extends BaseHostJUnit4Test { public void cect_11_2_2_2_RequestActiveSource() throws Exception { ITestDevice device = getDevice(); device.executeShellCommand("input keyevent KEYCODE_HOME"); - hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST, - CecMessage.REQUEST_ACTIVE_SOURCE); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.ACTIVE_SOURCE); - assertEquals(PHYSICAL_ADDRESS, hdmiCecClient.getParamsFromMessage(message)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, + CecOperand.REQUEST_ACTIVE_SOURCE); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.ACTIVE_SOURCE); + assertThat(CecMessage.getParams(message)).isEqualTo(PHYSICAL_ADDRESS); } /** @@ -89,10 +101,9 @@ public final class HdmiCecRoutingControlTest extends BaseHostJUnit4Test { try { device.executeShellCommand("input keyevent KEYCODE_HOME"); device.executeShellCommand("input keyevent KEYCODE_SLEEP"); - String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, - CecMessage.INACTIVE_SOURCE); - assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, - hdmiCecClient.getParamsFromMessage(message)); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, + CecOperand.INACTIVE_SOURCE); + assertThat(CecMessage.getParams(message)).isEqualTo(PHYSICAL_ADDRESS); } finally { /* Wake up the device */ device.executeShellCommand("input keyevent KEYCODE_WAKEUP"); diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStartupTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStartupTest.java new file mode 100644 index 00000000000..06b62f93b3a --- /dev/null +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStartupTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hdmicec.cts.playback; + +import static com.google.common.collect.Iterables.filter; +import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assume.assumeTrue; + +import android.hdmicec.cts.CecOperand; +import android.hdmicec.cts.HdmiCecClientWrapper; +import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; + +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; +import javax.annotation.Nullable; +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.runner.RunWith; +import org.junit.Test; + +import java.util.List; + +/** + * HDMI CEC test to verify physical address after device reboot (Section 10.2.3) + */ +@RunWith(DeviceJUnit4ClassRunner.class) +public final class HdmiCecStartupTest extends BaseHostJUnit4Test { + + private static final LogicalAddress PLAYBACK_DEVICE = LogicalAddress.PLAYBACK_1; + private static final ImmutableList<CecOperand> necessaryMessages = + new ImmutableList.Builder<CecOperand>() + .add(CecOperand.REPORT_PHYSICAL_ADDRESS, CecOperand.CEC_VERSION, + CecOperand.DEVICE_VENDOR_ID, CecOperand.GIVE_POWER_STATUS).build(); + private static final ImmutableList<CecOperand> permissibleMessages = + new ImmutableList.Builder<CecOperand>() + .add(CecOperand.VENDOR_COMMAND, CecOperand.GIVE_DEVICE_VENDOR_ID, + CecOperand.SET_OSD_NAME, CecOperand.GIVE_OSD_NAME).build(); + + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); + + @Rule + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + PLAYBACK_DEVICE.getDeviceType())) + .around(hdmiCecClient); + + /** + * Tests that the device sends all the messages that should be sent on startup. It also ensures + * that only the device only sends messages which are allowed by the spec. + */ + @Test + public void cectVerifyStartupMessages() throws Exception { + ITestDevice device = getDevice(); + + /* Make sure device is playback only. Not applicable to playback/audio combinations */ + String deviceTypeCsv = device.executeShellCommand("getprop ro.hdmi.device_type").trim(); + assumeTrue(deviceTypeCsv.equals(LogicalAddress.PLAYBACK_1.getDeviceType())); + + device.executeShellCommand("reboot"); + device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); + /* Monitor CEC messages for 20s after reboot */ + final List<CecOperand> messagesReceived = + hdmiCecClient.getAllMessages(LogicalAddress.PLAYBACK_1, 20); + + /* Predicate to apply on necessaryMessages to ensure that all necessaryMessages are received. */ + final Predicate<CecOperand> notReceived = new Predicate<CecOperand>() { + @Override + public boolean apply(@Nullable CecOperand cecOperand) { + return !messagesReceived.contains(cecOperand); + } + }; + + /* Predicate to apply on messagesReceived to ensure all messages received are permissible. */ + final Predicate<CecOperand> notAllowed = new Predicate<CecOperand>() { + @Override + public boolean apply(@Nullable CecOperand cecOperand) { + return !(permissibleMessages.contains(cecOperand) || necessaryMessages.contains(cecOperand)); + } + }; + + assertWithMessage("Some necessary messages are missing"). + that(filter(necessaryMessages, notReceived)).isEmpty(); + + assertWithMessage("Some non-permissible messages received"). + that(filter(messagesReceived, notAllowed)).isEmpty(); + } +} diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java index 5162a271490..229e807671c 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemAudioControlTest.java @@ -16,31 +16,44 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; -import java.util.concurrent.TimeUnit; - /** HDMI CEC test to verify system audio control commands (Section 11.2.15) */ @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecSystemAudioControlTest extends BaseHostJUnit4Test { - private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1; - @Rule + private static final LogicalAddress PLAYBACK_DEVICE = LogicalAddress.PLAYBACK_1; + public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this, "-t", "a"); + new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1, "-t", "a"); + + @Rule + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + PLAYBACK_DEVICE.getDeviceType())) + .around(hdmiCecClient); /** * Test 11.2.15-10 @@ -49,10 +62,12 @@ public final class HdmiCecSystemAudioControlTest extends BaseHostJUnit4Test { @Test public void cect_11_2_15_10_GiveSystemAudioModeStatus() throws Exception { ITestDevice device = getDevice(); + /* Home Key to prevent device from going to deep suspend state */ + device.executeShellCommand("input keyevent KEYCODE_HOME"); device.executeShellCommand("input keyevent KEYCODE_SLEEP"); device.executeShellCommand("input keyevent KEYCODE_WAKEUP"); - hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, - CecMessage.GIVE_SYSTEM_AUDIO_MODE_STATUS); + hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, + CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS); } /** @@ -64,22 +79,22 @@ public final class HdmiCecSystemAudioControlTest extends BaseHostJUnit4Test { @Test public void cect_11_2_15_11_VolumeUpDownUserControlPressed() throws Exception { ITestDevice device = getDevice(); - hdmiCecClient.sendCecMessage(CecDevice.AUDIO_SYSTEM, CecDevice.BROADCAST, - CecMessage.SET_SYSTEM_AUDIO_MODE, CecMessage.formatParams(1)); + hdmiCecClient.sendCecMessage(LogicalAddress.AUDIO_SYSTEM, LogicalAddress.BROADCAST, + CecOperand.SET_SYSTEM_AUDIO_MODE, CecMessage.formatParams(1)); device.executeShellCommand("input keyevent KEYCODE_VOLUME_UP"); - String message = hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, - CecMessage.USER_CONTROL_PRESSED); - assertEquals(HdmiCecConstants.CEC_CONTROL_VOLUME_UP, - hdmiCecClient.getParamsFromMessage(message)); - hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, CecMessage.USER_CONTROL_RELEASED); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, + CecOperand.USER_CONTROL_PRESSED); + assertThat(CecMessage.getParams(message)) + .isEqualTo(HdmiCecConstants.CEC_CONTROL_VOLUME_UP); + hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, CecOperand.USER_CONTROL_RELEASED); device.executeShellCommand("input keyevent KEYCODE_VOLUME_DOWN"); - message = hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, - CecMessage.USER_CONTROL_PRESSED); - assertEquals(HdmiCecConstants.CEC_CONTROL_VOLUME_DOWN, - hdmiCecClient.getParamsFromMessage(message)); - hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, CecMessage.USER_CONTROL_RELEASED); + message = hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, + CecOperand.USER_CONTROL_PRESSED); + assertThat(CecMessage.getParams(message)) + .isEqualTo(HdmiCecConstants.CEC_CONTROL_VOLUME_DOWN); + hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, CecOperand.USER_CONTROL_RELEASED); } /** @@ -91,13 +106,12 @@ public final class HdmiCecSystemAudioControlTest extends BaseHostJUnit4Test { @Test public void cect_11_2_15_12_MuteUserControlPressed() throws Exception { ITestDevice device = getDevice(); - hdmiCecClient.sendCecMessage(CecDevice.AUDIO_SYSTEM, CecDevice.BROADCAST, - CecMessage.SET_SYSTEM_AUDIO_MODE, CecMessage.formatParams(1)); + hdmiCecClient.sendCecMessage(LogicalAddress.AUDIO_SYSTEM, LogicalAddress.BROADCAST, + CecOperand.SET_SYSTEM_AUDIO_MODE, CecMessage.formatParams(1)); device.executeShellCommand("input keyevent KEYCODE_VOLUME_MUTE"); - String message = hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, - CecMessage.USER_CONTROL_PRESSED); - assertEquals(HdmiCecConstants.CEC_CONTROL_MUTE, - hdmiCecClient.getParamsFromMessage(message)); - hdmiCecClient.checkExpectedOutput(CecDevice.AUDIO_SYSTEM, CecMessage.USER_CONTROL_RELEASED); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, + CecOperand.USER_CONTROL_PRESSED); + assertThat(CecMessage.getParams(message)).isEqualTo(HdmiCecConstants.CEC_CONTROL_MUTE); + hdmiCecClient.checkExpectedOutput(LogicalAddress.AUDIO_SYSTEM, CecOperand.USER_CONTROL_RELEASED); } } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java index c6df9f7f0ca..5e59a8f4870 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java @@ -16,20 +16,25 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assume.assumeTrue; import android.hdmicec.cts.CecClientMessage; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; @@ -42,9 +47,18 @@ public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test { private static final String PROPERTY_LOCALE = "persist.sys.locale"; + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); + @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + LogicalAddress.PLAYBACK_1.getDeviceType())) + .around(hdmiCecClient); /** * Test 11.2.6-1 @@ -52,7 +66,7 @@ public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test { */ @Test public void cect_11_2_6_1_Ack() throws Exception { - String command = CecClientMessage.POLL + " " + CecDevice.PLAYBACK_1; + String command = CecClientMessage.POLL + " " + LogicalAddress.PLAYBACK_1; String expectedOutput = "POLL sent"; hdmiCecClient.sendConsoleMessage(command); if (!hdmiCecClient.checkConsoleOutput(expectedOutput)) { @@ -67,13 +81,13 @@ public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test { */ @Test public void cect_11_2_6_2_GivePhysicalAddress() throws Exception { - hdmiCecClient.sendCecMessage(CecMessage.GIVE_PHYSICAL_ADDRESS); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.REPORT_PHYSICAL_ADDRESS); + hdmiCecClient.sendCecMessage(CecOperand.GIVE_PHYSICAL_ADDRESS); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS); /* The checkExpectedOutput has already verified the first 4 nibbles of the message. We * have to verify the last 6 nibbles */ - int receivedParams = hdmiCecClient.getParamsFromMessage(message); - assertEquals(HdmiCecConstants.PHYSICAL_ADDRESS, receivedParams >> 8); - assertEquals(HdmiCecConstants.PLAYBACK_DEVICE_TYPE, receivedParams & 0xFF); + int receivedParams = CecMessage.getParams(message); + assertThat(HdmiCecConstants.PHYSICAL_ADDRESS).isEqualTo(receivedParams >> 8); + assertThat(HdmiCecConstants.PLAYBACK_DEVICE_TYPE).isEqualTo(receivedParams & 0xFF); } /** @@ -82,11 +96,10 @@ public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test { */ @Test public void cect_11_2_6_6_GiveCecVersion() throws Exception { - hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GET_CEC_VERSION); - String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, - CecMessage.CEC_VERSION); - - assertEquals(CEC_VERSION_NUMBER, hdmiCecClient.getParamsFromMessage(message)); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.GET_CEC_VERSION); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, + CecOperand.CEC_VERSION); + assertThat(CecMessage.getParams(message)).isEqualTo(CEC_VERSION_NUMBER); } /** @@ -95,11 +108,11 @@ public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test { */ @Test public void cect_11_2_6_7_GetMenuLanguage() throws Exception { - hdmiCecClient.sendCecMessage(CecDevice.TV, CecMessage.GET_MENU_LANGUAGE); - String message = hdmiCecClient.checkExpectedOutput(CecDevice.TV, CecMessage.FEATURE_ABORT); - int abortedOpcode = hdmiCecClient.getParamsFromMessage(message, - CecMessage.GET_MENU_LANGUAGE.toString().length()); - assertEquals(CecMessage.getMessage(abortedOpcode), CecMessage.GET_MENU_LANGUAGE); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.GET_MENU_LANGUAGE); + String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.FEATURE_ABORT); + int abortedOpcode = CecMessage.getParams(message, + CecOperand.GET_MENU_LANGUAGE.toString().length()); + assertThat(CecOperand.getOperand(abortedOpcode)).isEqualTo(CecOperand.GET_MENU_LANGUAGE); } private String getSystemLocale() throws Exception { @@ -133,9 +146,9 @@ public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test { final String language = originalLanguage.equals("spa") ? "eng" : "spa"; final String newLanguage = originalLanguage.equals("spa") ? "en" : "es"; try { - hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST, - CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language)); - assertEquals(newLanguage, extractLanguage(getSystemLocale())); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, + CecOperand.SET_MENU_LANGUAGE, CecMessage.convertStringToHexParams(language)); + assertThat(extractLanguage(getSystemLocale())).isEqualTo(newLanguage); } finally { setSystemLocale(locale); } @@ -152,9 +165,9 @@ public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test { final String originalLanguage = extractLanguage(locale); final String language = "spb"; try { - hdmiCecClient.sendCecMessage(CecDevice.TV, CecDevice.BROADCAST, - CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language)); - assertEquals(originalLanguage, extractLanguage(getSystemLocale())); + hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, + CecOperand.SET_MENU_LANGUAGE, CecMessage.convertStringToHexParams(language)); + assertThat(extractLanguage(getSystemLocale())).isEqualTo(originalLanguage); } finally { setSystemLocale(locale); } @@ -172,9 +185,9 @@ public final class HdmiCecSystemInformationTest extends BaseHostJUnit4Test { final String originalLanguage = extractLanguage(locale); final String language = originalLanguage.equals("spa") ? "eng" : "spa"; try { - hdmiCecClient.sendCecMessage(CecDevice.RECORDER_1, CecDevice.BROADCAST, - CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language)); - assertEquals(originalLanguage, extractLanguage(getSystemLocale())); + hdmiCecClient.sendCecMessage(LogicalAddress.RECORDER_1, LogicalAddress.BROADCAST, + CecOperand.SET_MENU_LANGUAGE, CecMessage.convertStringToHexParams(language)); + assertThat(extractLanguage(getSystemLocale())).isEqualTo(originalLanguage); } finally { setSystemLocale(locale); } diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemStandbyTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemStandbyTest.java index 1aa8fe47f2d..369542e3138 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemStandbyTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemStandbyTest.java @@ -16,20 +16,21 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; -import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; -import com.android.tradefed.device.TestDeviceState; -import com.android.tradefed.log.LogUtil.CLog; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; @@ -38,14 +39,24 @@ import java.util.concurrent.TimeUnit; /** HDMI CEC test to verify the device handles standby correctly (Section 11.2.3) */ @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecSystemStandbyTest extends BaseHostJUnit4Test { - private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1; + + private static final LogicalAddress PLAYBACK_DEVICE = LogicalAddress.PLAYBACK_1; private static final String HDMI_CONTROL_DEVICE_AUTO_OFF = "hdmi_control_auto_device_off_enabled"; + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); + @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + PLAYBACK_DEVICE.getDeviceType())) + .around(hdmiCecClient); private boolean setHdmiControlDeviceAutoOff(boolean turnOn) throws Exception { ITestDevice device = getDevice(); @@ -58,16 +69,16 @@ public final class HdmiCecSystemStandbyTest extends BaseHostJUnit4Test { return val.equals("1") ? true : false; } - private void checkDeviceAsleepAfterStandbySent(CecDevice source, CecDevice destination) + private void checkDeviceAsleepAfterStandbySent(LogicalAddress source, LogicalAddress destination) throws Exception { ITestDevice device = getDevice(); try { device.executeShellCommand("input keyevent KEYCODE_HOME"); TimeUnit.SECONDS.sleep(5); - hdmiCecClient.sendCecMessage(source, destination, CecMessage.STANDBY); + hdmiCecClient.sendCecMessage(source, destination, CecOperand.STANDBY); TimeUnit.SECONDS.sleep(5); String wakeState = device.executeShellCommand("dumpsys power | grep mWakefulness="); - assertEquals("mWakefulness=Asleep", wakeState.trim()); + assertThat(wakeState.trim()).isEqualTo("mWakefulness=Asleep"); } finally { /* Wake up the device */ device.executeShellCommand("input keyevent KEYCODE_WAKEUP"); @@ -84,19 +95,19 @@ public final class HdmiCecSystemStandbyTest extends BaseHostJUnit4Test { getDevice().waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); try { TimeUnit.SECONDS.sleep(5); - checkDeviceAsleepAfterStandbySent(CecDevice.TV, CecDevice.BROADCAST); + checkDeviceAsleepAfterStandbySent(LogicalAddress.TV, LogicalAddress.BROADCAST); /* Wake up the TV */ - hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV); - checkDeviceAsleepAfterStandbySent(CecDevice.RECORDER_1, CecDevice.BROADCAST); + hdmiCecClient.sendConsoleMessage("on " + LogicalAddress.TV); + checkDeviceAsleepAfterStandbySent(LogicalAddress.RECORDER_1, LogicalAddress.BROADCAST); /* Wake up the TV */ - hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV); - checkDeviceAsleepAfterStandbySent(CecDevice.AUDIO_SYSTEM, CecDevice.BROADCAST); + hdmiCecClient.sendConsoleMessage("on " + LogicalAddress.TV); + checkDeviceAsleepAfterStandbySent(LogicalAddress.AUDIO_SYSTEM, LogicalAddress.BROADCAST); /* Wake up the TV */ - hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV); - checkDeviceAsleepAfterStandbySent(CecDevice.PLAYBACK_2, CecDevice.BROADCAST); + hdmiCecClient.sendConsoleMessage("on " + LogicalAddress.TV); + checkDeviceAsleepAfterStandbySent(LogicalAddress.PLAYBACK_2, LogicalAddress.BROADCAST); } finally { /* Wake up the TV */ - hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV); + hdmiCecClient.sendConsoleMessage("on " + LogicalAddress.TV); } } @@ -108,11 +119,11 @@ public final class HdmiCecSystemStandbyTest extends BaseHostJUnit4Test { public void cect_11_2_3_3_HandleAddressedStandby() throws Exception { getDevice().executeShellCommand("reboot"); getDevice().waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); - checkDeviceAsleepAfterStandbySent(CecDevice.TV, CecDevice.PLAYBACK_1); - checkDeviceAsleepAfterStandbySent(CecDevice.RECORDER_1, CecDevice.PLAYBACK_1); - checkDeviceAsleepAfterStandbySent(CecDevice.AUDIO_SYSTEM, CecDevice.PLAYBACK_1); - checkDeviceAsleepAfterStandbySent(CecDevice.PLAYBACK_2, CecDevice.PLAYBACK_1); - checkDeviceAsleepAfterStandbySent(CecDevice.BROADCAST, CecDevice.PLAYBACK_1); + checkDeviceAsleepAfterStandbySent(LogicalAddress.TV, LogicalAddress.PLAYBACK_1); + checkDeviceAsleepAfterStandbySent(LogicalAddress.RECORDER_1, LogicalAddress.PLAYBACK_1); + checkDeviceAsleepAfterStandbySent(LogicalAddress.AUDIO_SYSTEM, LogicalAddress.PLAYBACK_1); + checkDeviceAsleepAfterStandbySent(LogicalAddress.PLAYBACK_2, LogicalAddress.PLAYBACK_1); + checkDeviceAsleepAfterStandbySent(LogicalAddress.BROADCAST, LogicalAddress.PLAYBACK_1); } /** @@ -125,7 +136,7 @@ public final class HdmiCecSystemStandbyTest extends BaseHostJUnit4Test { boolean wasOn = setHdmiControlDeviceAutoOff(false); try { device.executeShellCommand("input keyevent KEYCODE_SLEEP"); - hdmiCecClient.checkOutputDoesNotContainMessage(CecDevice.BROADCAST, CecMessage.STANDBY); + hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.BROADCAST, CecOperand.STANDBY); device.executeShellCommand("input keyevent KEYCODE_WAKEUP"); } finally { setHdmiControlDeviceAutoOff(wasOn); diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecVendorCommandsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecVendorCommandsTest.java index df9bc5ae4e8..edff394ba38 100644 --- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecVendorCommandsTest.java +++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecVendorCommandsTest.java @@ -16,30 +16,44 @@ package android.hdmicec.cts.playback; -import static org.junit.Assert.assertNotEquals; +import static com.google.common.truth.Truth.assertThat; -import android.hdmicec.cts.CecDevice; import android.hdmicec.cts.CecMessage; +import android.hdmicec.cts.CecOperand; import android.hdmicec.cts.HdmiCecClientWrapper; import android.hdmicec.cts.HdmiCecConstants; +import android.hdmicec.cts.LogicalAddress; +import android.hdmicec.cts.RequiredPropertyRule; +import android.hdmicec.cts.RequiredFeatureRule; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.Rule; +import org.junit.rules.RuleChain; import org.junit.runner.RunWith; import org.junit.Test; /** HDMI CEC test to verify device vendor specific commands (Section 11.2.9) */ @RunWith(DeviceJUnit4ClassRunner.class) public final class HdmiCecVendorCommandsTest extends BaseHostJUnit4Test { - private static final CecDevice PLAYBACK_DEVICE = CecDevice.PLAYBACK_1; + + private static final LogicalAddress PLAYBACK_DEVICE = LogicalAddress.PLAYBACK_1; private static final int INCORRECT_VENDOR_ID = 0x0; + public HdmiCecClientWrapper hdmiCecClient = new HdmiCecClientWrapper(LogicalAddress.PLAYBACK_1); + @Rule - public HdmiCecClientWrapper hdmiCecClient = - new HdmiCecClientWrapper(CecDevice.PLAYBACK_1, this); + public RuleChain ruleChain = + RuleChain + .outerRule(new RequiredFeatureRule(this, LogicalAddress.HDMI_CEC_FEATURE)) + .around(new RequiredFeatureRule(this, LogicalAddress.LEANBACK_FEATURE)) + .around(RequiredPropertyRule.asCsvContainsValue( + this, + LogicalAddress.HDMI_DEVICE_TYPE_PROPERTY, + PLAYBACK_DEVICE.getDeviceType())) + .around(hdmiCecClient); /** * Test 11.2.9-1 @@ -48,10 +62,14 @@ public final class HdmiCecVendorCommandsTest extends BaseHostJUnit4Test { */ @Test public void cect_11_2_9_1_GiveDeviceVendorId() throws Exception { - for (CecDevice cecDevice : CecDevice.values()) { - hdmiCecClient.sendCecMessage(cecDevice, CecMessage.GIVE_DEVICE_VENDOR_ID); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.DEVICE_VENDOR_ID); - assertNotEquals(INCORRECT_VENDOR_ID, hdmiCecClient.getParamsFromMessage(message)); + for (LogicalAddress logicalAddress : LogicalAddress.values()) { + // Skip the logical address of this device + if (logicalAddress == PLAYBACK_DEVICE) { + continue; + } + hdmiCecClient.sendCecMessage(logicalAddress, CecOperand.GIVE_DEVICE_VENDOR_ID); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.DEVICE_VENDOR_ID); + assertThat(CecMessage.getParams(message)).isNotEqualTo(INCORRECT_VENDOR_ID); } } @@ -65,7 +83,7 @@ public final class HdmiCecVendorCommandsTest extends BaseHostJUnit4Test { ITestDevice device = getDevice(); device.executeShellCommand("reboot"); device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT); - String message = hdmiCecClient.checkExpectedOutput(CecMessage.DEVICE_VENDOR_ID); - assertNotEquals(INCORRECT_VENDOR_ID, hdmiCecClient.getParamsFromMessage(message)); + String message = hdmiCecClient.checkExpectedOutput(CecOperand.DEVICE_VENDOR_ID); + assertThat(CecMessage.getParams(message)).isNotEqualTo(INCORRECT_VENDOR_ID); } } |