Loosening matching criteria to subset matching instead of exact matching.

Bug: 63174999

Test: Manual.

Change-Id: I53ee12c4425a88ce0e5c5cbb2fbcf9c2f04c11f4
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralAttributesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralAttributesActivity.java
index 6ed38e3..83e68e4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralAttributesActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralAttributesActivity.java
@@ -62,30 +62,55 @@
                     mSelectedProfile.getOutputAttributes();
                 StringBuilder sb = new StringBuilder();
 
-                if (!ListsHelper.isMatch(deviceInfo.getChannelCounts(), attribs.mChannelCounts)) {
+                // Channel Counts
+                if (deviceInfo.getChannelCounts().length == 0) {
+                    sb.append("Output - No Peripheral Channel Counts\n");
+                } else if (!ListsHelper.isSubset(deviceInfo.getChannelCounts(), attribs.mChannelCounts)) {
                     sb.append("Output - Channel Counts Mismatch\n");
                 }
-                if (!ListsHelper.isMatch(deviceInfo.getChannelIndexMasks(),
-                                         attribs.mChannelIndexMasks)) {
-                    sb.append("Output - Channel Index Masks Mismatch\n");
-                }
-                if (!ListsHelper.isMatch(deviceInfo.getChannelMasks(),
-                                         attribs.mChannelPositionMasks)) {
-                    sb.append("Output - Channel Position Masks Mismatch\n");
-                }
-                if (!ListsHelper.isMatch(deviceInfo.getEncodings(), attribs.mEncodings)) {
+
+                // Encodings
+                if (deviceInfo.getEncodings().length == 0) {
+                    sb.append("Output - No Peripheral Encodings\n");
+                } else if (!ListsHelper.isSubset(deviceInfo.getEncodings(), attribs.mEncodings)) {
                     sb.append("Output - Encodings Mismatch\n");
                 }
-                if (!ListsHelper.isMatch(deviceInfo.getSampleRates(), attribs.mSampleRates)) {
+
+                // Sample Rates
+                if (deviceInfo.getSampleRates().length == 0) {
+                    sb.append("Output - No Peripheral Sample Rates\n");
+                } else if (!ListsHelper.isSubset(deviceInfo.getSampleRates(), attribs.mSampleRates)) {
                     sb.append("Output - Sample Rates Mismatch\n");
                 }
 
+                // Channel Masks
+                if (deviceInfo.getChannelIndexMasks().length == 0 &&
+                    deviceInfo.getChannelMasks().length == 0) {
+                    sb.append("Output - No Peripheral Channel Masks\n");
+                } else {
+                    // Channel Index Masks
+                    if (!ListsHelper.isSubset(deviceInfo.getChannelIndexMasks(),
+                            attribs.mChannelIndexMasks)) {
+                        sb.append("Output - Channel Index Masks Mismatch\n");
+                    }
+
+                    // Channel Position Masks
+                    if (!ListsHelper.isSubset(deviceInfo.getChannelMasks(),
+                            attribs.mChannelPositionMasks)) {
+                        sb.append("Output - Channel Position Masks Mismatch\n");
+                    }
+                }
+
+                // Report
                 if (sb.toString().length() == 0){
                     metaSb.append("Output - Match\n");
                     outPass = true;
                 } else {
                     metaSb.append(sb.toString());
                 }
+            } else {
+                // No output device to test, so pass it.
+                outPass = true;
             }
 
             // Inputs
@@ -95,30 +120,50 @@
                     mSelectedProfile.getInputAttributes();
                 StringBuilder sb = new StringBuilder();
 
-                if (!ListsHelper.isMatch(deviceInfo.getChannelCounts(), attribs.mChannelCounts)) {
+                // Channel Counts
+                if (deviceInfo.getChannelCounts().length == 0) {
+                    sb.append("Input - No Peripheral Channel Counts\n");
+                } else if (!ListsHelper.isSubset(deviceInfo.getChannelCounts(), attribs.mChannelCounts)) {
                     sb.append("Input - Channel Counts Mismatch\n");
                 }
-                if (!ListsHelper.isMatch(deviceInfo.getChannelIndexMasks(),
-                                         attribs.mChannelIndexMasks)) {
-                    sb.append("Input - Channel Index Masks Mismatch\n");
-                }
-                if (!ListsHelper.isMatch(deviceInfo.getChannelMasks(),
-                                         attribs.mChannelPositionMasks)) {
-                    sb.append("Input - Channel Position Masks Mismatch\n");
-                }
-                if (!ListsHelper.isMatch(deviceInfo.getEncodings(), attribs.mEncodings)) {
+
+                // Encodings
+                if (deviceInfo.getEncodings().length == 0) {
+                    sb.append("Input - No Peripheral Encodings\n");
+                } else if (!ListsHelper.isSubset(deviceInfo.getEncodings(), attribs.mEncodings)) {
                     sb.append("Input - Encodings Mismatch\n");
                 }
-                if (!ListsHelper.isMatch(deviceInfo.getSampleRates(), attribs.mSampleRates)) {
+
+                // Sample Rates
+                if (deviceInfo.getSampleRates().length == 0) {
+                    sb.append("Input - No Peripheral Sample Rates\n");
+                } else if (!ListsHelper.isSubset(deviceInfo.getSampleRates(), attribs.mSampleRates)) {
                     sb.append("Input - Sample Rates Mismatch\n");
                 }
 
+                // Channel Masks
+                if (deviceInfo.getChannelIndexMasks().length == 0 &&
+                        deviceInfo.getChannelMasks().length == 0) {
+                    sb.append("Input - No Peripheral Channel Masks\n");
+                } else {
+                    if (!ListsHelper.isSubset(deviceInfo.getChannelIndexMasks(),
+                            attribs.mChannelIndexMasks)) {
+                        sb.append("Input - Channel Index Masks Mismatch\n");
+                    }
+                    if (!ListsHelper.isSubset(deviceInfo.getChannelMasks(),
+                            attribs.mChannelPositionMasks)) {
+                        sb.append("Input - Channel Position Masks Mismatch\n");
+                    }
+                }
                 if (sb.toString().length() == 0){
-                    inPass = true;
                     metaSb.append("Input - Match\n");
+                    inPass = true;
                 } else {
                     metaSb.append(sb.toString());
                 }
+            } else {
+                // No input device, so pass it.
+                inPass = true;
             }
 
             mTestStatusTx.setText(metaSb.toString());
@@ -126,7 +171,6 @@
             mTestStatusTx.setText("No Peripheral or No Matching Profile.");
         }
 
-        //TODO we need to support output-only and input-only peripherals
         getPassButton().setEnabled(outPass && inPass);
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ListsHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ListsHelper.java
index 4d14347..97822d0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ListsHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ListsHelper.java
@@ -31,4 +31,33 @@
 
         return true;
     }
+
+    static private boolean hasValue(int[] a, int value) {
+        // one can't use indexOf on an int[], so just scan.
+        for (int aVal : a) {
+            if (aVal == value) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * return true if the values in "a" are a subset of those in "b".
+     * Assume values are represented no more than once in each array.
+     */
+    static public boolean isSubset(int[] a, int[] b) {
+        if (a.length > b.length) {
+            return false;
+        }
+
+        for (int aVal : a) {
+            if (!hasValue(b, aVal)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
index 22452ec..59b20b0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
@@ -50,21 +50,24 @@
             "</PeripheralProfile>" +
             "<PeripheralProfile ProfileName=\"Audio Interface\" ProfileDescription=\"Presonus AudioVox 44VSL\" ProductName=\"USB-Audio - AudioBox 44 VSL\">" +
               "<OutputDevInfo ChanCounts=\"2,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
-              "<InputDevInfo ChanCounts=\"2,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
+              "<InputDevInfo ChanCounts=\"1,2,4\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
             "</PeripheralProfile>" +
             "<PeripheralProfile ProfileName=\"AudioBox 22VSL\" ProfileDescription=\"Presonus AudioBox 22VSL\" ProductName=\"USB-Audio - AudioBox 22 VSL\">" +
               "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
-              "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
+              "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
             "</PeripheralProfile>" +
             "<PeripheralProfile ProfileName=\"AudioBox USB\" ProfileDescription=\"Presonus AudioBox USB\" ProductName=\"USB-Audio - AudioBox USB\">" +
               "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
-              "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
+              "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
             "</PeripheralProfile>" +
-            "<PeripheralProfile ProfileName=\"gen1-headset\" ProfileDescription=\"Google Generation 1 USB Headset\" ProductName=\"USB-Audio - Skylab\">" +
+            "<PeripheralProfile ProfileName=\"gen1-headset\" ProfileDescription=\"Reference USB Headset\" ProductName=\"USB-Audio - Skylab\">" +
             "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"2,4\" SampleRates=\"8000,16000,32000,44100,48000\" />" +
             "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1\" Encodings=\"2\" SampleRates=\"8000,16000,32000,44100,48000\" />" +
             "<ButtonInfo HasBtnA=\"1\" HasBtnB=\"1\" HasBtnC=\"1\" HasBtnD=\"1\" />" +
           "</PeripheralProfile>" +
+          "<PeripheralProfile ProfileName=\"mir\" ProfileDescription=\"Reference USB Dongle\" ProductName=\"USB-Audio - USB Audio\">" +
+            "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\" />" +
+          "</PeripheralProfile>" +
           "</ProfileList>";
 
     // XML Tags and Attributes