Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69e1ad70 authored by Ivan Chiang's avatar Ivan Chiang
Browse files

Update the database for file operations in FileSystemProvider

Use MediaStore.scanFile to Handle .nomedia file case for file
operations.

Fix: 173574639
Test: manual
      Rename/move/delete/copy files in storage root in DocumentsUI
Change-Id: I8231a67548bdb133bb47edf832db14aeb389e7ea
parent 128ce52d
Loading
Loading
Loading
Loading
+21 −43
Original line number Diff line number Diff line
@@ -20,15 +20,14 @@ import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
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;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.FileObserver;
@@ -39,7 +38,6 @@ 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;
@@ -66,6 +64,7 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
@@ -271,8 +270,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {
                throw new IllegalStateException("Failed to touch " + file + ": " + e);
            }
        }
        MediaStore.scanFile(getContext().getContentResolver(), file);

        updateMediaStore(getContext(), file);
        return childId;
    }

@@ -295,7 +293,9 @@ public abstract class FileSystemProvider extends DocumentsProvider {
        onDocIdChanged(afterDocId);

        final File afterVisibleFile = getFileForDocId(afterDocId, true);
        moveInMediaStore(beforeVisibleFile, afterVisibleFile);

        updateMediaStore(getContext(), beforeVisibleFile);
        updateMediaStore(getContext(), afterVisibleFile);

        if (!TextUtils.equals(docId, afterDocId)) {
            return afterDocId;
@@ -323,17 +323,23 @@ public abstract class FileSystemProvider extends DocumentsProvider {
        onDocIdChanged(sourceDocumentId);
        onDocIdDeleted(sourceDocumentId);
        onDocIdChanged(docId);
        moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true));

        // update the database
        updateMediaStore(getContext(), visibleFileBefore);
        updateMediaStore(getContext(), getFileForDocId(docId, true));
        return docId;
    }

    private void moveInMediaStore(@Nullable File oldVisibleFile, @Nullable File newVisibleFile) {
        if (oldVisibleFile != null) {
            MediaStore.scanFile(getContext().getContentResolver(), oldVisibleFile);
    private static void updateMediaStore(@NonNull Context context, File file) {
        if (file != null) {
            final ContentResolver resolver = context.getContentResolver();
            final String noMedia = ".nomedia";
            // For file, check whether the file name is .nomedia or not.
            // If yes, scan the parent directory to update all files in the directory.
            if (!file.isDirectory() && file.getName().toLowerCase(Locale.ROOT).endsWith(noMedia)) {
                MediaStore.scanFile(resolver, file.getParentFile());
            } else {
                MediaStore.scanFile(resolver, file);
            }
        if (newVisibleFile != null) {
            MediaStore.scanFile(getContext().getContentResolver(), newVisibleFile);
        }
    }

@@ -354,35 +360,7 @@ public abstract class FileSystemProvider extends DocumentsProvider {

        onDocIdChanged(docId);
        onDocIdDeleted(docId);
        removeFromMediaStore(visibleFile);
    }

    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) {
            final long token = Binder.clearCallingIdentity();

            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 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);
            }
        }
        updateMediaStore(getContext(), visibleFile);
    }

    @Override