[coastguard skipped] Merge sparse cherrypicks from sparse-13775243-L92100030014435199 into 24Q3-platform-release.
COASTGUARD_SKIP: I91c44428dc730be4cf42b3cb9c02e8eca4440f81
COASTGUARD_SKIP: I6cb652cecf3a3023532bb17eee275bf66fee250d
COASTGUARD_SKIP: Ibe8a80d65c4dff6368352944e004c5c934430953
Change-Id: Ie412064bca0eb653cbc36f45b2ed966488856b38
diff --git a/src/com/android/providers/media/AccessChecker.java b/src/com/android/providers/media/AccessChecker.java
index 23704d5..4dea3c4 100644
--- a/src/com/android/providers/media/AccessChecker.java
+++ b/src/com/android/providers/media/AccessChecker.java
@@ -55,8 +55,10 @@
import static com.android.providers.media.LocalUriMatcher.VIDEO_THUMBNAILS;
import static com.android.providers.media.LocalUriMatcher.VIDEO_THUMBNAILS_ID;
import static com.android.providers.media.MediaGrants.PACKAGE_USER_ID_COLUMN;
+import static com.android.providers.media.MediaProvider.INCLUDED_DEFAULT_DIRECTORIES;
import static com.android.providers.media.util.DatabaseUtils.bindSelection;
+import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.MediaStore.Files.FileColumns;
import android.provider.MediaStore.MediaColumns;
@@ -67,8 +69,6 @@
import androidx.annotation.VisibleForTesting;
import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
/**
* Class responsible for performing all access checks (read/write access states for calling package)
@@ -267,7 +267,7 @@
@NonNull
public static String getWhereForConstrainedAccess(
@NonNull LocalCallingIdentity callingIdentity, int uriType,
- boolean forWrite, Optional<List<String>> includedDefaultDirectoriesOptional) {
+ boolean forWrite, @NonNull Bundle extras) {
switch (uriType) {
case AUDIO_MEDIA_ID:
case AUDIO_MEDIA: {
@@ -361,12 +361,9 @@
// Allow access to file in directories. This si particularly used only for
// SystemGallery use-case
- if (includedDefaultDirectoriesOptional.isPresent()) {
- final String defaultDirectorySql = getWhereForDefaultDirectoryMatch(
- includedDefaultDirectoriesOptional.get());
- if (defaultDirectorySql != null) {
- options.add(defaultDirectorySql);
- }
+ final String defaultDirectorySql = getWhereForDefaultDirectoryMatch(extras);
+ if (defaultDirectorySql != null) {
+ options.add(defaultDirectorySql);
}
return TextUtils.join(" OR ", options);
@@ -444,11 +441,12 @@
* @see MediaProvider#INCLUDED_DEFAULT_DIRECTORIES
*/
@Nullable
- private static String getWhereForDefaultDirectoryMatch(
- List<String> includedDefaultDirectories) {
+ private static String getWhereForDefaultDirectoryMatch(@NonNull Bundle extras) {
+ final ArrayList<String> includedDefaultDirs = extras.getStringArrayList(
+ INCLUDED_DEFAULT_DIRECTORIES);
final ArrayList<String> options = new ArrayList<>();
- if (includedDefaultDirectories != null) {
- for (String defaultDir : includedDefaultDirectories) {
+ if (includedDefaultDirs != null) {
+ for (String defaultDir : includedDefaultDirs) {
options.add(FileColumns.RELATIVE_PATH + " LIKE '" + defaultDir + "/%'");
}
}
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index fc2b34d..34e726a 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -421,6 +421,15 @@
private static final String FILE_DATABASE_UUID = ".database_uuid";
/**
+ * Specify what default directories the caller gets full access to. By default, the caller
+ * shouldn't get full access to any default dirs.
+ * But for example, we do an exception for System Gallery apps and allow them full access to:
+ * DCIM, Pictures, Movies.
+ */
+ static final String INCLUDED_DEFAULT_DIRECTORIES =
+ "android:included-default-directories";
+
+ /**
* Value indicating that operations should include database rows matching the criteria defined
* by this key only when calling package has write permission to the database row or column is
* {@column MediaColumns#IS_PENDING} and is set by FUSE.
@@ -2841,8 +2850,7 @@
}
final String writeAccessCheckSql = getWhereForConstrainedAccess(mCallingIdentity.get(),
- uriType, /* forWrite */ true, /* includedDefaultDirectoriesOptional */
- Optional.empty());
+ uriType, /* forWrite */ true, Bundle.EMPTY);
final String matchWritableRowsClause = String.format("%s=0 OR (%s=1 AND (%s OR %s))",
column, column, MATCH_PENDING_FROM_FUSE, writeAccessCheckSql);
@@ -3001,8 +3009,7 @@
final String[] selectionArgs = new String[] {path};
final SQLiteQueryBuilder qbForQuery =
- getQueryBuilder(TYPE_QUERY, match, uri, Bundle.EMPTY,
- null, /* includedDefaultDirectoriesOptional */ Optional.empty());
+ getQueryBuilder(TYPE_QUERY, match, uri, Bundle.EMPTY, null);
try (Cursor c = qbForQuery.query(helper, new String[] {FileColumns.OWNER_PACKAGE_NAME},
selection, selectionArgs, null, null, null, null, null)) {
if (!c.moveToFirst()) {
@@ -3019,8 +3026,7 @@
}
final SQLiteQueryBuilder qbForUpdate =
- getQueryBuilder(TYPE_UPDATE, match, uri, Bundle.EMPTY, null,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ getQueryBuilder(TYPE_UPDATE, match, uri, Bundle.EMPTY, null);
ContentValues values = new ContentValues();
values.put(FileColumns.OWNER_PACKAGE_NAME, "null");
return qbForUpdate.update(helper, values, selection, selectionArgs) == 1;
@@ -3028,15 +3034,14 @@
private boolean updateDatabaseForFuseRename(@NonNull DatabaseHelper helper,
@NonNull String oldPath, @NonNull String newPath, @NonNull ContentValues values) {
- return updateDatabaseForFuseRename(helper, oldPath, newPath, values, Bundle.EMPTY,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ return updateDatabaseForFuseRename(helper, oldPath, newPath, values, Bundle.EMPTY);
}
private boolean updateDatabaseForFuseRename(@NonNull DatabaseHelper helper,
@NonNull String oldPath, @NonNull String newPath, @NonNull ContentValues values,
- @NonNull Bundle qbExtras, Optional<List<String>> includedDefaultDirectoriesOptional) {
+ @NonNull Bundle qbExtras) {
return updateDatabaseForFuseRename(helper, oldPath, newPath, values, qbExtras,
- FileUtils.getContentUriForPath(oldPath), includedDefaultDirectoriesOptional);
+ FileUtils.getContentUriForPath(oldPath));
}
/**
@@ -3044,12 +3049,10 @@
*/
private boolean updateDatabaseForFuseRename(@NonNull DatabaseHelper helper,
@NonNull String oldPath, @NonNull String newPath, @NonNull ContentValues values,
- @NonNull Bundle qbExtras, Uri uriOldPath,
- Optional<List<String>> includedDefaultDirectoriesOptional) {
+ @NonNull Bundle qbExtras, Uri uriOldPath) {
boolean allowHidden = isCallingPackageAllowedHidden();
final SQLiteQueryBuilder qbForUpdate = getQueryBuilder(TYPE_UPDATE,
- matchUri(uriOldPath, allowHidden), uriOldPath, qbExtras, null,
- includedDefaultDirectoriesOptional);
+ matchUri(uriOldPath, allowHidden), uriOldPath, qbExtras, null);
// uriOldPath may use Files uri which doesn't allow modifying AudioColumns. Include
// AudioColumns projection map if we are modifying any audio columns while renaming
@@ -3086,8 +3089,7 @@
}
if (retryUpdateWithReplace) {
- if (deleteForFuseRename(helper, oldPath, newPath, qbExtras, selection, allowHidden,
- includedDefaultDirectoriesOptional)) {
+ if (deleteForFuseRename(helper, oldPath, newPath, qbExtras, selection, allowHidden)) {
Log.i(TAG, "Retrying database update after deleting conflicting entry");
count = qbForUpdate.update(helper, values, selection, new String[]{oldPath});
} else {
@@ -3098,15 +3100,13 @@
}
private boolean deleteForFuseRename(DatabaseHelper helper, String oldPath,
- String newPath, Bundle qbExtras, String selection, boolean allowHidden,
- Optional<List<String>> includedDefaultDirectoriesOptional) {
+ String newPath, Bundle qbExtras, String selection, boolean allowHidden) {
// We are replacing file in newPath with file in oldPath. If calling package has
// write permission for newPath, delete existing database entry and retry update.
final Uri uriNewPath = FileUtils.getContentUriForPath(oldPath);
final SQLiteQueryBuilder qbForDelete = getQueryBuilder(TYPE_DELETE,
- matchUri(uriNewPath, allowHidden), uriNewPath, qbExtras, null,
- includedDefaultDirectoriesOptional);
- if (qbForDelete.delete(helper, selection, new String[]{newPath}) == 1) {
+ matchUri(uriNewPath, allowHidden), uriNewPath, qbExtras, null);
+ if (qbForDelete.delete(helper, selection, new String[] {newPath}) == 1) {
return true;
}
// Check if delete can be done using other URI grants
@@ -3234,7 +3234,7 @@
final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_UPDATE,
matchUri(uriOldPath, isCallingPackageAllowedHidden()), uriOldPath, Bundle.EMPTY,
- null, /* includedDefaultDirectoriesOptional */ Optional.empty());
+ null);
final DatabaseHelper helper;
try {
helper = getDatabaseForUri(uriOldPath);
@@ -3326,6 +3326,9 @@
helper.beginTransaction();
try {
+ final Bundle qbExtras = new Bundle();
+ qbExtras.putStringArrayList(INCLUDED_DEFAULT_DIRECTORIES,
+ getIncludedDefaultDirectories());
final boolean wasHidden = FileUtils.shouldDirBeHidden(new File(oldPath));
final boolean isHidden = FileUtils.shouldDirBeHidden(new File(newPath));
for (String filePath : fileList) {
@@ -3334,7 +3337,7 @@
if(!updateDatabaseForFuseRename(helper, oldPath + "/" + filePath, newFilePath,
getContentValuesForFuseRename(newFilePath, mimeType, wasHidden, isHidden,
/* isSameMimeType */ true),
- new Bundle(), Optional.of(getIncludedDefaultDirectories()))) {
+ qbExtras)) {
Log.e(TAG, "Calling package doesn't have write permission to rename file.");
return OsConstants.EPERM;
}
@@ -3458,7 +3461,7 @@
return false;
}
return updateDatabaseForFuseRename(helper, oldPath, newPath, contentValues, Bundle.EMPTY,
- oldPathGrantedUri, /* includedDefaultDirectoriesOptional */ Optional.empty());
+ oldPathGrantedUri);
}
/**
@@ -3639,8 +3642,7 @@
type = TYPE_QUERY;
}
- final SQLiteQueryBuilder qb = getQueryBuilder(type, table, uri, Bundle.EMPTY,
- null, /* includedDefaultDirectoriesOptional */ Optional.empty());
+ final SQLiteQueryBuilder qb = getQueryBuilder(type, table, uri, Bundle.EMPTY, null);
try (Cursor c = qb.query(helper,
new String[] { BaseColumns._ID }, null, null, null, null, null, null, null)) {
if (c.getCount() == 1) {
@@ -3730,6 +3732,9 @@
PulledMetrics.logVolumeAccessViaMediaProvider(getCallingUidOrSelf(), volumeName);
queryArgs = (queryArgs != null) ? queryArgs : new Bundle();
+ // INCLUDED_DEFAULT_DIRECTORIES extra should only be set inside MediaProvider.
+ queryArgs.remove(INCLUDED_DEFAULT_DIRECTORIES);
+
final ArraySet<String> honoredArgs = new ArraySet<>();
DatabaseUtils.resolveQueryArgs(queryArgs, honoredArgs::add, this::ensureCustomCollator);
@@ -3787,7 +3792,7 @@
final DatabaseHelper helper = getDatabaseForUri(uri);
final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_QUERY, table, uri, queryArgs,
- honoredArgs::add, /* includedDefaultDirectoriesOptional */ Optional.empty());
+ honoredArgs::add);
// Allowing hidden column _user_id for this query to support Cloned Profile use case.
if (table == FILES) {
qb.allowColumn(FileColumns._USER_ID);
@@ -5269,7 +5274,7 @@
// row irrespective of is_download=1.
final Uri uri = FileUtils.getContentUriForPath(path);
SQLiteQueryBuilder qb = getQueryBuilder(TYPE_UPDATE, matchUri(uri, allowHidden), uri,
- extras, null, /* includedDefaultDirectoriesOptional */ Optional.empty());
+ extras, null);
// We won't be able to update columns that are not part of projection map of Files table. We
// have already checked strict columns in previous insert operation which failed with
@@ -5347,6 +5352,9 @@
// REDACTED_URI_BUNDLE_KEY extra should only be set inside MediaProvider.
extras.remove(QUERY_ARG_REDACTED_URI);
+ // INCLUDED_DEFAULT_DIRECTORIES extra should only be set inside MediaProvider.
+ extras.remove(INCLUDED_DEFAULT_DIRECTORIES);
+
final boolean allowHidden = isCallingPackageAllowedHidden();
final int match = matchUri(uri, allowHidden);
@@ -5495,8 +5503,7 @@
long rowId = -1;
Uri newUri = null;
- final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_INSERT, match, uri, extras, null,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_INSERT, match, uri, extras, null);
switch (match) {
case IMAGES_MEDIA: {
@@ -5768,8 +5775,7 @@
// We already handle the required permission checks for the app before we get here
final LocalCallingIdentity token = clearLocalCallingIdentity();
try {
- return getQueryBuilder(type, match, uri, extras, honored,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ return getQueryBuilder(type, match, uri, extras, honored);
} finally {
restoreLocalCallingIdentity(token);
}
@@ -5791,20 +5797,17 @@
* </ul>
*/
private @NonNull SQLiteQueryBuilder getQueryBuilder(int type, int match,
- @NonNull Uri uri, @NonNull Bundle extras, @Nullable Consumer<String> honored,
- Optional<List<String>> includedDefaultDirectoriesOptional) {
+ @NonNull Uri uri, @NonNull Bundle extras, @Nullable Consumer<String> honored) {
Trace.beginSection("MP.getQueryBuilder");
try {
- return getQueryBuilderInternal(type, match, uri, extras, honored,
- includedDefaultDirectoriesOptional);
+ return getQueryBuilderInternal(type, match, uri, extras, honored);
} finally {
Trace.endSection();
}
}
private @NonNull SQLiteQueryBuilder getQueryBuilderInternal(int type, int match,
- @NonNull Uri uri, @NonNull Bundle extras, @Nullable Consumer<String> honored,
- Optional<List<String>> includedDefaultDirectoriesOptional) {
+ @NonNull Uri uri, @NonNull Bundle extras, @Nullable Consumer<String> honored) {
final boolean forWrite;
switch (type) {
case TYPE_QUERY: forWrite = false; break;
@@ -5874,8 +5877,7 @@
// to commit to this as an API.
final boolean includeAllVolumes = shouldIncludeRecentlyUnmountedVolumes(uri, extras);
- appendAccessCheckQuery(qb, forWrite, uri, match, extras, volumeName,
- includedDefaultDirectoriesOptional);
+ appendAccessCheckQuery(qb, forWrite, uri, match, extras, volumeName);
switch (match) {
case IMAGES_MEDIA_ID:
@@ -6273,8 +6275,7 @@
}
private void appendAccessCheckQuery(@NonNull SQLiteQueryBuilder qb, boolean forWrite,
- @NonNull Uri uri, int uriType, @NonNull Bundle extras, @NonNull String volumeName,
- Optional<List<String>> includedDefaultDirectoriesOptional) {
+ @NonNull Uri uri, int uriType, @NonNull Bundle extras, @NonNull String volumeName) {
Objects.requireNonNull(extras);
final Uri redactedUri = extras.getParcelable(QUERY_ARG_REDACTED_URI);
@@ -6315,7 +6316,7 @@
// Allow access to files which are owned by the caller. Or allow access to files
// based on legacy or any other special access permissions.
options.add(getWhereForConstrainedAccess(mCallingIdentity.get(), uriType, forWrite,
- includedDefaultDirectoriesOptional));
+ extras));
}
} else {
if (isLatestSelectionOnlyRequired) {
@@ -6325,7 +6326,7 @@
// Allow access to files which are owned by the caller. Or allow access to files
// based on legacy or any other special access permissions.
options.add(getWhereForConstrainedAccess(mCallingIdentity.get(), uriType, forWrite,
- includedDefaultDirectoriesOptional));
+ extras));
}
appendWhereStandalone(qb, TextUtils.join(" OR ", options));
@@ -6419,6 +6420,9 @@
return 0;
}
+ // INCLUDED_DEFAULT_DIRECTORIES extra should only be set inside MediaProvider.
+ extras.remove(INCLUDED_DEFAULT_DIRECTORIES);
+
uri = safeUncanonicalize(uri);
final boolean allowHidden = isCallingPackageAllowedHidden();
final int match = matchUri(uri, allowHidden);
@@ -6494,8 +6498,7 @@
}
}
- final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_DELETE, match, uri, extras, null,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_DELETE, match, uri, extras, null);
{
// Give callers interacting with a specific media item a chance to
@@ -6633,8 +6636,7 @@
// 2. delete file row from the db
final boolean allowHidden = isCallingPackageAllowedHidden();
final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_DELETE,
- matchUri(uriGranted, allowHidden), uriGranted, extras, null,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ matchUri(uriGranted, allowHidden), uriGranted, extras, null);
int count = qb.delete(helper, BaseColumns._ID + "=" + id, null);
if (isDownload == 1) {
@@ -7957,6 +7959,8 @@
// Related items are only considered for new media creation, and they
// can't be leveraged to move existing content into blocked locations
extras.remove(QUERY_ARG_RELATED_URI);
+ // INCLUDED_DEFAULT_DIRECTORIES extra should only be set inside MediaProvider.
+ extras.remove(INCLUDED_DEFAULT_DIRECTORIES);
final String userWhere = extras.getString(QUERY_ARG_SQL_SELECTION);
final String[] userWhereArgs = extras.getStringArray(QUERY_ARG_SQL_SELECTION_ARGS);
@@ -8029,8 +8033,7 @@
}
}
- final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_UPDATE, match, uri, extras, null,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_UPDATE, match, uri, extras, null);
// Give callers interacting with a specific media item a chance to
// escalate access if they don't already have it
@@ -8549,8 +8552,7 @@
extras.putInt(QUERY_ARG_MATCH_PENDING, MATCH_INCLUDE);
extras.putInt(QUERY_ARG_MATCH_TRASHED, MATCH_INCLUDE);
final SQLiteQueryBuilder qbForReplace = getQueryBuilder(TYPE_DELETE,
- matchUri(uri, allowHidden), uri, extras, null,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ matchUri(uri, allowHidden), uri, extras, null);
final long rowId = getIdIfPathOwnedByPackages(qbForReplace, helper, path,
mCallingIdentity.get().getSharedPackagesAsString());
@@ -8846,8 +8848,7 @@
try {
helper = getDatabaseForUri(membersUri);
qb = getQueryBuilder(TYPE_DELETE, AUDIO_PLAYLISTS_ID_MEMBERS,
- membersUri, queryArgs, null,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ membersUri, queryArgs, null);
} catch (VolumeNotFoundException ignored) {
return new int[0];
}
@@ -10856,8 +10857,7 @@
// First, check to see if caller has direct write access
if (forWrite) {
- final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_UPDATE, table, uri, extras,
- null, /* includedDefaultDirectoriesOptional */ Optional.empty());
+ final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_UPDATE, table, uri, extras, null);
qb.allowColumn(SQLiteQueryBuilder.ROWID_COLUMN);
try (Cursor c = qb.query(helper, new String[] { SQLiteQueryBuilder.ROWID_COLUMN },
selection, selectionArgs, null, null, null, null, null)) {
@@ -10881,8 +10881,7 @@
}
// Second, check to see if caller has direct read access
- final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_QUERY, table, uri, extras, null,
- /* includedDefaultDirectoriesOptional */ Optional.empty());
+ final SQLiteQueryBuilder qb = getQueryBuilder(TYPE_QUERY, table, uri, extras, null);
qb.allowColumn(SQLiteQueryBuilder.ROWID_COLUMN);
try (Cursor c = qb.query(helper, new String[] { SQLiteQueryBuilder.ROWID_COLUMN },
selection, selectionArgs, null, null, null, null, null)) {
diff --git a/src/com/android/providers/media/photopicker/data/PickerDbFacade.java b/src/com/android/providers/media/photopicker/data/PickerDbFacade.java
index 7714109..4e248c8 100644
--- a/src/com/android/providers/media/photopicker/data/PickerDbFacade.java
+++ b/src/com/android/providers/media/photopicker/data/PickerDbFacade.java
@@ -32,7 +32,6 @@
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.database.MatrixCursor;
import android.database.MergeCursor;
import android.database.sqlite.SQLiteConstraintException;
@@ -1045,31 +1044,11 @@
}
private Cursor queryMediaIdForAppsLocked(@NonNull SQLiteQueryBuilder qb,
- @NonNull String[] columns, @NonNull String[] selectionArgs,
+ @NonNull String[] projection, @NonNull String[] selectionArgs,
String pickerSegmentType) {
- final Cursor cursor =
- qb.query(mDatabase, getMediaStoreProjectionLocked(columns, pickerSegmentType),
- /* selection */ null, selectionArgs, /* groupBy */ null, /* having */ null,
- /* orderBy */ null, /* limitStr */ null);
-
- if (columns == null || columns.length == 0 || cursor.getColumnCount() == columns.length) {
- return cursor;
- } else {
- // An unknown column was encountered. Populate it will null for backwards compatibility.
- final MatrixCursor result = new MatrixCursor(columns);
- if (cursor.moveToFirst()) {
- do {
- final ContentValues contentValues = new ContentValues();
- DatabaseUtils.cursorRowToContentValues(cursor, contentValues);
- final MatrixCursor.RowBuilder rowBuilder = result.newRow();
- for (String column : columns) {
- rowBuilder.add(column, contentValues.get(column));
- }
- } while (cursor.moveToNext());
- }
- cursor.close();
- return result;
- }
+ return qb.query(mDatabase, getMediaStoreProjectionLocked(projection, pickerSegmentType),
+ /* selection */ null, selectionArgs, /* groupBy */ null, /* having */ null,
+ /* orderBy */ null, /* limitStr */ null);
}
/**
@@ -1221,51 +1200,54 @@
}
private String[] getMediaStoreProjectionLocked(String[] columns, String pickerSegmentType) {
- final List<String> projection = new ArrayList<>();
+ final String[] projection = new String[columns.length];
- for (int i = 0; i < columns.length; i++) {
+ for (int i = 0; i < projection.length; i++) {
switch (columns[i]) {
case PickerMediaColumns.DATA:
- projection.add(getProjectionDataLocked(PickerMediaColumns.DATA,
- pickerSegmentType));
+ projection[i] = getProjectionDataLocked(PickerMediaColumns.DATA,
+ pickerSegmentType);
break;
case PickerMediaColumns.DISPLAY_NAME:
- projection.add(getProjectionSimple(
- getDisplayNameSql(), PickerMediaColumns.DISPLAY_NAME));
+ projection[i] =
+ getProjectionSimple(
+ getDisplayNameSql(), PickerMediaColumns.DISPLAY_NAME);
break;
case PickerMediaColumns.MIME_TYPE:
- projection.add(getProjectionSimple(
- KEY_MIME_TYPE, PickerMediaColumns.MIME_TYPE));
+ projection[i] =
+ getProjectionSimple(KEY_MIME_TYPE, PickerMediaColumns.MIME_TYPE);
break;
case PickerMediaColumns.DATE_TAKEN:
- projection.add(getProjectionSimple(
- KEY_DATE_TAKEN_MS, PickerMediaColumns.DATE_TAKEN));
+ projection[i] =
+ getProjectionSimple(KEY_DATE_TAKEN_MS, PickerMediaColumns.DATE_TAKEN);
break;
case PickerMediaColumns.SIZE:
- projection.add(getProjectionSimple(KEY_SIZE_BYTES, PickerMediaColumns.SIZE));
+ projection[i] = getProjectionSimple(KEY_SIZE_BYTES, PickerMediaColumns.SIZE);
break;
case PickerMediaColumns.DURATION_MILLIS:
- projection.add(getProjectionSimple(
- KEY_DURATION_MS, PickerMediaColumns.DURATION_MILLIS));
+ projection[i] =
+ getProjectionSimple(
+ KEY_DURATION_MS, PickerMediaColumns.DURATION_MILLIS);
break;
case PickerMediaColumns.HEIGHT:
- projection.add(getProjectionSimple(KEY_HEIGHT, PickerMediaColumns.HEIGHT));
+ projection[i] = getProjectionSimple(KEY_HEIGHT, PickerMediaColumns.HEIGHT);
break;
case PickerMediaColumns.WIDTH:
- projection.add(getProjectionSimple(KEY_WIDTH, PickerMediaColumns.WIDTH));
+ projection[i] = getProjectionSimple(KEY_WIDTH, PickerMediaColumns.WIDTH);
break;
case PickerMediaColumns.ORIENTATION:
- projection.add(getProjectionSimple(
- KEY_ORIENTATION, PickerMediaColumns.ORIENTATION));
+ projection[i] =
+ getProjectionSimple(KEY_ORIENTATION, PickerMediaColumns.ORIENTATION);
break;
default:
+ projection[i] = getProjectionSimple("NULL", columns[i]);
// Ignore unsupported columns; we do not throw error here to support
- // backward compatibility for ACTION_GET_CONTENT takeover.
+ // backward compatibility
Log.w(TAG, "Unexpected Picker column: " + columns[i]);
}
}
- return projection.toArray(new String[0]);
+ return projection;
}
private String getProjectionAuthorityLocked() {
diff --git a/tests/src/com/android/providers/media/AccessCheckerTest.java b/tests/src/com/android/providers/media/AccessCheckerTest.java
index 17286c9..677feb7 100644
--- a/tests/src/com/android/providers/media/AccessCheckerTest.java
+++ b/tests/src/com/android/providers/media/AccessCheckerTest.java
@@ -51,8 +51,7 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
-import android.os.Environment;
-import android.provider.MediaStore;
+import android.os.Bundle;
import android.system.Os;
import android.text.TextUtils;
@@ -64,8 +63,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
@RunWith(AndroidJUnit4.class)
public class AccessCheckerTest {
@@ -367,27 +364,22 @@
// App with no permissions only has access to owned files
assertWithMessage("Expected owned access SQL for Audio collection")
- .that(getWhereForConstrainedAccess(hasNoPerms, AUDIO_MEDIA, false,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasNoPerms, AUDIO_MEDIA, false, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasNoPerms)
+ " OR is_ringtone=1 OR is_alarm=1 OR is_notification=1");
assertWithMessage("Expected owned access SQL for Video collection")
- .that(getWhereForConstrainedAccess(hasNoPerms, VIDEO_MEDIA, false,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasNoPerms, VIDEO_MEDIA, false, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasNoPerms));
assertWithMessage("Expected owned access SQL for Images collection")
- .that(getWhereForConstrainedAccess(hasNoPerms, IMAGES_MEDIA, false,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasNoPerms, IMAGES_MEDIA, false, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasNoPerms));
// App with no permissions only has access to owned files
assertWithMessage("Expected owned access SQL for Downloads collection")
- .that(getWhereForConstrainedAccess(hasNoPerms, DOWNLOADS, false,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasNoPerms, DOWNLOADS, false, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasNoPerms));
assertWithMessage("Expected owned access SQL for FILES collection")
- .that(getWhereForConstrainedAccess(hasNoPerms, FILES, false,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasNoPerms, FILES, false, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasNoPerms));
}
@@ -402,27 +394,12 @@
// App with READ_EXTERNAL_STORAGE or READ_MEDIA_* permission has access to only owned
// non-media files or media files.
assertWithMessage("Expected owned access SQL for Downloads collection")
- .that(getWhereForConstrainedAccess(hasReadMedia, DOWNLOADS, false,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasReadMedia, DOWNLOADS, false, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasReadMedia));
assertWithMessage("Expected owned access SQL for FILES collection")
- .that(getWhereForConstrainedAccess(hasReadMedia, FILES, false,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasReadMedia, FILES, false, Bundle.EMPTY))
.isEqualTo(
getWhereForOwnerPackageMatch(hasReadMedia) + " OR " + getFilesAccessSql());
- assertWithMessage("Expected owned access SQL for FILES collection")
- .that(getWhereForConstrainedAccess(hasReadMedia, FILES, false,
- /* includedDefaultDirectoriesOptional */Optional.of(
- List.of(Environment.DIRECTORY_DCIM, Environment.DIRECTORY_PICTURES,
- Environment.DIRECTORY_MOVIES))))
- .isEqualTo(
- getWhereForOwnerPackageMatch(hasReadMedia) + " OR "
- + getFilesAccessSql() + " OR "
- + MediaStore.Files.FileColumns.RELATIVE_PATH + " LIKE 'DCIM/%'"
- + " OR " + MediaStore.Files.FileColumns.RELATIVE_PATH
- + " LIKE 'Pictures/%'"
- + " OR " + MediaStore.Files.FileColumns.RELATIVE_PATH
- + " LIKE 'Movies/%'");
}
@Test
@@ -432,27 +409,22 @@
// App with no permissions only has access to owned files.
assertWithMessage("Expected owned access SQL for Audio collection")
- .that(getWhereForConstrainedAccess(noPerms, AUDIO_MEDIA, true,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(noPerms, AUDIO_MEDIA, true, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(noPerms)
+ " OR is_ringtone=1 OR is_alarm=1 OR is_notification=1");
assertWithMessage("Expected owned access SQL for Video collection")
- .that(getWhereForConstrainedAccess(noPerms, VIDEO_MEDIA, true,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(noPerms, VIDEO_MEDIA, true, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(noPerms));
assertWithMessage("Expected owned access SQL for Images collection")
- .that(getWhereForConstrainedAccess(noPerms, IMAGES_MEDIA, true,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(noPerms, IMAGES_MEDIA, true, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(noPerms));
// App with no permissions only has access to owned files
assertWithMessage("Expected owned access SQL for Downloads collection")
- .that(getWhereForConstrainedAccess(noPerms, DOWNLOADS, true,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(noPerms, DOWNLOADS, true, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(noPerms));
assertWithMessage("Expected owned access SQL for FILES collection")
- .that(getWhereForConstrainedAccess(noPerms, FILES, true,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(noPerms, FILES, true, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(noPerms));
}
@@ -467,12 +439,10 @@
// App with write permission to media files has access write access to media files and owned
// files.
assertWithMessage("Expected owned access SQL for Downloads collection")
- .that(getWhereForConstrainedAccess(hasReadPerms, DOWNLOADS, true,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasReadPerms, DOWNLOADS, true, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasReadPerms));
assertWithMessage("Expected owned access SQL for FILES collection")
- .that(getWhereForConstrainedAccess(hasReadPerms, FILES, true,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasReadPerms, FILES, true, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasReadPerms) + " OR "
+ getFilesAccessSql());
}
@@ -511,13 +481,11 @@
// Legacy app with WRITE_EXTERNAL_STORAGE permission has access to non-media files as well.
// However, they don't have global write access to secondary volume.
assertWithMessage("Expected where clause SQL for Downloads collection to be")
- .that(getWhereForConstrainedAccess(hasLegacyWrite, DOWNLOADS, true,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasLegacyWrite, DOWNLOADS, true, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasLegacyWrite) + " OR "
+ AccessChecker.getWhereForExternalPrimaryMatch());
assertWithMessage("Expected where clause SQL for FILES collection to be")
- .that(getWhereForConstrainedAccess(hasLegacyWrite, FILES, true,
- /* includedDefaultDirectoriesOptional */ Optional.empty()))
+ .that(getWhereForConstrainedAccess(hasLegacyWrite, FILES, true, Bundle.EMPTY))
.isEqualTo(getWhereForOwnerPackageMatch(hasLegacyWrite) + " OR "
+ AccessChecker.getWhereForExternalPrimaryMatch() + " OR "
+ getFilesAccessSql());
diff --git a/tests/src/com/android/providers/media/photopicker/data/PickerDbFacadeTest.java b/tests/src/com/android/providers/media/photopicker/data/PickerDbFacadeTest.java
index 1feb763..1283dd1 100644
--- a/tests/src/com/android/providers/media/photopicker/data/PickerDbFacadeTest.java
+++ b/tests/src/com/android/providers/media/photopicker/data/PickerDbFacadeTest.java
@@ -1401,7 +1401,7 @@
}
// Assert invalid projection column
- final String invalidColumn = "test invalid column";
+ final String invalidColumn = "testInvalidColumn";
final String[] invalidProjection = new String[]{
PickerMediaColumns.DATE_TAKEN,
invalidColumn
@@ -1413,17 +1413,12 @@
"Unexpected number of rows when asserting invalid projection column with "
+ "cloud provider.")
.that(cr.getCount()).isEqualTo(1);
- assertWithMessage("Unexpected number of columns in cursor")
- .that(cr.getColumnCount())
- .isEqualTo(2);
cr.moveToFirst();
- assertWithMessage("Unexpected value of the invalidColumn with cloud provider.")
+ assertWithMessage(
+ "Unexpected value of the invalidColumn with cloud provider.")
.that(cr.getLong(cr.getColumnIndexOrThrow(invalidColumn)))
.isEqualTo(0);
- assertWithMessage("Unexpected value of the invalidColumn with cloud provider.")
- .that(cr.getString(cr.getColumnIndexOrThrow(invalidColumn)))
- .isEqualTo(null);
assertWithMessage(
"Unexpected value of PickerMediaColumns.DATE_TAKEN with cloud provider.")
.that(cr.getLong(cr.getColumnIndexOrThrow(PickerMediaColumns.DATE_TAKEN)))