Merge "Address the comments left in the IPv6 utils change."
diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
index e5bb58d..115f19d 100644
--- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
@@ -76,15 +76,26 @@
         return true;
 
     }
+
     /**
      * @return True if any element satisfies the predicate, false otherwise.
      *   Note that means this always returns false for empty collections.
      */
     public static <T> boolean any(@NonNull Collection<T> elem, @NonNull Predicate<T> predicate) {
+        return indexOf(elem, predicate) >= 0;
+    }
+
+    /**
+     * @return The index of the first element that matches the predicate, or -1 if none.
+     */
+    @Nullable
+    public static <T> int indexOf(@NonNull Collection<T> elem, @NonNull Predicate<T> predicate) {
+        int idx = 0;
         for (final T e : elem) {
-            if (predicate.test(e)) return true;
+            if (predicate.test(e)) return idx;
+            idx++;
         }
-        return false;
+        return -1;
     }
 
     /**
diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
index 5a0200f..3de78c6 100644
--- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
@@ -78,4 +78,31 @@
         }
         return transports[0];
     }
+
+    /**
+     * Unpacks long value into an array of bits.
+     */
+    public static int[] unpackBits(long val) {
+        int size = Long.bitCount(val);
+        int[] result = new int[size];
+        int index = 0;
+        int bitPos = 0;
+        while (val != 0) {
+            if ((val & 1) == 1) result[index++] = bitPos;
+            val = val >>> 1;
+            bitPos++;
+        }
+        return result;
+    }
+
+    /**
+     * Packs array of bits into a long value.
+     */
+    public static long packBits(int[] bits) {
+        long packed = 0;
+        for (int b : bits) {
+            packed |= (1L << b);
+        }
+        return packed;
+    }
 }
diff --git a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt
index 09126d7..91fb1cd 100644
--- a/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt
+++ b/staticlibs/hostdevice/com/android/testutils/MiscAsserts.kt
@@ -32,10 +32,18 @@
     assertEquals(0, len, "Expected empty array, but length was $len")
 }
 
+fun <T> assertEmpty(ts: List<T>) = ts.size.let { len ->
+    assertEquals(0, len, "Expected empty list, but length was $len")
+}
+
 fun <T> assertLength(expected: Int, got: Array<T>) = got.size.let { len ->
     assertEquals(expected, len, "Expected array of length $expected, but was $len for $got")
 }
 
+fun <T> assertLength(expected: Int, got: List<T>) = got.size.let { len ->
+    assertEquals(expected, len, "Expected list of length $expected, but was $len for $got")
+}
+
 // Bridge method to help write this in Java. If you're writing Kotlin, consider using
 // kotlin.test.assertFailsWith instead, as that method is reified and inlined.
 fun <T : Exception> assertThrows(expected: Class<T>, block: ThrowingRunnable): T {
@@ -103,3 +111,12 @@
         !Modifier.isStatic(it.modifiers) && !Modifier.isTransient(it.modifiers)
     }.size)
 }
+
+fun assertSameElements(expected: List<String?>, actual: List<String?>) {
+    val expectedSet: HashSet<String?> = HashSet<String?>(expected)
+    assertEquals(expectedSet.size.toLong(), expected.size.toLong(),
+            "expected list contains duplicates")
+    val actualSet: HashSet<String?> = HashSet<String?>(actual)
+    assertEquals(actualSet.size.toLong(), actual.size.toLong(), "actual list contains duplicates")
+    assertEquals(expectedSet, actualSet)
+}
diff --git a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java
index e47c864..45493bd 100644
--- a/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java
+++ b/staticlibs/tests/unit/src/android/net/util/LinkPropertiesUtilsTest.java
@@ -16,6 +16,8 @@
 
 package android.net.util;
 
+import static com.android.testutils.MiscAsserts.assertSameElements;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -40,7 +42,6 @@
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
 import java.util.function.Function;
 
@@ -247,14 +248,6 @@
         assertEquals(linkAddr2, results.added.get(0));
     }
 
-    private void assertSameElements(List<String> expected, List<String> actual) {
-        HashSet<String> expectedSet = new HashSet(expected);
-        assertEquals("expected list contains duplicates", expectedSet.size(), expected.size());
-        HashSet<String> actualSet = new HashSet(actual);
-        assertEquals("actual list contains duplicates", actualSet.size(), actual.size());
-        assertEquals(expectedSet, actualSet);
-    }
-
     private void assertCompareOrUpdateResult(CompareOrUpdateResult result,
             List<String> expectedAdded, List<String> expectedRemoved,
             List<String> expectedUpdated) {
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
index 0007742..0886426 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.runner.AndroidJUnit4
 import org.junit.Test
 import org.junit.runner.RunWith
+import kotlin.test.assertEquals
 import kotlin.test.assertFalse
 import kotlin.test.assertTrue
 
@@ -40,6 +41,15 @@
     }
 
     @Test
+    fun testIndexOf() {
+        assertEquals(4, CollectionUtils.indexOf(listOf("A", "B", "C", "D", "E")) { it == "E" })
+        assertEquals(0, CollectionUtils.indexOf(listOf("A", "B", "C", "D", "E")) { it == "A" })
+        assertEquals(1, CollectionUtils.indexOf(listOf("AA", "BBB", "CCCC")) { it.length >= 3 })
+        assertEquals(1, CollectionUtils.indexOf(listOf("AA", null, "CCCC")) { it == null })
+        assertEquals(1, CollectionUtils.indexOf(listOf(null, "CCCC")) { it != null })
+    }
+
+    @Test
     fun testAll() {
         assertFalse(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "E" })
         assertTrue(CollectionUtils.all(listOf("A", "B", "C", "D", "E")) { it != "F" })
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt
index e94d132..df2f459 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt
@@ -26,11 +26,14 @@
 import androidx.test.filters.SmallTest
 import androidx.test.runner.AndroidJUnit4
 import com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport
+import com.android.net.module.util.NetworkCapabilitiesUtils.packBits
+import com.android.net.module.util.NetworkCapabilitiesUtils.unpackBits
 import org.junit.Test
 import org.junit.runner.RunWith
 import java.lang.IllegalArgumentException
 import kotlin.test.assertEquals
 import kotlin.test.assertFailsWith
+import kotlin.test.assertTrue
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
@@ -58,4 +61,21 @@
             getDisplayTransport(intArrayOf())
         }
     }
-}
\ No newline at end of file
+
+    @Test
+    fun testBitPackingTestCase() {
+        runBitPackingTestCase(0, intArrayOf())
+        runBitPackingTestCase(1, intArrayOf(0))
+        runBitPackingTestCase(3, intArrayOf(0, 1))
+        runBitPackingTestCase(4, intArrayOf(2))
+        runBitPackingTestCase(63, intArrayOf(0, 1, 2, 3, 4, 5))
+        runBitPackingTestCase(Long.MAX_VALUE.inv(), intArrayOf(63))
+        runBitPackingTestCase(Long.MAX_VALUE.inv() + 1, intArrayOf(0, 63))
+        runBitPackingTestCase(Long.MAX_VALUE.inv() + 2, intArrayOf(1, 63))
+    }
+
+    fun runBitPackingTestCase(packedBits: Long, bits: IntArray) {
+        assertEquals(packedBits, packBits(bits))
+        assertTrue(bits contentEquals unpackBits(packedBits))
+    }
+}