Make CTS more opinionated about the platform's default MimeMap.

Historically, the mapping implemented by MimeMap (formerly MimeUtils)
was largely untested and therefore differed between Android devices.

This CL topic makes CtsMimeMapTestCases a lot more opinionated by
checking that:

 - MimeMap.getDefault() must respect all of the mappings supplied
   in stock Android. This is enforced via CTS bundling a copy of:
   - the {,android.,vendor.}mime.types data files
   - DefaultMimeMapFactory (rewritten via jarjar to
     android.content.type.cts.StockAndroidMimeMapFactory)
   MimeMap.getDefault() is allowed to implement _additional_
   mappings, but changed or removed mappings are not allowed.
 - Public APIs android.webkit.MimeTypeMap and
   URLConnection.getFileNameMap() must behave consistently with
   MimeMap.getDefault() (in stock Android, those APIs are
   implemented directly on top of MimeMap.getDefault()).

Test: atest CtsMimeMapTestCases
Test: atest CtsLibcoreTestCases:libcore.libcore.net.MimeMapTest
Test: The above atest runs pass on a device that contains an
      additional mapping in vendor.mime.types that is not
      present in CTS.
Test: Checked that on a device that changes a mapping in
      android.mime.types, CtsLibcoreTestCases still passes
      but CtsMimeMapTestCases fails.

Bug: 141842930
Bug: 139895945

Change-Id: Ie7492d6399b04b4b2765a02f58fe3e7e6352e41e
diff --git a/luni/src/main/java/libcore/net/MimeMap.java b/luni/src/main/java/libcore/net/MimeMap.java
index 14cc25e..ba6a403 100644
--- a/luni/src/main/java/libcore/net/MimeMap.java
+++ b/luni/src/main/java/libcore/net/MimeMap.java
@@ -23,6 +23,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import libcore.api.CorePlatformApi;
 import libcore.util.NonNull;
 import libcore.util.Nullable;
@@ -150,6 +151,30 @@
     }
 
     /**
+     * Returns the set of MIME types that this {@link MimeMap}
+     * {@link #hasMimeType(String) maps to some extension}. Note that the
+     * reverse mapping might not exist.
+     *
+     * @hide
+     */
+    @libcore.api.CorePlatformApi
+    public @NonNull Set<String> mimeTypes() {
+        return Collections.unmodifiableSet(mimeToExt.keySet());
+    }
+
+    /**
+     * Returns the set of extensions that this {@link MimeMap}
+     * {@link #hasExtension(String) maps to some MIME type}. Note that the
+     * reverse mapping might not exist.
+     *
+     * @hide
+     */
+    @libcore.api.CorePlatformApi
+    public @NonNull Set<String> extensions() {
+        return Collections.unmodifiableSet(extToMime.keySet());
+    }
+
+    /**
      * Returns the canonical (lowercase) form of the given extension or MIME type.
      */
     private static @NonNull String toLowerCase(@NonNull String s) {
@@ -284,7 +309,8 @@
          * @return This builder.
          */
         @CorePlatformApi
-        public Builder put(@NonNull String mimeSpec, @NonNull List<@NonNull String> extensionSpecs) {
+        public Builder put(@NonNull String mimeSpec, @NonNull List<@NonNull String> extensionSpecs)
+        {
             Element mimeElement = new Element(mimeSpec); // validate mimeSpec unconditionally
             if (extensionSpecs.isEmpty()) {
                 return this;
diff --git a/luni/src/test/java/libcore/libcore/net/MimeMapTest.java b/luni/src/test/java/libcore/libcore/net/MimeMapTest.java
index 4bc762d..698e7e8 100644
--- a/luni/src/test/java/libcore/libcore/net/MimeMapTest.java
+++ b/luni/src/test/java/libcore/libcore/net/MimeMapTest.java
@@ -23,7 +23,10 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
 import libcore.net.MimeMap;
 
 import static org.junit.Assert.assertEquals;
@@ -265,6 +268,46 @@
         );
     }
 
+    @Test public void extensions() {
+        assertEquals(Collections.emptySet(), emptyMap.extensions());
+        mimeMap = MimeMap.builder()
+                .put("text/plain", Arrays.asList("txt", "text"))
+                .put("audi/mpeg", "m4a")
+                .put("application/msword", "doc")
+                .put("text/plain", "tx")
+                .build();
+        Set<String> extensions = new HashSet<>(Arrays.asList(
+                "txt", "text", "m4a", "doc", "tx"));
+        assertEquals(extensions, mimeMap.extensions());
+        // Check that the extensions() view is unmodifiable
+        try {
+            mimeMap.extensions().add("ext");
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    @Test public void mimeTypes() {
+        assertEquals(Collections.emptySet(), emptyMap.mimeTypes());
+        mimeMap = MimeMap.builder()
+                .put("text/plain", Arrays.asList("txt", "text"))
+                .put("audio/mpeg", "m4a")
+                .put("application/msword", "doc")
+                .put("text/plain", "tx")
+                .build();
+        Set<String> mimeTypes = new HashSet<>(Arrays.asList(
+                "text/plain",
+                "audio/mpeg",
+                "application/msword"));
+        assertEquals(mimeTypes, mimeMap.mimeTypes());
+        // Check that the mimeTypes() view is unmodifiable
+        try {
+            mimeMap.mimeTypes().add("foo/bar");
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
     /**
      * Tests invalid put() invocations that have '?' in additional/invalid places.
      */
@@ -278,7 +321,8 @@
     }
 
     private static void assertPutThrowsNpe(String mime, String... exts) {
-        assertThrowsNpe(() -> MimeMap.builder().put(mime, Arrays.asList(exts)));    }
+        assertThrowsNpe(() -> MimeMap.builder().put(mime, Arrays.asList(exts)));
+    }
 
     private static void assertPutThrowsIae(final String mime, final String... exts) {
         assertThrowsIae(() -> MimeMap.builder().put(mime, Arrays.asList(exts)));
diff --git a/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index ca7d2f9..4fc669b 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -1205,11 +1205,13 @@
   public final class MimeMap {
     method public libcore.net.MimeMap.Builder buildUpon();
     method public static libcore.net.MimeMap.Builder builder();
+    method @NonNull public java.util.Set<java.lang.String> extensions();
     method @NonNull public static libcore.net.MimeMap getDefault();
     method @Nullable public String guessExtensionFromMimeType(@Nullable String);
     method @Nullable public String guessMimeTypeFromExtension(@Nullable String);
     method public boolean hasExtension(@Nullable String);
     method public boolean hasMimeType(@Nullable String);
+    method @NonNull public java.util.Set<java.lang.String> mimeTypes();
     method public static void setDefault(@NonNull libcore.net.MimeMap);
   }