Merge "camera2: Update jpeg EXIF CTS test for LEGACY." into lmp-dev
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 37cd471..3347ba4 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -129,6 +129,17 @@
     <permission-group android:name="android.permission-group.COST_MONEY"/>
     <!-- Used for PackageManager test, don't delete! -->
     <uses-configuration/>
+    <uses-feature android:name="android.hardware.camera" />
+    <uses-feature android:glEsVersion="0x00020000" />
+    <feature-group/>
+    <feature-group>
+        <uses-feature android:glEsVersion="0x00030000" />
+        <uses-feature android:name="android.hardware.location" />
+    </feature-group>
+    <feature-group>
+        <uses-feature android:glEsVersion="0x00010001" />
+        <uses-feature android:name="android.hardware.camera" />
+    </feature-group>
 
     <application android:label="Android TestCase"
                 android:icon="@drawable/size_48x48"
diff --git a/tests/tests/content/src/android/content/pm/cts/FeatureGroupInfoTest.java b/tests/tests/content/src/android/content/pm/cts/FeatureGroupInfoTest.java
new file mode 100644
index 0000000..0b9de54
--- /dev/null
+++ b/tests/tests/content/src/android/content/pm/cts/FeatureGroupInfoTest.java
@@ -0,0 +1,175 @@
+/**
+ * Copyright (C) 2014 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.content.pm.cts;
+
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+public class FeatureGroupInfoTest extends AndroidTestCase {
+
+    private PackageManager mPackageManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mPackageManager = getContext().getPackageManager();
+    }
+
+    public void testFeatureGroupsAreCorrect() throws Exception {
+        FeatureInfo[] expectedFeatures = new FeatureInfo[] {
+                createFeatureInfo("android.hardware.camera", true),
+                createFeatureInfo(0x00020000, true)
+        };
+
+        FeatureGroupInfo[] expectedGroups = new FeatureGroupInfo[] {
+                createFeatureGroup(new FeatureInfo[] {
+                }),
+                createFeatureGroup(new FeatureInfo[] {
+                        createFeatureInfo("android.hardware.location", true),
+                        createFeatureInfo(0x00030000, true)
+                }),
+                createFeatureGroup(new FeatureInfo[] {
+                        createFeatureInfo("android.hardware.camera", true),
+                        createFeatureInfo(0x00010001, true)
+                })
+        };
+
+        PackageInfo pi = mPackageManager.getPackageInfo(getContext().getPackageName(),
+                PackageManager.GET_CONFIGURATIONS);
+        assertNotNull(pi);
+        assertNotNull(pi.reqFeatures);
+        assertNotNull(pi.featureGroups);
+
+        assertFeatureInfosMatch(pi.reqFeatures, expectedFeatures);
+        assertFeatureGroupsMatch(pi.featureGroups, expectedGroups);
+    }
+
+    private static void assertFeatureInfosMatch(FeatureInfo[] actualFeatures,
+            FeatureInfo[] expectedFeatures) {
+        // We're going to do linear comparisons, so sort everything first.
+        Arrays.sort(actualFeatures, sFeatureInfoComparator);
+        Arrays.sort(expectedFeatures, sFeatureInfoComparator);
+
+        assertEquals(0, compareFeatureInfoArrays(actualFeatures, expectedFeatures));
+    }
+
+    private static void assertFeatureGroupsMatch(FeatureGroupInfo[] actualGroups,
+            FeatureGroupInfo[] expectedGroups) {
+        // We're going to do linear comparisons, so sort everything first.
+        sortFeatureInfos(actualGroups);
+        sortFeatureInfos(expectedGroups);
+
+        Arrays.sort(actualGroups, sFeatureGroupComparator);
+        Arrays.sort(expectedGroups, sFeatureGroupComparator);
+
+        assertEquals(expectedGroups.length, actualGroups.length);
+        final int N = expectedGroups.length;
+        for (int i = 0; i < N; i++) {
+            assertEquals(0, sFeatureGroupComparator.compare(expectedGroups[i], actualGroups[i]));
+        }
+    }
+
+    /**
+     * Helper method to create FeatureInfo objects.
+     */
+    private static FeatureInfo createFeatureInfo(String name, boolean required) {
+        FeatureInfo fi = new FeatureInfo();
+        fi.name = name;
+        if (required) {
+            fi.flags |= FeatureInfo.FLAG_REQUIRED;
+        }
+        return fi;
+    }
+
+    /**
+     * Helper method to create OpenGL FeatureInfo objects.
+     */
+    private static FeatureInfo createFeatureInfo(int glEsVersion, boolean required) {
+        FeatureInfo fi = new FeatureInfo();
+        fi.reqGlEsVersion = glEsVersion;
+        if (required) {
+            fi.flags |= FeatureInfo.FLAG_REQUIRED;
+        }
+        return fi;
+    }
+
+    private static FeatureGroupInfo createFeatureGroup(FeatureInfo[] featureInfos) {
+        FeatureGroupInfo group = new FeatureGroupInfo();
+        group.features = featureInfos;
+        return group;
+    }
+
+    private static void sortFeatureInfos(FeatureGroupInfo[] group) {
+        for (FeatureGroupInfo g : group) {
+            if (g.features != null) {
+                Arrays.sort(g.features, sFeatureInfoComparator);
+            }
+        }
+    }
+
+    private static int compareFeatureInfoArrays(FeatureInfo[] a, FeatureInfo[] b) {
+        final int aCount = a != null ? a.length : 0;
+        final int bCount = b != null ? b.length : 0;
+        final int N = Math.min(aCount, bCount);
+        for (int i = 0; i < N; i++) {
+            int diff = sFeatureInfoComparator.compare(a[i], b[i]);
+            if (diff != 0) {
+                return diff;
+            }
+        }
+        return Integer.compare(aCount, bCount);
+    }
+
+    /**
+     * A Comparator for FeatureGroups that assumes that the FeatureInfo array is
+     * already sorted.
+     */
+    private static final Comparator<FeatureGroupInfo> sFeatureGroupComparator =
+            new Comparator<FeatureGroupInfo>() {
+                @Override
+                public int compare(FeatureGroupInfo o1, FeatureGroupInfo o2) {
+                    return compareFeatureInfoArrays(o1.features, o2.features);
+                }
+            };
+
+    private static final Comparator<FeatureInfo> sFeatureInfoComparator =
+            new Comparator<FeatureInfo>() {
+                @Override
+                public int compare(FeatureInfo o1, FeatureInfo o2) {
+                    final int diff;
+                    if (o1.name == null && o2.name != null) {
+                        diff = -1;
+                    } else if (o1.name != null && o2.name == null) {
+                        diff = 1;
+                    } else if (o1.name == null && o2.name == null) {
+                        diff = Integer.compare(o1.reqGlEsVersion, o2.reqGlEsVersion);
+                    } else {
+                        diff = o1.name.compareTo(o2.name);
+                    }
+
+                    if (diff == 0) {
+                        return Integer.compare(o1.flags, o2.flags);
+                    }
+                    return diff;
+                }
+            };
+}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraSessionUtils.java b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraSessionUtils.java
index d85a610..134d674 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraSessionUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraSessionUtils.java
@@ -38,7 +38,7 @@
 import java.util.List;
 import java.util.concurrent.LinkedBlockingQueue;
 
-import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.cts.helpers.Preconditions.*;
 import static org.mockito.Mockito.*;
 
 /**
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Preconditions.java b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Preconditions.java
index 8520a48..cb9e522 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Preconditions.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Preconditions.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2.cts.helpers;
 
+import java.util.Collection;
 import java.util.Objects;
 
 /**
@@ -90,6 +91,22 @@
     }
 
     /**
+     * Checks that the value is not {@code null}.
+     *
+     * <p>
+     * Returns the value directly, so you can use {@code checkNotNull("value", value)} inline.
+     * </p>
+     *
+     * @param arg Argument to check
+     * @return arg
+     *
+     * @throws NullPointerException if arg was {@code null}
+     */
+    public static <T> T checkNotNull(T arg) {
+        return checkNotNull("", arg);
+    }
+
+    /**
      * Checks that the state is currently {@link true}.
      *
      * @param message Message to raise an exception with if the state checking fails.
@@ -107,6 +124,57 @@
         return state;
     }
 
+        /**
+     * Ensures that the {@link Collection} is not {@code null}, and none of its elements are
+     * {@code null}.
+     *
+     * @param value a {@link Collection} of boxed objects
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated {@link Collection}
+     *
+     * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
+     */
+    public static <T> Collection<T> checkCollectionElementsNotNull(final Collection<T> value,
+            final String valueName) {
+        if (value == null) {
+            throw new NullPointerException(valueName + " must not be null");
+        }
+
+        long ctr = 0;
+        for (T elem : value) {
+            if (elem == null) {
+                throw new NullPointerException(
+                        String.format("%s[%d] must not be null", valueName, ctr));
+            }
+            ++ctr;
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the {@link Collection} is not {@code null}, and contains at least one element.
+     *
+     * @param value a {@link Collection} of boxed elements.
+     * @param valueName the name of the argument to use if the check fails.
+
+     * @return the validated {@link Collection}
+     *
+     * @throws NullPointerException if the {@code value} was {@code null}
+     * @throws IllegalArgumentException if the {@code value} was empty
+     */
+    public static <T> Collection<T> checkCollectionNotEmpty(final Collection<T> value,
+            final String valueName) {
+        if (value == null) {
+            throw new NullPointerException(valueName + " must not be null");
+        }
+        if (value.isEmpty()) {
+            throw new IllegalArgumentException(valueName + " is empty");
+        }
+        return value;
+    }
+
     // Suppress default constructor for noninstantiability
     private Preconditions() { throw new AssertionError(); }
 }