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

Commit 87a9cffd authored by François Degros's avatar François Degros
Browse files

Don't browse nested archives

Restrict the visibility of the "Browse", "Extract here", "Open" and
"Open With" menu items.
The "Browse", "Open" and "Open with" menu items are not visible for
nested archives (i.e. archives located in a browsed archive).
The "Extract here" menu item is not visible if the current directory
does not allow the creation of subdirectories.

Bug: 406872038
Flag: com.android.documentsui.flags.use_material3
Flag: com.android.documentsui.flags.zip_ng_ro
Test: atest DocumentsUIGoogleTests:com.android.documentsui.files.MenuManagerTest
Test: atest DocumentsUIGoogleTests:com.android.documentsui.picker.MenuManagerTest
Test: atest DocumentsUIGoogleTests:com.android.documentsui.base.DocumentInfoTest
Change-Id: I717c634c9de34d0ecfd05eec544cc30186d4ffa5
parent 2b45e2d8
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.documentsui.base;

import static com.android.documentsui.base.SharedMinimal.DEBUG;
import static com.android.documentsui.base.SharedMinimal.redact;
import static com.android.documentsui.util.FlagUtils.isZipNgFlagEnabled;

import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -321,8 +320,7 @@ public class DocumentInfo implements Durable, Parcelable {

    // Containers are documents which can be opened in DocumentsUI as folders.
    public boolean isContainer() {
        return isDirectory() || (isArchive() && !isPartial() && (isZipNgFlagEnabled()
                || !isInArchive()));
        return isDirectory() || (isArchive() && !isPartial() && !isInArchive());
    }

    public boolean isVirtual() {
+1 −1
Original line number Diff line number Diff line
@@ -186,6 +186,6 @@ public class SelectionMetadata extends SelectionObserver<String>
    @Override
    public boolean canOpen() {
        return mFileCount == 1 && mDirectoryCount == 0 && mPartialCount == 0 && (
                isZipNgFlagEnabled() || mInArchiveCount == 0);
                mInArchiveCount == 0 || (isZipNgFlagEnabled() && mArchiveCount == 0));
    }
}
+6 −7
Original line number Diff line number Diff line
@@ -134,7 +134,7 @@ public final class MenuManager extends com.android.documentsui.MenuManager {
        final boolean hasDir = selectionDetails.containsDirectories();
        final boolean hasFile = selectionDetails.containsFiles();

        assert(hasDir || hasFile);
        assert hasDir || hasFile;
        if (!hasDir) {
            inflater.inflate(R.menu.file_context_menu, menu);
            updateContextMenuForFiles(menu, selectionDetails);
@@ -200,7 +200,7 @@ public final class MenuManager extends com.android.documentsui.MenuManager {

    @Override
    protected void updateOpenInNewWindow(MenuItem openInNewWindow, RootInfo root) {
        assert(openInNewWindow.isVisible() && openInNewWindow.isEnabled());
        assert openInNewWindow.isVisible() && openInNewWindow.isEnabled();
    }

    @Override
@@ -232,12 +232,12 @@ public final class MenuManager extends com.android.documentsui.MenuManager {

    @Override
    protected void updateExtractHere(@NonNull MenuItem it, @NonNull SelectionDetails selection) {
        Menus.setEnabledAndVisible(it, selection.isArchive());
        Menus.setEnabledAndVisible(it, selection.isArchive() && mDirDetails.canCreateDirectory());
    }

    @Override
    protected void updateBrowse(@NonNull MenuItem it, @NonNull SelectionDetails selection) {
        Menus.setEnabledAndVisible(it, selection.isArchive());
        Menus.setEnabledAndVisible(it, selection.isArchive() && !mDirDetails.isInArchive());
    }

    @Override
@@ -325,8 +325,7 @@ public final class MenuManager extends com.android.documentsui.MenuManager {
                    selectedUri.getAuthority());
            String title = res.getString(R.string.menu_view_in_owner, appName);
            view.setTitle(title);
        }
        else {
        } else {
            Menus.setEnabledAndVisible(view, false);
        }
    }
+59 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.documentsui.base;

import static android.provider.DocumentsContract.Document.MIME_TYPE_DIR;

import static androidx.core.util.Preconditions.checkArgument;

import static com.google.common.truth.Truth.assertThat;
@@ -33,6 +35,7 @@ import androidx.test.filters.SmallTest;
import androidx.test.rule.provider.ProviderTestRule;

import com.android.documentsui.InspectorProvider;
import com.android.documentsui.archives.ArchivesProvider;
import com.android.documentsui.testing.TestProvidersAccess;
import com.android.documentsui.util.VersionUtils;

@@ -134,7 +137,7 @@ public class DocumentInfoTest extends AndroidTestCase {

        assertThat(mimeTypes.size()).isEqualTo(1);

        assertThat(mimeTypes.contains(DocumentsContract.Document.MIME_TYPE_DIR)).isTrue();
        assertThat(mimeTypes.contains(MIME_TYPE_DIR)).isTrue();
    }

    @Test
@@ -202,4 +205,59 @@ public class DocumentInfoTest extends AndroidTestCase {
                    .isEqualTo(otherUserDoc.getDocumentUri().getUserInfo());
        }
    }

    @Test
    public void testTextFile() throws Exception {
        final DocumentInfo doc = createDocInfo("authority.a", "doc.1", "text/plain");
        assertThat(doc.isArchive()).isFalse();
        assertThat(doc.isContainer()).isFalse();
        assertThat(doc.isDirectory()).isFalse();
        assertThat(doc.isInArchive()).isFalse();
    }

    @Test
    public void testDirectory() throws Exception {
        final DocumentInfo doc = createDocInfo("authority.a", "doc.1", MIME_TYPE_DIR);
        assertThat(doc.isArchive()).isFalse();
        assertThat(doc.isContainer()).isTrue();
        assertThat(doc.isDirectory()).isTrue();
        assertThat(doc.isInArchive()).isFalse();
    }

    @Test
    public void testArchive() throws Exception {
        final DocumentInfo doc = createDocInfo("authority.a", "doc.1", "application/zip");
        assertThat(doc.isArchive()).isTrue();
        assertThat(doc.isContainer()).isTrue();
        assertThat(doc.isDirectory()).isFalse();
        assertThat(doc.isInArchive()).isFalse();
    }

    @Test
    public void testTextFileInArchive() throws Exception {
        final DocumentInfo doc = createDocInfo(ArchivesProvider.AUTHORITY, "doc.1", "text/plain");
        assertThat(doc.isArchive()).isFalse();
        assertThat(doc.isContainer()).isFalse();
        assertThat(doc.isDirectory()).isFalse();
        assertThat(doc.isInArchive()).isTrue();
    }

    @Test
    public void testDirectoryInArchive() throws Exception {
        final DocumentInfo doc = createDocInfo(ArchivesProvider.AUTHORITY, "doc.1", MIME_TYPE_DIR);
        assertThat(doc.isArchive()).isFalse();
        assertThat(doc.isContainer()).isTrue();
        assertThat(doc.isDirectory()).isTrue();
        assertThat(doc.isInArchive()).isTrue();
    }

    @Test
    public void testArchiveInArchive() throws Exception {
        final DocumentInfo doc = createDocInfo(ArchivesProvider.AUTHORITY, "doc.1",
                "application/zip");
        assertThat(doc.isArchive()).isTrue();
        assertThat(doc.isContainer()).isFalse();
        assertThat(doc.isDirectory()).isFalse();
        assertThat(doc.isInArchive()).isTrue();
    }
}
+23 −0
Original line number Diff line number Diff line
@@ -794,6 +794,9 @@ public final class MenuManagerTest {
        selectionDetails.size = 1;
        selectionDetails.containFiles = true;
        selectionDetails.isArchive = true;
        selectionDetails.containsFilesInArchive = false;
        dirDetails.isInArchive = false;
        dirDetails.canCreateDirectory = true;
        mgr.updateContextMenuForFiles(testMenu, selectionDetails);
        if (isZipNgFlagEnabled()) {
            mDirExtractHere.assertEnabledAndVisible();
@@ -802,6 +805,26 @@ public final class MenuManagerTest {
            mDirExtractHere.assertDisabledAndInvisible();
            mDirBrowse.assertDisabledAndInvisible();
        }

        // On archive in read-only directory (but not a nested archive)
        selectionDetails.containsFilesInArchive = false;
        dirDetails.isInArchive = false;
        dirDetails.canCreateDirectory = false;
        mgr.updateContextMenuForFiles(testMenu, selectionDetails);
        mDirExtractHere.assertDisabledAndInvisible();
        if (isZipNgFlagEnabled()) {
            mDirBrowse.assertEnabledAndVisible();
        } else {
            mDirBrowse.assertDisabledAndInvisible();
        }

        // On nested archive
        selectionDetails.containsFilesInArchive = true;
        dirDetails.isInArchive = true;
        dirDetails.canCreateDirectory = false;
        mgr.updateContextMenuForFiles(testMenu, selectionDetails);
        mDirExtractHere.assertDisabledAndInvisible();
        mDirBrowse.assertDisabledAndInvisible();
    }

    @Test