diff --git a/mime/Android.bp b/mime/Android.bp index 0ae94d44061d5d601352a7f8469ae71df68ba906..51290f6b1176ad2f55c33121dd2bcd3c15f53770 100644 --- a/mime/Android.bp +++ b/mime/Android.bp @@ -12,24 +12,84 @@ // See the License for the specific language governing permissions and // limitations under the License. + +java_defaults { + name: "mimemap-defaults", + srcs: [ + "java/android/content/type/DefaultMimeMapFactory.java", + ], + sdk_version: "core_platform", +} + java_library { name: "mimemap", + defaults: ["mimemap-defaults"], + static_libs: ["mimemap-res.jar"], + visibility: [ + "//frameworks/base:__subpackages__", + ], +} + +java_library { + name: "mimemap-testing", + defaults: ["mimemap-defaults"], + static_libs: ["mimemap-testing-res.jar"], + jarjar_rules: "jarjar-rules.txt", visibility: [ "//cts/tests/tests/mimemap:__subpackages__", "//frameworks/base:__subpackages__", ], +} + +// The mimemap-res.jar and mimemap-testing-res.jar genrules produce a .jar that +// has the resource file in a subdirectory res/ and testres/, respectively. +// Those paths need to They need to be in different paths because one of them +// ends up on a bootclasspath jar whereas the other one ends up in a test jar. +// Bootclasspath resources hide test or application resources under the same +// path because ClassLoader.getResource(String) consults the parent ClassLoader +// first. +// +// Further notes: +// - the "cp" command will flatten any directory paths that occur in $(in), +// but here they happen to already be in the root directory. If we needed +// to preserve sub paths then we might want to zip the files first and then +// unzip them below the new parent directory. +// - the path names "res/" and "testres/" and duplicated in .java source files +// (DefaultMimeMapFactory.java and MimeMapTest.java, as of October 2019). +java_genrule { + name: "mimemap-res.jar", + tools: [ + "soong_zip", + ], + srcs: [":mime.types"], + out: ["mimemap-res.jar"], + cmd: "mkdir $(genDir)/res/ && cp $(in) $(genDir)/res/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/res/", +} - srcs: [ - "java/android/content/type/DefaultMimeMapFactory.java", +// The same as mimemap-res.jar except that the resources are placed in a different directory. +// They get bundled with CTS so that CTS can compare a device's MimeMap implementation vs. +// the stock Android one from when CTS was built. +java_genrule { + name: "mimemap-testing-res.jar", + tools: [ + "soong_zip", ], + srcs: [":mime.types"], + out: ["mimemap-testing-res.jar"], + cmd: "mkdir $(genDir)/testres/ && cp $(in) $(genDir)/testres/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/testres/", +} - java_resources: [ +// Combination of all *mime.types resources. +filegroup { + name: "mime.types", + visibility: [ + "//visibility:private", + ], + srcs: [ ":debian.mime.types", ":android.mime.types", ":vendor.mime.types", ], - - sdk_version: "core_platform", } filegroup { diff --git a/mime/jarjar-rules.txt b/mime/jarjar-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..145d1dbf3d115a5397eb0e56b0062f1e5aa5a79f --- /dev/null +++ b/mime/jarjar-rules.txt @@ -0,0 +1 @@ +rule android.content.type.DefaultMimeMapFactory android.content.type.cts.StockAndroidMimeMapFactory \ No newline at end of file diff --git a/mime/java/android/content/type/DefaultMimeMapFactory.java b/mime/java/android/content/type/DefaultMimeMapFactory.java index 56b234fe0e1c4c20b92d3f3c19b827526125202c..13039a4ab1e24ad72ea96c460ccf55f315a6c667 100644 --- a/mime/java/android/content/type/DefaultMimeMapFactory.java +++ b/mime/java/android/content/type/DefaultMimeMapFactory.java @@ -20,10 +20,13 @@ import libcore.net.MimeMap; import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import java.util.function.Function; import java.util.regex.Pattern; /** @@ -45,21 +48,33 @@ public class DefaultMimeMapFactory { * Android's default mapping between MIME types and extensions. */ public static MimeMap create() { - MimeMap.Builder builder = MimeMap.builder(); - parseTypes(builder, true, "/mime.types"); - parseTypes(builder, true, "/android.mime.types"); - parseTypes(builder, false, "/vendor.mime.types"); - return builder.build(); + Class c = DefaultMimeMapFactory.class; + // The resources are placed into the res/ path by the "mimemap-res.jar" genrule. + return create(resourceName -> c.getResourceAsStream("/res/" + resourceName)); } private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+"); + /** + * Creates a {@link MimeMap} instance whose resources are loaded from the + * InputStreams looked up in {@code resourceSupplier}. + * + * @hide + */ + public static MimeMap create(Function<String, InputStream> resourceSupplier) { + MimeMap.Builder builder = MimeMap.builder(); + parseTypes(builder, true, resourceSupplier, "mime.types"); + parseTypes(builder, true, resourceSupplier, "android.mime.types"); + parseTypes(builder, false, resourceSupplier, "vendor.mime.types"); + return builder.build(); + } + private static void parseTypes(MimeMap.Builder builder, boolean allowOverwrite, - String resource) { - try (BufferedReader r = new BufferedReader( - new InputStreamReader(DefaultMimeMapFactory.class.getResourceAsStream(resource)))) { + Function<String, InputStream> resourceSupplier, String resourceName) { + try (InputStream inputStream = Objects.requireNonNull(resourceSupplier.apply(resourceName)); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { String line; - while ((line = r.readLine()) != null) { + while ((line = reader.readLine()) != null) { int commentPos = line.indexOf('#'); if (commentPos >= 0) { line = line.substring(0, commentPos); @@ -78,7 +93,7 @@ public class DefaultMimeMapFactory { builder.put(specs.get(0), specs.subList(1, specs.size())); } } catch (IOException | RuntimeException e) { - throw new RuntimeException("Failed to parse " + resource, e); + throw new RuntimeException("Failed to parse " + resourceName, e); } }