Merge "Include pending media as well when deleting mediastore entries." into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
442399b1c1
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user