Fix case-sensitive comparisons of Android/media
There are several places where we determine things based on whether a
path contains Android/media - but these need to be compared ignoring
case.
Factored out common methods in StringUtils, fixed package name of
StringUtils.
Bug: 195101715
Bug: 209892068
Test: atest FileUtilsTest
Test: TEST_MAPPING
Change-Id: Iaf381750bba12654159e943cc9dfe8e87f92cbcd
Merged-In: Iaf381750bba12654159e943cc9dfe8e87f92cbcd
diff --git a/Android.bp b/Android.bp
index 89e4b95..62c38d5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -120,6 +120,7 @@
"src/com/android/providers/media/util/ForegroundThread.java",
"src/com/android/providers/media/util/Logging.java",
"src/com/android/providers/media/util/MimeUtils.java",
+ "src/com/android/providers/media/util/StringUtils.java",
"src/com/android/providers/media/playlist/*.java",
],
sdk_version: "module_current",
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index 659da39..b7aab10 100755
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -433,7 +433,8 @@
static double get_entry_timeout(const string& path, node* node, struct fuse* fuse) {
string media_path = fuse->GetEffectiveRootPath() + "/Android/media";
if (fuse->disable_dentry_cache || node->ShouldInvalidate() ||
- is_package_owned_path(path, fuse->path) || android::base::StartsWith(path, media_path)) {
+ is_package_owned_path(path, fuse->path) ||
+ android::base::StartsWithIgnoreCase(path, media_path)) {
// We set dentry timeout to 0 for the following reasons:
// 1. The dentry cache was completely disabled
// 2.1 Case-insensitive lookups need to invalidate other case-insensitive dentry matches
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 3a12e37..af40b6b 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -235,6 +235,7 @@
import com.android.providers.media.util.PermissionUtils;
import com.android.providers.media.util.SQLiteQueryBuilder;
import com.android.providers.media.util.SpecialFormatDetector;
+import com.android.providers.media.util.StringUtils;
import com.android.providers.media.util.UserCache;
import com.android.providers.media.util.XmpInterface;
@@ -2271,7 +2272,7 @@
supportedPrimaryMimeType = ClipDescription.MIMETYPE_UNKNOWN;
}
return (supportedPrimaryMimeType.equalsIgnoreCase(ClipDescription.MIMETYPE_UNKNOWN) ||
- MimeUtils.startsWithIgnoreCase(mimeType, supportedPrimaryMimeType));
+ StringUtils.startsWithIgnoreCase(mimeType, supportedPrimaryMimeType));
}
/**
@@ -7599,7 +7600,7 @@
// Offer thumbnail of media, when requested
final boolean wantsThumb = (opts != null) && opts.containsKey(ContentResolver.EXTRA_SIZE)
- && MimeUtils.startsWithIgnoreCase(mimeTypeFilter, "image/");
+ && StringUtils.startsWithIgnoreCase(mimeTypeFilter, "image/");
if (wantsThumb) {
final ParcelFileDescriptor pfd = ensureThumbnail(uri, signal);
return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
diff --git a/src/com/android/providers/media/PermissionActivity.java b/src/com/android/providers/media/PermissionActivity.java
index 5b53e7d..50d2557 100644
--- a/src/com/android/providers/media/PermissionActivity.java
+++ b/src/com/android/providers/media/PermissionActivity.java
@@ -73,6 +73,7 @@
import com.android.providers.media.MediaProvider.LocalUriMatcher;
import com.android.providers.media.util.Metrics;
+import com.android.providers.media.util.StringUtils;
import java.io.IOException;
import java.util.ArrayList;
@@ -85,7 +86,6 @@
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
-import src.com.android.providers.media.util.StringUtils;
/**
* Permission dialog that asks for user confirmation before performing a
diff --git a/src/com/android/providers/media/photopicker/ui/AlbumGridHolder.java b/src/com/android/providers/media/photopicker/ui/AlbumGridHolder.java
index 67fed45..1585d3b 100644
--- a/src/com/android/providers/media/photopicker/ui/AlbumGridHolder.java
+++ b/src/com/android/providers/media/photopicker/ui/AlbumGridHolder.java
@@ -28,12 +28,12 @@
import com.android.providers.media.R;
import com.android.providers.media.photopicker.data.model.Category;
+import com.android.providers.media.util.StringUtils;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
-import src.com.android.providers.media.util.StringUtils;
/**
* ViewHolder of a album item within a RecyclerView.
diff --git a/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java b/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
index 5e8d2ac..e0ced0c 100644
--- a/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
+++ b/src/com/android/providers/media/photopicker/ui/PhotosTabFragment.java
@@ -35,12 +35,12 @@
import com.android.providers.media.photopicker.data.model.Category.CategoryType;
import com.android.providers.media.photopicker.data.model.Item;
import com.android.providers.media.photopicker.util.LayoutModeUtils;
+import com.android.providers.media.util.StringUtils;
import com.google.android.material.snackbar.Snackbar;
import java.text.NumberFormat;
import java.util.Locale;
-import src.com.android.providers.media.util.StringUtils;
/**
* Photos tab fragment for showing the photos
diff --git a/src/com/android/providers/media/util/FileUtils.java b/src/com/android/providers/media/util/FileUtils.java
index b907e43..8da9e97 100644
--- a/src/com/android/providers/media/util/FileUtils.java
+++ b/src/com/android/providers/media/util/FileUtils.java
@@ -736,8 +736,8 @@
extFromMimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
}
- if (MimeUtils.equalIgnoreCase(mimeType, mimeTypeFromExt)
- || MimeUtils.equalIgnoreCase(ext, extFromMimeType)) {
+ if (StringUtils.equalIgnoreCase(mimeType, mimeTypeFromExt)
+ || StringUtils.equalIgnoreCase(ext, extFromMimeType)) {
// Extension maps back to requested MIME type; allow it
} else {
// No match; insist that create file matches requested MIME
@@ -1167,7 +1167,7 @@
if (relativePath != null) {
final String externalMediaDir = (crossUserRoot == null || crossUserRoot.isEmpty())
? "Android/media" : crossUserRoot + "/Android/media";
- return relativePath.startsWith(externalMediaDir);
+ return StringUtils.startsWithIgnoreCase(relativePath, externalMediaDir);
}
return false;
}
diff --git a/src/com/android/providers/media/util/MimeUtils.java b/src/com/android/providers/media/util/MimeUtils.java
index 38c3635..65f3e83 100644
--- a/src/com/android/providers/media/util/MimeUtils.java
+++ b/src/com/android/providers/media/util/MimeUtils.java
@@ -29,23 +29,6 @@
import java.util.Objects;
public class MimeUtils {
- /**
- * Variant of {@link Objects#equal(Object, Object)} but which tests with
- * case-insensitivity.
- */
- public static boolean equalIgnoreCase(@Nullable String a, @Nullable String b) {
- return (a != null) && a.equalsIgnoreCase(b);
- }
-
- /**
- * Variant of {@link String#startsWith(String)} but which tests with
- * case-insensitivity.
- */
- public static boolean startsWithIgnoreCase(@Nullable String target, @Nullable String other) {
- if (target == null || other == null) return false;
- if (other.length() > target.length()) return false;
- return target.regionMatches(true, 0, other, 0, other.length());
- }
/**
* Resolve the MIME type of the given file, returning
@@ -114,17 +97,17 @@
public static boolean isAudioMimeType(@Nullable String mimeType) {
if (mimeType == null) return false;
- return startsWithIgnoreCase(mimeType, "audio/");
+ return StringUtils.startsWithIgnoreCase(mimeType, "audio/");
}
public static boolean isVideoMimeType(@Nullable String mimeType) {
if (mimeType == null) return false;
- return startsWithIgnoreCase(mimeType, "video/");
+ return StringUtils.startsWithIgnoreCase(mimeType, "video/");
}
public static boolean isImageMimeType(@Nullable String mimeType) {
if (mimeType == null) return false;
- return startsWithIgnoreCase(mimeType, "image/");
+ return StringUtils.startsWithIgnoreCase(mimeType, "image/");
}
public static boolean isImageOrVideoMediaType(int mediaType) {
@@ -170,7 +153,7 @@
public static boolean isDocumentMimeType(@Nullable String mimeType) {
if (mimeType == null) return false;
- if (startsWithIgnoreCase(mimeType, "text/")) return true;
+ if (StringUtils.startsWithIgnoreCase(mimeType, "text/")) return true;
switch (mimeType.toLowerCase(Locale.ROOT)) {
case "application/epub+zip":
diff --git a/src/com/android/providers/media/util/StringUtils.java b/src/com/android/providers/media/util/StringUtils.java
index f73a58a..b6f70e0 100644
--- a/src/com/android/providers/media/util/StringUtils.java
+++ b/src/com/android/providers/media/util/StringUtils.java
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-package src.com.android.providers.media.util;
+package com.android.providers.media.util;
import android.icu.text.MessageFormat;
-import java.io.File;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
+
import android.content.res.Resources;
+import androidx.annotation.Nullable;
+
public class StringUtils {
/**
@@ -37,4 +40,23 @@
arguments.put("count", count);
return msgFormat.format(arguments);
}
+
+
+ /**
+ * Variant of {@link String#startsWith(String)} but which tests with
+ * case-insensitivity.
+ */
+ public static boolean startsWithIgnoreCase(@Nullable String target, @Nullable String other) {
+ if (target == null || other == null) return false;
+ if (other.length() > target.length()) return false;
+ return target.regionMatches(true, 0, other, 0, other.length());
+ }
+
+ /**
+ * Variant of {@link Objects#equal(Object, Object)} but which tests with
+ * case-insensitivity.
+ */
+ public static boolean equalIgnoreCase(@Nullable String a, @Nullable String b) {
+ return (a != null) && a.equalsIgnoreCase(b);
+ }
}
diff --git a/tests/src/com/android/providers/media/util/FileUtilsTest.java b/tests/src/com/android/providers/media/util/FileUtilsTest.java
index 5d70aee..398f431 100644
--- a/tests/src/com/android/providers/media/util/FileUtilsTest.java
+++ b/tests/src/com/android/providers/media/util/FileUtilsTest.java
@@ -944,6 +944,7 @@
"/storage/0000-0000/AppClone/"
}) {
assertTrue(isExternalMediaDirectory(prefix + "Android/media/foo.jpg", "AppClone"));
+ assertTrue(isExternalMediaDirectory(prefix + "android/mEdia/foo.jpg", "AppClone"));
assertFalse(isExternalMediaDirectory(prefix + "Android/media/foo.jpg", "NotAppClone"));
}
}
diff --git a/tests/src/com/android/providers/media/util/MimeUtilsTest.java b/tests/src/com/android/providers/media/util/MimeUtilsTest.java
index b57b5c5..9491a98 100644
--- a/tests/src/com/android/providers/media/util/MimeUtilsTest.java
+++ b/tests/src/com/android/providers/media/util/MimeUtilsTest.java
@@ -16,9 +16,6 @@
package com.android.providers.media.util;
-import static com.android.providers.media.util.MimeUtils.equalIgnoreCase;
-import static com.android.providers.media.util.MimeUtils.startsWithIgnoreCase;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -42,30 +39,6 @@
}
@Test
- public void testEqualIgnoreCase() throws Exception {
- assertTrue(equalIgnoreCase("image/jpg", "image/jpg"));
- assertTrue(equalIgnoreCase("image/jpg", "Image/Jpg"));
-
- assertFalse(equalIgnoreCase("image/jpg", "image/png"));
- assertFalse(equalIgnoreCase("image/jpg", null));
- assertFalse(equalIgnoreCase(null, "image/jpg"));
- assertFalse(equalIgnoreCase(null, null));
- }
-
- @Test
- public void testStartsWithIgnoreCase() throws Exception {
- assertTrue(startsWithIgnoreCase("image/jpg", "image/"));
- assertTrue(startsWithIgnoreCase("Image/Jpg", "image/"));
-
- assertFalse(startsWithIgnoreCase("image/", "image/jpg"));
-
- assertFalse(startsWithIgnoreCase("image/jpg", "audio/"));
- assertFalse(startsWithIgnoreCase("image/jpg", null));
- assertFalse(startsWithIgnoreCase(null, "audio/"));
- assertFalse(startsWithIgnoreCase(null, null));
- }
-
- @Test
public void testResolveMimeType() throws Exception {
assertEquals("image/jpeg",
MimeUtils.resolveMimeType(new File("foo.jpg")));
diff --git a/tests/src/com/android/providers/media/util/StringUtilsTest.java b/tests/src/com/android/providers/media/util/StringUtilsTest.java
new file mode 100644
index 0000000..51a571e
--- /dev/null
+++ b/tests/src/com/android/providers/media/util/StringUtilsTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 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 com.android.providers.media.util;
+
+import static com.android.providers.media.util.StringUtils.equalIgnoreCase;
+import static com.android.providers.media.util.StringUtils.startsWithIgnoreCase;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class StringUtilsTest {
+ @Test
+ public void testEqualIgnoreCase() throws Exception {
+ assertTrue(equalIgnoreCase("image/jpg", "image/jpg"));
+ assertTrue(equalIgnoreCase("image/jpg", "Image/Jpg"));
+
+ assertFalse(equalIgnoreCase("image/jpg", "image/png"));
+ assertFalse(equalIgnoreCase("image/jpg", null));
+ assertFalse(equalIgnoreCase(null, "image/jpg"));
+ assertFalse(equalIgnoreCase(null, null));
+ }
+
+ @Test
+ public void testStartsWithIgnoreCase() throws Exception {
+ assertTrue(startsWithIgnoreCase("image/jpg", "image/"));
+ assertTrue(startsWithIgnoreCase("Image/Jpg", "image/"));
+
+ assertFalse(startsWithIgnoreCase("image/", "image/jpg"));
+
+ assertFalse(startsWithIgnoreCase("image/jpg", "audio/"));
+ assertFalse(startsWithIgnoreCase("image/jpg", null));
+ assertFalse(startsWithIgnoreCase(null, "audio/"));
+ assertFalse(startsWithIgnoreCase(null, null));
+ }
+}