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

Commit a5050235 authored by Ben Reich's avatar Ben Reich
Browse files

Ensure the options menu is refreshed on Recent when no selection

When selecting an item the app bar menu is refreshed to show actions
relating to the current selection. When the selection is cleared, the
menu should refresh. Unfortunately one of the sections was incorrectly
bailing out when the search bar was showing, this refactors some of the
update() method to be clearer and ensures the action menu is always
updated.

This also includes a fix to the openDrawer method which was not
correctly identifying the drawer when in the nav_rail layout. The
selector was finding `container_roots` when the layout actually uses
`nav_rail_container_roots`. It updates it to use regex instead of exact
match.

Fix: 411295692
Test: atest com.android.documentsui.FilesActivityUiTest
Flag: com.android.documentsui.flags.use_material3
Change-Id: Ic8c5dc768ca5135392749c91bfbfdf684e39a4e6
parent 3a35c553
Loading
Loading
Loading
Loading
+15 −18
Original line number Diff line number Diff line
@@ -320,15 +320,11 @@ public class NavigationViewManager extends SelectionTracker.SelectionObserver<St

        mDrawer.setTitle(mEnv.getDrawerTitle());

        boolean showBurgerMenuOnToolbar = true;
        if (isUseMaterial3FlagEnabled()) {
            View navRailRoots = mActivity.findViewById(R.id.nav_rail_container_roots);
            if (navRailRoots != null) {
                // If nav rail exists, burger menu will show on the nav rail instead.
                showBurgerMenuOnToolbar = false;
            }
        }

        // Show burger menu on toolbar unless `use_material3` flag is on and the nav rail exists
        // (the burger menu will show on the nav rail instead).
        boolean showBurgerMenuOnToolbar =
                !isUseMaterial3FlagEnabled()
                        || mActivity.findViewById(R.id.nav_rail_container_roots) == null;
        if (showBurgerMenuOnToolbar) {
            mToolbar.setNavigationIcon(getActionBarIcon());
            mToolbar.setNavigationContentDescription(R.string.drawer_open);
@@ -337,18 +333,11 @@ public class NavigationViewManager extends SelectionTracker.SelectionObserver<St
            mToolbar.setNavigationContentDescription(null);
        }

        if ((!isUseMaterial3FlagEnabled() || !inSelectionMode()) && shouldShowSearchBar()) {
            mBreadcrumb.show(false);
            mToolbar.setTitle(null);
            mSearchBarView.setVisibility(View.VISIBLE);
            return;
        }

        mSearchBarView.setVisibility(View.GONE);

        if (isUseMaterial3FlagEnabled()) {
            updateActionMenu();

            if (inSelectionMode()) {
                mSearchBarView.setVisibility(View.GONE);
                final int quantity = mInjector.selectionMgr.getSelection().size();
                final String title =
                        mToolbar.getContext()
@@ -362,6 +351,14 @@ public class NavigationViewManager extends SelectionTracker.SelectionObserver<St
            }
        }

        if (shouldShowSearchBar()) {
            mBreadcrumb.show(false);
            mToolbar.setTitle(null);
            mSearchBarView.setVisibility(View.VISIBLE);
            return;
        }

        mSearchBarView.setVisibility(View.GONE);
        String title =
                mState.stack.size() <= 1 ? mEnv.getCurrentRoot().title : mState.stack.getTitle();
        if (VERBOSE) Log.v(TAG, "New toolbar title is: " + title);
+10 −6
Original line number Diff line number Diff line
@@ -65,9 +65,10 @@ public class SidebarBot extends Bots.BaseBot {
        // We might need to expand drawer if not visible
        openDrawer();

        final UiSelector rootsList = new UiSelector().resourceId(
                mTargetPackage + ":id/container_roots").childSelector(
                new UiSelector().resourceId(mRootListId));
        final UiSelector rootsList =
                new UiSelector()
                        .resourceIdMatches(mTargetPackage + ":id/.*container_roots")
                        .childSelector(new UiSelector().resourceId(mRootListId));

        // Wait for the first list item to appear
        new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(mTimeout);
@@ -84,9 +85,12 @@ public class SidebarBot extends Bots.BaseBot {
    }

    public void openDrawer() throws UiObjectNotFoundException {
        final UiSelector rootsList = new UiSelector().resourceId(
                mTargetPackage + ":id/container_roots").childSelector(
                new UiSelector().resourceId(mRootListId));
        // Let's check for `nav_rail_container_roots` as well as `container_roots` to avoid opening
        // the drawer in nav rail layout.
        final UiSelector rootsList =
                new UiSelector()
                        .resourceIdMatches(mTargetPackage + ":id/.*container_roots")
                        .childSelector(new UiSelector().resourceId(mRootListId));

        // We might need to expand drawer if not visible
        if (!new UiObject(rootsList).waitForExists(mTimeout)) {
+82 −19
Original line number Diff line number Diff line
@@ -16,6 +16,12 @@

package com.android.documentsui;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;

import static com.android.documentsui.StubProvider.ROOT_0_ID;
import static com.android.documentsui.StubProvider.ROOT_1_ID;
import static com.android.documentsui.base.Providers.AUTHORITY_STORAGE;
@@ -38,6 +44,7 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.uiautomator.UiObjectNotFoundException;

import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.RootInfo;
@@ -85,11 +92,7 @@ public class FilesActivityUiTest extends ActivityTestJunit4<FilesActivity> {
        }
    }

    @Test
    @RequiresFlagsEnabled(FLAG_USE_MATERIAL3)
    public void testRecentsSelectionClearsSearchBar() throws Exception {
        assume().that(context.getResources().getBoolean(R.bool.show_search_bar)).isTrue();

    private DocumentsProviderHelper setupStorageAuthorityDocsHelper() throws Exception {
        // Create DocumentsProviderHelper to create files in Internal storage.
        DocumentsProviderHelper storageDocsHelper =
                new DocumentsProviderHelper(
@@ -107,18 +110,14 @@ public class FilesActivityUiTest extends ActivityTestJunit4<FilesActivity> {
        }

        assertTrue(info != null && info.isDirectory());
        return storageDocsHelper;
    }

        // Open up Recents and create a file that should appear.
        bots.roots.openRoot("Recent");
        final String fileName = "Recent.txt";
        storageDocsHelper.createDocument(info.documentId, "text/plain", fileName);
        try {
            bots.directory.waitForDocument(fileName);
            bots.directory.selectDocument(fileName, 1);
        } finally {
    private void cleanupFile(String fileName, String primaryRootTitle)
            throws UiObjectNotFoundException {
        // Unselect the file and remove it.
        bots.directory.selectDocument(fileName);
            bots.roots.openRoot(primaryRoot.title);
        bots.roots.openRoot(primaryRootTitle);
        bots.directory.openDocument("Download");

        bots.directory.waitForDocument(fileName);
@@ -131,6 +130,27 @@ public class FilesActivityUiTest extends ActivityTestJunit4<FilesActivity> {
        bots.directory.findDocument(fileName).waitUntilGone(5000);
        assertFalse(bots.directory.hasDocuments(fileName));
    }

    @Test
    @RequiresFlagsEnabled(FLAG_USE_MATERIAL3)
    public void testRecentsSelectionClearsSearchBar() throws Exception {
        assume().that(context.getResources().getBoolean(R.bool.show_search_bar)).isTrue();

        DocumentsProviderHelper storageDocsHelper = setupStorageAuthorityDocsHelper();
        RootInfo primaryRoot = storageDocsHelper.getRoot(ROOT_ID_DEVICE);
        DocumentInfo info = storageDocsHelper.findFile(primaryRoot.documentId, "Download");

        // Open up Recents and create a file that should appear.
        bots.roots.openRoot("Recent");
        final String fileName = "Recent.txt";
        storageDocsHelper.createDocument(info.documentId, "text/plain", fileName);

        try {
            bots.directory.waitForDocument(fileName);
            bots.directory.selectDocument(fileName, 1);
        } finally {
            cleanupFile(fileName, primaryRoot.title);
        }
    }

    @Test
@@ -239,4 +259,47 @@ public class FilesActivityUiTest extends ActivityTestJunit4<FilesActivity> {
            bots.sort.assertHeaderHide();
        }
    }

    @Test
    @RequiresFlagsEnabled(FLAG_USE_MATERIAL3)
    public void testClearSelectionInRecentsResetsActions() throws Exception {
        assume().that(context.getResources().getBoolean(R.bool.show_search_bar)).isTrue();

        // Ensure Downloads exists and get the location of the main root (e.g. "Pixel Tablet").
        DocumentsProviderHelper storageDocsHelper = setupStorageAuthorityDocsHelper();
        RootInfo primaryRoot = storageDocsHelper.getRoot(ROOT_ID_DEVICE);
        DocumentInfo info = storageDocsHelper.findFile(primaryRoot.documentId, "Download");

        // Create a file in "Download".
        final String fileName = "recent_file.txt";
        storageDocsHelper.createDocument(info.documentId, "text/plain", fileName);

        // Navigate to "Download" and ensure the file exists (this should ensure it also exists in
        // Recent).
        bots.roots.openRoot(primaryRoot.title);
        bots.directory.openDocument("Download");
        bots.directory.waitForDocument(fileName);

        // Open Recent and wait for the document to appear.
        bots.roots.openRoot("Recent");
        bots.directory.waitForDocument(fileName);

        try {
            // The search option menu shows up when no items are selected, use this as a proxy for
            // the options menu being refreshed (it should only show when a file is selected).
            onView(withId(R.id.action_menu_share)).check(doesNotExist());

            // Select the recent document, which will refresh the options menu and the share action
            // menu item should appear.
            bots.directory.selectDocument(fileName, 1);
            onView(withId(R.id.action_menu_share)).check(matches(isDisplayed()));

            // Deselect the file and ensure the share menu disappears (this ensures the menu is
            // refreshed).
            bots.directory.selectDocument(fileName);
            onView(withId(R.id.action_menu_share)).check(doesNotExist());
        } finally {
            cleanupFile(fileName, primaryRoot.title);
        }
    }
}