Commit c70daafc authored by Ethan Xu's avatar Ethan Xu Committed by Commit Bot

Add MimeTypeFilter to support Web Share Target v2.

The purpose of this CL is to refactor the MimeTypeFilter code inside chrome/android/java/src/org/chromium/chrome/browser/photo_picker/MimeTypeFileFilter.java,
and modify it for the purpose of mime type filtering in Web share target v2.

The specific usage of MimeTypeFilter is to help determine
whether a mime type is accepted by a list of accepted mime types.

In order to fit the spec for Web Share Target v2, one new additional logic is added.
"*/*" is now recognized as accepting all mime types.

The Web Share Target v2 CL in reference is:
https://chromium-review.googlesource.com/c/chromium/src/+/1271776

Change-Id: I9daa21e4049ae7a153858dc084f64294fe4f2584
Reviewed-on: https://chromium-review.googlesource.com/c/1324096
Commit-Queue: Ethan Xu <xuethan@google.com>
Reviewed-by: default avatarBence Béky <bnc@chromium.org>
Reviewed-by: default avatarGlenn Hartmann <hartmanng@chromium.org>
Reviewed-by: default avatarPeter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarFinnur Thorarinsson <finnur@chromium.org>
Cr-Commit-Position: refs/heads/master@{#609901}
parent 6d63b5ff
...@@ -11,6 +11,7 @@ import android.provider.MediaStore; ...@@ -11,6 +11,7 @@ import android.provider.MediaStore;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.base.task.AsyncTask; import org.chromium.base.task.AsyncTask;
import org.chromium.net.MimeTypeFilter;
import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.base.WindowAndroid;
import java.io.File; import java.io.File;
...@@ -39,7 +40,7 @@ class FileEnumWorkerTask extends AsyncTask<List<PickerBitmap>> { ...@@ -39,7 +40,7 @@ class FileEnumWorkerTask extends AsyncTask<List<PickerBitmap>> {
private FilesEnumeratedCallback mCallback; private FilesEnumeratedCallback mCallback;
// The filter to apply to the list. // The filter to apply to the list.
private MimeTypeFileFilter mFilter; private MimeTypeFilter mFilter;
// The camera directory undir DCIM. // The camera directory undir DCIM.
private static final String SAMPLE_DCIM_SOURCE_SUB_DIRECTORY = "Camera"; private static final String SAMPLE_DCIM_SOURCE_SUB_DIRECTORY = "Camera";
...@@ -50,8 +51,8 @@ class FileEnumWorkerTask extends AsyncTask<List<PickerBitmap>> { ...@@ -50,8 +51,8 @@ class FileEnumWorkerTask extends AsyncTask<List<PickerBitmap>> {
* @param callback The callback to use to communicate back the results. * @param callback The callback to use to communicate back the results.
* @param filter The file filter to apply to the list. * @param filter The file filter to apply to the list.
*/ */
public FileEnumWorkerTask(WindowAndroid windowAndroid, FilesEnumeratedCallback callback, public FileEnumWorkerTask(
MimeTypeFileFilter filter) { WindowAndroid windowAndroid, FilesEnumeratedCallback callback, MimeTypeFilter filter) {
mWindowAndroid = windowAndroid; mWindowAndroid = windowAndroid;
mCallback = callback; mCallback = callback;
mFilter = filter; mFilter = filter;
......
...@@ -27,6 +27,7 @@ import org.chromium.chrome.browser.ChromeActivity; ...@@ -27,6 +27,7 @@ import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.util.ConversionUtils; import org.chromium.chrome.browser.util.ConversionUtils;
import org.chromium.chrome.browser.widget.selection.SelectableListLayout; import org.chromium.chrome.browser.widget.selection.SelectableListLayout;
import org.chromium.chrome.browser.widget.selection.SelectionDelegate; import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
import org.chromium.net.MimeTypeFilter;
import org.chromium.ui.PhotoPickerListener; import org.chromium.ui.PhotoPickerListener;
import org.chromium.ui.UiUtils; import org.chromium.ui.UiUtils;
...@@ -365,7 +366,7 @@ public class PickerCategoryView extends RelativeLayout ...@@ -365,7 +366,7 @@ public class PickerCategoryView extends RelativeLayout
mEnumStartTime = SystemClock.elapsedRealtime(); mEnumStartTime = SystemClock.elapsedRealtime();
mWorkerTask = new FileEnumWorkerTask( mWorkerTask = new FileEnumWorkerTask(
mActivity.getWindowAndroid(), this, new MimeTypeFileFilter(mMimeTypes)); mActivity.getWindowAndroid(), this, new MimeTypeFilter(mMimeTypes, true));
mWorkerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); mWorkerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
......
...@@ -1230,7 +1230,6 @@ chrome_java_sources = [ ...@@ -1230,7 +1230,6 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java", "java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java",
"java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java", "java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java",
"java/src/org/chromium/chrome/browser/photo_picker/FileEnumWorkerTask.java", "java/src/org/chromium/chrome/browser/photo_picker/FileEnumWorkerTask.java",
"java/src/org/chromium/chrome/browser/photo_picker/MimeTypeFileFilter.java",
"java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java", "java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java",
"java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerToolbar.java", "java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerToolbar.java",
"java/src/org/chromium/chrome/browser/photo_picker/PickerAdapter.java", "java/src/org/chromium/chrome/browser/photo_picker/PickerAdapter.java",
......
...@@ -16,6 +16,7 @@ android_library("net_java") { ...@@ -16,6 +16,7 @@ android_library("net_java") {
"java/src/org/chromium/net/HttpNegotiateAuthenticator.java", "java/src/org/chromium/net/HttpNegotiateAuthenticator.java",
"java/src/org/chromium/net/HttpNegotiateConstants.java", "java/src/org/chromium/net/HttpNegotiateConstants.java",
"java/src/org/chromium/net/HttpUtil.java", "java/src/org/chromium/net/HttpUtil.java",
"java/src/org/chromium/net/MimeTypeFilter.java",
"java/src/org/chromium/net/NetStringUtil.java", "java/src/org/chromium/net/NetStringUtil.java",
"java/src/org/chromium/net/NetworkChangeNotifier.java", "java/src/org/chromium/net/NetworkChangeNotifier.java",
"java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java", "java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java",
...@@ -157,6 +158,7 @@ android_library("net_javatests") { ...@@ -157,6 +158,7 @@ android_library("net_javatests") {
"javatests/src/org/chromium/net/AndroidProxyConfigServiceTestUtil.java", "javatests/src/org/chromium/net/AndroidProxyConfigServiceTestUtil.java",
"javatests/src/org/chromium/net/AndroidProxySelectorTest.java", "javatests/src/org/chromium/net/AndroidProxySelectorTest.java",
"javatests/src/org/chromium/net/HttpUtilTest.java", "javatests/src/org/chromium/net/HttpUtilTest.java",
"javatests/src/org/chromium/net/MimeTypeFilterTest.java",
"javatests/src/org/chromium/net/NetErrorsTest.java", "javatests/src/org/chromium/net/NetErrorsTest.java",
"javatests/src/org/chromium/net/NetworkChangeNotifierNoNativeTest.java", "javatests/src/org/chromium/net/NetworkChangeNotifierNoNativeTest.java",
"javatests/src/org/chromium/net/NetworkChangeNotifierTest.java", "javatests/src/org/chromium/net/NetworkChangeNotifierTest.java",
......
// Copyright 2017 The Chromium Authors. All rights reserved. // Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
package org.chromium.chrome.browser.photo_picker; package org.chromium.net;
import android.net.Uri;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
...@@ -14,72 +15,75 @@ import java.util.List; ...@@ -14,72 +15,75 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
/** /**
* A file filter for handling extensions mapping to MIME types (such as images/jpeg and images/*). * A mime type filter that supports filtering both mime types and file extensions.
* Note that this class is used specifically to implement
* the mime type filtering for web share target spec:
* https://pr-preview.s3.amazonaws.com/ewilligers/web-share-target/pull/53.html#determining-if-a-file-is-accepted.
* It is also used inside chrome/android/java/src/org/chromium/chrome/browser/photo_picker.
*/ */
class MimeTypeFileFilter implements FileFilter { public class MimeTypeFilter implements FileFilter {
private HashSet<String> mExtensions = new HashSet<>(); private HashSet<String> mExtensions = new HashSet<>();
private HashSet<String> mMimeTypes = new HashSet<>(); private HashSet<String> mMimeTypes = new HashSet<>();
private HashSet<String> mMimeSupertypes = new HashSet<>(); private HashSet<String> mMimeSupertypes = new HashSet<>();
private MimeTypeMap mMimeTypeMap; private MimeTypeMap mMimeTypeMap;
private boolean mAcceptAllMimeTypes;
private boolean mAcceptDirectory;
/** /**
* Contructs a MimeTypeFileFilter object. * Contructs a MimeTypeFilter object.
* @param mimeTypes A list of MIME types this filter accepts. * @param mimeTypes A list of MIME types this filter accepts.
* For example: images/gif, video/*. * For example: images/gif, video/*.
*/ */
public MimeTypeFileFilter(@NonNull List<String> mimeTypes) { public MimeTypeFilter(@NonNull List<String> mimeTypes, boolean acceptDirectory) {
for (String field : mimeTypes) { for (String field : mimeTypes) {
field = field.trim().toLowerCase(Locale.US); field = field.trim().toLowerCase(Locale.US);
if (field.startsWith(".")) { if (field.startsWith(".")) {
mExtensions.add(field.substring(1)); mExtensions.add(field.substring(1));
} else if (field.equals("*/*")) {
mAcceptAllMimeTypes = true;
} else if (field.endsWith("/*")) { } else if (field.endsWith("/*")) {
mMimeSupertypes.add(field.substring(0, field.length() - 2)); mMimeSupertypes.add(field.substring(0, field.length() - 2));
} else if (field.contains("/")) { } else if (field.contains("/")) {
mMimeTypes.add(field); mMimeTypes.add(field);
} else {
// Throw exception?
} }
} }
mMimeTypeMap = MimeTypeMap.getSingleton(); mMimeTypeMap = MimeTypeMap.getSingleton();
mAcceptDirectory = acceptDirectory;
} }
@Override /**
public boolean accept(@NonNull File file) { * Returns true if either the uri or the mimeType is accepted by the MimeTypeFilter
if (file.isDirectory()) { * @param uri
return true; * @param mimeType
} */
public boolean accept(Uri uri, String mimeType) {
String uri = file.toURI().toString(); if (uri != null) {
String ext = MimeTypeMap.getFileExtensionFromUrl(uri).toLowerCase(Locale.US); String fileExtension =
if (mExtensions.contains(ext)) { MimeTypeMap.getFileExtensionFromUrl(uri.toString()).toLowerCase(Locale.US);
return true; if (mExtensions.contains(fileExtension)) {
return true;
}
if (mimeType == null) {
mimeType = getMimeTypeFromExtension(fileExtension);
}
} }
String mimeType = getMimeTypeFromExtension(ext);
if (mimeType != null) { if (mimeType != null) {
if (mMimeTypes.contains(mimeType) if (mAcceptAllMimeTypes || mMimeTypes.contains(mimeType)
|| mMimeSupertypes.contains(getMimeSupertype(mimeType))) { || mMimeSupertypes.contains(getMimeSupertype(mimeType))) {
return true; return true;
} }
} }
return false; return false;
} }
private HashSet<String> getAcceptedSupertypes() { @Override
HashSet<String> supertypes = new HashSet<>(); public boolean accept(@NonNull File file) {
supertypes.addAll(mMimeSupertypes); if (file.isDirectory()) {
for (String mimeType : mMimeTypes) { return mAcceptDirectory;
supertypes.add(getMimeSupertype(mimeType));
}
for (String ext : mExtensions) {
String mimeType = getMimeTypeFromExtension(ext);
if (mimeType != null) {
supertypes.add(getMimeSupertype(mimeType));
}
} }
return supertypes; return accept(Uri.fromFile(file), null);
} }
private String getMimeTypeFromExtension(@NonNull String ext) { private String getMimeTypeFromExtension(@NonNull String ext) {
...@@ -88,7 +92,7 @@ class MimeTypeFileFilter implements FileFilter { ...@@ -88,7 +92,7 @@ class MimeTypeFileFilter implements FileFilter {
} }
@NonNull @NonNull
private String getMimeSupertype(@NonNull String mimeType) { private static String getMimeSupertype(@NonNull String mimeType) {
return mimeType.split("/", 2)[0]; return mimeType.split("/", 2)[0];
} }
} }
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.net;
import android.net.Uri;
import android.support.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import java.util.ArrayList;
/**
* Tests for MimeTypeFilter.
*/
@RunWith(BaseJUnit4ClassRunner.class)
public class MimeTypeFilterTest {
@Test
@SmallTest
public void testAcceptAllMimeTypes() {
ArrayList<String> mimeTypes = new ArrayList<String>();
mimeTypes.add("*/*");
MimeTypeFilter mimeFilter = new MimeTypeFilter(mimeTypes, false);
Assert.assertTrue(mimeFilter.accept(null, "image/jpeg"));
}
@Test
@SmallTest
public void testAcceptAllImageTypes() {
ArrayList<String> mimeTypes = new ArrayList<String>();
mimeTypes.add("image/*");
MimeTypeFilter mimeFilter = new MimeTypeFilter(mimeTypes, false);
Assert.assertTrue(mimeFilter.accept(null, "image/jpeg"));
Assert.assertTrue(mimeFilter.accept(null, "image/gif"));
}
@Test
@SmallTest
public void testAcceptOnlyOneType() {
ArrayList<String> mimeTypes = new ArrayList<String>();
mimeTypes.add("text/plain");
MimeTypeFilter mimeFilter = new MimeTypeFilter(mimeTypes, false);
Assert.assertTrue(mimeFilter.accept(null, "text/plain"));
Assert.assertFalse(mimeFilter.accept(null, "image/gif"));
}
@Test
@SmallTest
public void testAcceptExtension() {
ArrayList<String> mimeTypes = new ArrayList<String>();
mimeTypes.add(".jpeg");
MimeTypeFilter mimeFilter = new MimeTypeFilter(mimeTypes, false);
Uri jpegUri = Uri.parse("image.jpeg");
Uri gifUri = Uri.parse("image.gif");
Assert.assertTrue(mimeFilter.accept(jpegUri, ""));
Assert.assertFalse(mimeFilter.accept(gifUri, ""));
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment