Merge "Include pending media as well when deleting mediastore entries." into rvc-dev

This commit is contained in:
Sudheer Shanka
2020-02-27 17:49:53 +00:00
committed by Android (Google) Code Review
3 changed files with 52 additions and 17 deletions

View File

@@ -3827,6 +3827,18 @@ public abstract class ContentResolver implements ContentInterface {
return queryArgs;
}
/** @hide */
public static @NonNull Bundle includeSqlSelectionArgs(@NonNull Bundle queryArgs,
@Nullable String selection, @Nullable String[] selectionArgs) {
if (selection != null) {
queryArgs.putString(QUERY_ARG_SQL_SELECTION, selection);
}
if (selectionArgs != null) {
queryArgs.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs);
}
return queryArgs;
}
/**
* Returns structured sort args formatted as an SQL sort clause.
*

View File

@@ -16,6 +16,7 @@
package android.database;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentValues;
@@ -1548,4 +1549,24 @@ public class DatabaseUtils {
}
return -1;
}
/**
* Escape the given argument for use in a {@code LIKE} statement.
* @hide
*/
public static String escapeForLike(@NonNull String arg) {
// Shamelessly borrowed from com.android.providers.media.util.DatabaseUtils
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < arg.length(); i++) {
final char c = arg.charAt(i);
switch (c) {
case '%': sb.append('\\');
break;
case '_': sb.append('\\');
break;
}
sb.append(c);
}
return sb.toString();
}
}

View File

@@ -23,6 +23,7 @@ import android.content.ContentResolver;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.MatrixCursor;
import android.database.MatrixCursor.RowBuilder;
import android.graphics.Point;
@@ -38,6 +39,7 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsProvider;
import android.provider.MediaStore;
import android.provider.MediaStore.Files.FileColumns;
import android.provider.MetadataReader;
import android.system.Int64Ref;
import android.text.TextUtils;
@@ -333,15 +335,17 @@ public abstract class FileSystemProvider extends DocumentsProvider {
if (isDirectory) {
FileUtils.deleteContents(file);
}
if (!file.delete()) {
// We could be deleting pending media which doesn't have any content yet, so only throw
// if the file exists and we fail to delete it.
if (file.exists() && !file.delete()) {
throw new IllegalStateException("Failed to delete " + file);
}
onDocIdChanged(docId);
removeFromMediaStore(visibleFile, isDirectory);
removeFromMediaStore(visibleFile);
}
private void removeFromMediaStore(@Nullable File visibleFile, boolean isFolder)
private void removeFromMediaStore(@Nullable File visibleFile)
throws FileNotFoundException {
// visibleFolder is null if we're removing a document from external thumb drive or SD card.
if (visibleFile != null) {
@@ -350,21 +354,19 @@ public abstract class FileSystemProvider extends DocumentsProvider {
try {
final ContentResolver resolver = getContext().getContentResolver();
final Uri externalUri = MediaStore.Files.getContentUri("external");
final Bundle queryArgs = new Bundle();
queryArgs.putInt(MediaStore.QUERY_ARG_MATCH_PENDING, MediaStore.MATCH_INCLUDE);
// Remove media store entries for any files inside this directory, using
// path prefix match. Logic borrowed from MtpDatabase.
if (isFolder) {
final String path = visibleFile.getAbsolutePath() + "/";
resolver.delete(externalUri,
"_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
new String[]{path + "%", Integer.toString(path.length()), path});
}
// Remove media store entry for this exact file.
final String path = visibleFile.getAbsolutePath();
resolver.delete(externalUri,
"_data LIKE ?1 AND lower(_data)=lower(?2)",
new String[]{path, path});
// Remove the media store entry corresponding to visibleFile and if it is a
// directory, also remove media store entries for any files inside this directory.
// Logic borrowed from com.android.providers.media.scan.ModernMediaScanner.
final String pathEscapedForLike = DatabaseUtils.escapeForLike(
visibleFile.getAbsolutePath());
ContentResolver.includeSqlSelectionArgs(queryArgs,
FileColumns.DATA + " LIKE ? ESCAPE '\\' OR "
+ FileColumns.DATA + " LIKE ? ESCAPE '\\'",
new String[] {pathEscapedForLike + "/%", pathEscapedForLike});
resolver.delete(externalUri, queryArgs);
} finally {
Binder.restoreCallingIdentity(token);
}