Added CONFIG_HDMI_SOURCE.

Some tests are specific to HDMI source devices (e.g. OTT boxes) and
should not be run on HDMI sink devices (e.g. TV panels, phones). This
change introduces the CONFIG_HDMI_SOURCE value for the test_required_configs
metadata key.

Bug: 145499731
Test: manual
Change-Id: I5f32db915ac23d45fd57a04364b25a127c11e570
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 532ed68..4d46518 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -3197,6 +3197,8 @@
             <meta-data android:name="test_category" android:value="@string/test_category_tv" />
             <meta-data android:name="test_required_features"
                        android:value="android.software.leanback" />
+            <meta-data android:name="test_required_configs"
+                       android:value="config_hdmi_source"/>
         </activity>
         <activity android:name=".tv.display.DisplayModesTestActivity"
                   android:label="@string/tv_display_modes_test"
@@ -3205,9 +3207,11 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
-            <meta-data android:name="test_category" android:value="@string/test_category_tv" />
+            <meta-data android:name="test_category" android:value="@string/test_category_tv"/>
             <meta-data android:name="test_required_features"
-                       android:value="android.software.leanback" />
+                       android:value="android.software.leanback"/>
+            <meta-data android:name="test_required_configs"
+                       android:value="config_hdmi_source"/>
         </activity>
 
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
index 47514b8..76019cb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
@@ -27,13 +27,17 @@
 import android.util.Log;
 import android.widget.ListView;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * {@link TestListAdapter} that populates the {@link TestListActivity}'s {@link ListView} by
@@ -89,6 +93,7 @@
  * </ol>
  */
 public class ManifestTestListAdapter extends TestListAdapter {
+    private static final String LOG_TAG = "ManifestTestListAdapter";
 
     private static final String TEST_CATEGORY_META_DATA = "test_category";
 
@@ -106,6 +111,8 @@
 
     private static final String CONFIG_HAS_RECENTS = "config_has_recents";
 
+    private static final String CONFIG_HDMI_SOURCE = "config_hdmi_source";
+
     private final HashSet<String> mDisabledTests;
 
     private Context mContext;
@@ -146,12 +153,7 @@
             List<TestListItem> tests = filterTests(testsByCategory.get(testCategory));
             if (!tests.isEmpty()) {
                 allRows.add(TestListItem.newCategory(testCategory));
-                Collections.sort(tests, new Comparator<TestListItem>() {
-                    @Override
-                    public int compare(TestListItem item, TestListItem otherItem) {
-                        return item.title.compareTo(otherItem.title);
-                    }
-                });
+                Collections.sort(tests, Comparator.comparing(item -> item.title));
                 allRows.addAll(tests);
             }
         }
@@ -168,7 +170,7 @@
                 PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
         int size = list.size();
 
-        List<ResolveInfo> matchingList = new ArrayList<ResolveInfo>();
+        List<ResolveInfo> matchingList = new ArrayList<>();
         for (int i = 0; i < size; i++) {
             ResolveInfo info = list.get(i);
             String parent = getTestParent(info.activityInfo.metaData);
@@ -181,14 +183,13 @@
     }
 
     Map<String, List<TestListItem>> getTestsByCategory(List<ResolveInfo> list) {
-        Map<String, List<TestListItem>> testsByCategory =
-                new HashMap<String, List<TestListItem>>();
+        Map<String, List<TestListItem>> testsByCategory = new HashMap<>();
 
         int size = list.size();
         for (int i = 0; i < size; i++) {
             ResolveInfo info = list.get(i);
             if (info.activityInfo == null || mDisabledTests.contains(info.activityInfo.name)) {
-                Log.w("CtsVerifier", "ignoring disabled test: " + info.activityInfo.name);
+                Log.w(LOG_TAG, "ignoring disabled test: " + info.activityInfo.name);
                 continue;
             }
             String title = getTitle(mContext, info.activityInfo);
@@ -345,6 +346,19 @@
                             return false;
                         }
                         break;
+                    case CONFIG_HDMI_SOURCE:
+                        final int DEVICE_TYPE_HDMI_SOURCE = 4;
+                        try {
+                            if (!getHdmiDeviceType().contains(DEVICE_TYPE_HDMI_SOURCE)) {
+                                return false;
+                            }
+                        } catch (Exception exception) {
+                            Log.e(
+                                    LOG_TAG,
+                                    "Exception while looking up HDMI device type.",
+                                    exception);
+                        }
+                        break;
                     default:
                         break;
                 }
@@ -353,8 +367,24 @@
         return true;
     }
 
+    private static List<Integer> getHdmiDeviceType()
+            throws InvocationTargetException, IllegalAccessException, ClassNotFoundException,
+                    NoSuchMethodException {
+        Method getStringMethod =
+                ClassLoader.getSystemClassLoader()
+                        .loadClass("android.os.SystemProperties")
+                        .getMethod("get", String.class);
+        String deviceTypesStr = (String) getStringMethod.invoke(null, "ro.hdmi.device_type");
+        if (deviceTypesStr.equals("")) {
+            return new ArrayList<>();
+        }
+        return Arrays.stream(deviceTypesStr.split(","))
+                .map(Integer::parseInt)
+                .collect(Collectors.toList());
+    }
+
     List<TestListItem> filterTests(List<TestListItem> tests) {
-        List<TestListItem> filteredTests = new ArrayList<TestListItem>();
+        List<TestListItem> filteredTests = new ArrayList<>();
         for (TestListItem test : tests) {
             if (!hasAnyFeature(test.excludedFeatures) && hasAllFeatures(test.requiredFeatures)
                     && matchAllConfigs(test.requiredConfigs)) {