Show correct sort header after root switch.

Bug: 31119758
Change-Id: I4f99140d67196c363f0276bce2d57e93dad0187f
diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java
index 2c8c127..7ae2e51 100644
--- a/src/com/android/documentsui/BaseActivity.java
+++ b/src/com/android/documentsui/BaseActivity.java
@@ -267,6 +267,7 @@
         }
 
         mState.derivedMode = LocalPreferences.getViewMode(this, root, MODE_GRID);
+        mSortController.onViewModeChanged(mState.derivedMode);
 
         // Set summary header's visibility. Only recents and downloads root may have summary in
         // their docs.
diff --git a/tests/src/com/android/documentsui/FilesActivityUiTest.java b/tests/src/com/android/documentsui/FilesActivityUiTest.java
index 1b47705..afc7e9d 100644
--- a/tests/src/com/android/documentsui/FilesActivityUiTest.java
+++ b/tests/src/com/android/documentsui/FilesActivityUiTest.java
@@ -75,4 +75,27 @@
         bots.breadcrumb.clickItem("TEST_ROOT_0");
         bots.directory.waitForDocument(dirName1);
     }
+
+    public void testRootChange_UpdatesSortHeader() throws Exception {
+
+        // switch to separate display modes for two separate roots. Each
+        // mode has its own distinct sort header. This should be remembered
+        // by files app.
+        bots.roots.openRoot("Images");
+        bots.main.switchToGridMode();
+        bots.roots.openRoot("Videos");
+        bots.main.switchToListMode();
+
+        // Now switch back and assert the correct mode sort header mode
+        // is restored when we load the root with that display mode.
+        bots.roots.openRoot("Images");
+        bots.sortHeader.assertDropdownMode();
+        if (bots.main.inFixedLayout()) {
+            bots.roots.openRoot("Videos");
+            bots.sortHeader.assertColumnMode();
+        } else {
+            bots.roots.openRoot("Videos");
+            bots.sortHeader.assertDropdownMode();
+        }
+    }
 }
diff --git a/tests/src/com/android/documentsui/SortDocumentUiTest.java b/tests/src/com/android/documentsui/SortDocumentUiTest.java
index 8f1dc17..ac4fa4c 100644
--- a/tests/src/com/android/documentsui/SortDocumentUiTest.java
+++ b/tests/src/com/android/documentsui/SortDocumentUiTest.java
@@ -90,7 +90,7 @@
 
         bots.main.switchToListMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_DESCENDING);
         bots.directory.assertOrder(DIRS_IN_NAME_DESC, FILES_IN_NAME_DESC);
     }
@@ -100,7 +100,7 @@
 
         bots.main.switchToListMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_ASCENDING);
         bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_ASC);
     }
@@ -110,7 +110,7 @@
 
         bots.main.switchToListMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_DESCENDING);
         bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_DESC);
     }
@@ -120,7 +120,7 @@
 
         bots.main.switchToListMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_ASCENDING);
         bots.directory.assertOrder(DIRS, FILES);
     }
@@ -130,7 +130,7 @@
 
         bots.main.switchToListMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_DESCENDING);
         bots.directory.assertOrder(DIRS_IN_MODIFIED_DESC, FILES_IN_MODIFIED_DESC);
     }
@@ -140,7 +140,7 @@
 
         bots.main.switchToGridMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_DESCENDING);
         bots.directory.assertOrder(DIRS_IN_NAME_DESC, FILES_IN_NAME_DESC);
     }
@@ -150,7 +150,7 @@
 
         bots.main.switchToGridMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_ASCENDING);
         bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_ASC);
     }
@@ -160,7 +160,7 @@
 
         bots.main.switchToGridMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_SIZE, SortDimension.SORT_DIRECTION_DESCENDING);
         bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_DESC);
     }
@@ -170,7 +170,7 @@
 
         bots.main.switchToGridMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_ASCENDING);
         bots.directory.assertOrder(DIRS, FILES);
     }
@@ -180,7 +180,7 @@
 
         bots.main.switchToGridMode();
 
-        bots.directory.sortBy(
+        bots.sortHeader.sortBy(
                 SortModel.SORT_DIMENSION_ID_DATE, SortDimension.SORT_DIRECTION_DESCENDING);
         bots.directory.assertOrder(DIRS_IN_MODIFIED_DESC, FILES_IN_MODIFIED_DESC);
     }
diff --git a/tests/src/com/android/documentsui/bots/Bots.java b/tests/src/com/android/documentsui/bots/Bots.java
index 4bda531..d5aafa8 100644
--- a/tests/src/com/android/documentsui/bots/Bots.java
+++ b/tests/src/com/android/documentsui/bots/Bots.java
@@ -36,6 +36,7 @@
 
     public final BreadBot breadcrumb;
     public final DirectoryListBot directory;
+    public final SortHeaderBot sortHeader;
     public final KeyboardBot keyboard;
     public final RootsListBot roots;
     public final SearchBot search;
@@ -46,6 +47,7 @@
         breadcrumb = new BreadBot(device, context, TIMEOUT, main);
         roots = new RootsListBot(device, context, TIMEOUT);
         directory = new DirectoryListBot(device, context, TIMEOUT);
+        sortHeader = new SortHeaderBot(device, context, TIMEOUT);
         keyboard = new KeyboardBot(device, context, TIMEOUT);
         search = new SearchBot(device, context, TIMEOUT);
     }
@@ -55,7 +57,7 @@
      * and making assertions against the state of it.
      */
     static abstract class BaseBot {
-        final UiDevice mDevice;
+        public final UiDevice mDevice;
         final Context mContext;
         final int mTimeout;
 
diff --git a/tests/src/com/android/documentsui/bots/DirectoryListBot.java b/tests/src/com/android/documentsui/bots/DirectoryListBot.java
index f9f5996..b07beec 100644
--- a/tests/src/com/android/documentsui/bots/DirectoryListBot.java
+++ b/tests/src/com/android/documentsui/bots/DirectoryListBot.java
@@ -16,26 +16,13 @@
 
 package com.android.documentsui.bots;
 
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.withChild;
-import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withParent;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static com.android.documentsui.sorting.SortDimension.SORT_DIRECTION_ASCENDING;
-
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
-
-import static org.hamcrest.Matchers.allOf;
+import static junit.framework.Assert.fail;
 
 import android.content.Context;
 import android.graphics.Rect;
-import android.support.annotation.StringRes;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.BySelector;
 import android.support.test.uiautomator.Configurator;
@@ -49,16 +36,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 
-import com.android.documentsui.R;
-import com.android.documentsui.sorting.SortDimension;
-import com.android.documentsui.sorting.SortDimension.SortDirection;
-import com.android.documentsui.sorting.SortModel;
-import com.android.documentsui.sorting.SortModel.SortDimensionId;
-
-import junit.framework.Assert;
-
-import org.hamcrest.Matcher;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -75,15 +52,8 @@
     private static final BySelector SNACK_DELETE =
             By.desc(Pattern.compile("^Deleting [0-9]+ file.+"));
 
-    private final SortModel mSortModel = SortModel.createModel();
-
-    private final DropdownSortBot mDropdownBot;
-    private final HeaderSortBot mHeaderBot;
-
     public DirectoryListBot(UiDevice device, Context context, int timeout) {
         super(device, context, timeout);
-        mDropdownBot = new DropdownSortBot();
-        mHeaderBot = new HeaderSortBot();
     }
 
     public void assertDocumentsCount(int count) throws UiObjectNotFoundException {
@@ -99,7 +69,7 @@
             }
         }
         if (!absent.isEmpty()) {
-            Assert.fail("Expected documents " + Arrays.asList(labels)
+            fail("Expected documents " + Arrays.asList(labels)
                     + ", but missing " + absent);
         }
     }
@@ -112,7 +82,7 @@
             }
         }
         if (!found.isEmpty()) {
-            Assert.fail("Expected documents not present" + Arrays.asList(labels)
+            fail("Expected documents not present" + Arrays.asList(labels)
                     + ", but present " + found);
         }
     }
@@ -234,22 +204,6 @@
         assertHasFocus(DIR_LIST_ID);
     }
 
-    public void sortBy(@SortDimensionId int id, @SortDirection int direction) {
-        assert(direction != SortDimension.SORT_DIRECTION_NONE);
-
-        final @StringRes int labelId = mSortModel.getDimensionById(id).getLabelId();
-        final String label = mContext.getString(labelId);
-        final boolean result;
-        if (Matchers.present(mDropdownBot.MATCHER)) {
-            result = mDropdownBot.sortBy(label, direction);
-        } else {
-            result = mHeaderBot.sortBy(label, direction);
-        }
-
-        assertTrue("Sorting by id: " + id + " in direction: " + direction + " failed.",
-                result);
-    }
-
     public void assertOrder(String[] dirs, String[] files) throws UiObjectNotFoundException {
         for (int i = 0; i < dirs.length - 1; ++i) {
             assertOrder(dirs[i], dirs[i + 1]);
@@ -284,90 +238,4 @@
                     firstBound.bottom < secondBound.top || firstBound.left > secondBound.right);
         }
     }
-
-    private static class DropdownSortBot {
-
-        private static final Matcher<View> MATCHER = withId(R.id.dropdown_sort_widget);
-        private static final Matcher<View> DROPDOWN_MATCHER = allOf(
-                withId(R.id.sort_dimen_dropdown),
-                withParent(MATCHER));
-        private static final Matcher<View> SORT_ARROW_MATCHER = allOf(
-                withId(R.id.sort_arrow),
-                withParent(MATCHER));
-
-        private boolean sortBy(String label, @SortDirection int direction) {
-            onView(DROPDOWN_MATCHER).perform(click());
-            onView(withText(label)).perform(click());
-
-            if (direction != getDirection()) {
-                onView(SORT_ARROW_MATCHER).perform(click());
-            }
-
-            return Matchers.present(allOf(
-                    DROPDOWN_MATCHER,
-                    withText(label)))
-                    && getDirection() == direction;
-        }
-
-        private @SortDirection int getDirection() {
-            final boolean ascending = Matchers.present(
-                    allOf(
-                            SORT_ARROW_MATCHER,
-                            withContentDescription(R.string.sort_direction_ascending)));
-
-            if (ascending) {
-                return SORT_DIRECTION_ASCENDING;
-            }
-
-            final boolean descending = Matchers.present(
-                    allOf(
-                            SORT_ARROW_MATCHER,
-                            withContentDescription(R.string.sort_direction_descending)));
-
-            return descending
-                    ? SortDimension.SORT_DIRECTION_DESCENDING
-                    : SortDimension.SORT_DIRECTION_NONE;
-        }
-    }
-
-    private static class HeaderSortBot {
-
-        private static final Matcher<View> MATCHER = withId(R.id.table_header);
-
-        private boolean sortBy(String label, @SortDirection int direction) {
-            final Matcher<View> cellMatcher = allOf(
-                    withChild(withText(label)),
-                    isDescendantOfA(MATCHER));
-            onView(cellMatcher).perform(click());
-
-            final @SortDirection int viewDirection = getDirection(cellMatcher);
-
-            if (viewDirection != direction) {
-                onView(cellMatcher).perform(click());
-            }
-
-            return getDirection(cellMatcher) == direction;
-        }
-
-        private @SortDirection int getDirection(Matcher<View> cellMatcher) {
-            final boolean ascending =
-                    Matchers.present(
-                            allOf(
-                                    withContentDescription(R.string.sort_direction_ascending),
-                                    withParent(cellMatcher)));
-            if (ascending) {
-                return SORT_DIRECTION_ASCENDING;
-            }
-
-            final boolean descending =
-                    Matchers.present(
-                            allOf(
-                                    withContentDescription(R.string.sort_direction_descending),
-                                    withParent(cellMatcher)));
-
-            return descending
-                    ? SortDimension.SORT_DIRECTION_DESCENDING
-                    : SortDimension.SORT_DIRECTION_NONE;
-        }
-    }
 }
diff --git a/tests/src/com/android/documentsui/bots/SortHeaderBot.java b/tests/src/com/android/documentsui/bots/SortHeaderBot.java
new file mode 100644
index 0000000..24bdc70
--- /dev/null
+++ b/tests/src/com/android/documentsui/bots/SortHeaderBot.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.bots;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
+import static android.support.test.espresso.matcher.ViewMatchers.withChild;
+import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withParent;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static com.android.documentsui.sorting.SortDimension.SORT_DIRECTION_ASCENDING;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.hamcrest.Matchers.allOf;
+
+import android.content.Context;
+import android.support.annotation.StringRes;
+import android.support.test.uiautomator.UiDevice;
+import android.view.View;
+
+import com.android.documentsui.R;
+import com.android.documentsui.sorting.SortDimension;
+import com.android.documentsui.sorting.SortDimension.SortDirection;
+import com.android.documentsui.sorting.SortModel;
+import com.android.documentsui.sorting.SortModel.SortDimensionId;
+
+import org.hamcrest.Matcher;
+
+/**
+ * A test helper class that provides support for controlling the UI Breadcrumb
+ * programmatically, and making assertions against the state of the UI.
+ * <p>
+ * Support for working directly with Roots and Directory view can be found in the respective bots.
+ */
+public class SortHeaderBot extends Bots.BaseBot {
+
+    private final SortModel mSortModel = SortModel.createModel();
+    private final DropdownSortBot mDropBot;
+    private final ColumnSortBot mColumnBot;
+
+    public SortHeaderBot(UiDevice device, Context context, int timeout) {
+        super(device, context, timeout);
+        mDropBot = new DropdownSortBot();
+        mColumnBot = new ColumnSortBot();
+    }
+
+    public void sortBy(@SortDimensionId int id, @SortDirection int direction) {
+        assert(direction != SortDimension.SORT_DIRECTION_NONE);
+
+        final @StringRes int labelId = mSortModel.getDimensionById(id).getLabelId();
+        final String label = mContext.getString(labelId);
+        final boolean result;
+        if (Matchers.present(mDropBot.MATCHER)) {
+            result = mDropBot.sortBy(label, direction);
+        } else {
+            result = mColumnBot.sortBy(label, direction);
+        }
+
+        assertTrue("Sorting by id: " + id + " in direction: " + direction + " failed.",
+                result);
+    }
+
+    public void assertDropdownMode() {
+        assertTrue(Matchers.present(mDropBot.MATCHER));
+    }
+
+    public void assertColumnMode() {
+        // BEWARE THOSE WHO TREAD IN THIS DARK CORNER.
+        // Note that for some reason this doesn't work:
+        // assertTrue(Matchers.present(mColumnBot.MATCHER));
+        // Dunno why, something to do with our implementation
+        // or with espresso. It's sad that I'm leaving you
+        // with this little gremlin, but we all have to
+        // move on and get stuff done :)
+        assertFalse(Matchers.present(mDropBot.MATCHER));
+    }
+
+    private static class DropdownSortBot {
+
+        private static final Matcher<View> MATCHER = withId(R.id.dropdown_sort_widget);
+        private static final Matcher<View> DROPDOWN_MATCHER = allOf(
+                withId(R.id.sort_dimen_dropdown),
+                withParent(MATCHER));
+        private static final Matcher<View> SORT_ARROW_MATCHER = allOf(
+                withId(R.id.sort_arrow),
+                withParent(MATCHER));
+
+        private boolean sortBy(String label, @SortDirection int direction) {
+            onView(DROPDOWN_MATCHER).perform(click());
+            onView(withText(label)).perform(click());
+
+            if (direction != getDirection()) {
+                onView(SORT_ARROW_MATCHER).perform(click());
+            }
+
+            return Matchers.present(allOf(
+                    DROPDOWN_MATCHER,
+                    withText(label)))
+                    && getDirection() == direction;
+        }
+
+        private @SortDirection int getDirection() {
+            final boolean ascending = Matchers.present(
+                    allOf(
+                            SORT_ARROW_MATCHER,
+                            withContentDescription(R.string.sort_direction_ascending)));
+
+            if (ascending) {
+                return SORT_DIRECTION_ASCENDING;
+            }
+
+            final boolean descending = Matchers.present(
+                    allOf(
+                            SORT_ARROW_MATCHER,
+                            withContentDescription(R.string.sort_direction_descending)));
+
+            return descending
+                    ? SortDimension.SORT_DIRECTION_DESCENDING
+                    : SortDimension.SORT_DIRECTION_NONE;
+        }
+    }
+
+    private static class ColumnSortBot {
+
+        private static final Matcher<View> MATCHER = withId(R.id.table_header);
+
+        private boolean sortBy(String label, @SortDirection int direction) {
+            final Matcher<View> cellMatcher = allOf(
+                    withChild(withText(label)),
+                    isDescendantOfA(MATCHER));
+            onView(cellMatcher).perform(click());
+
+            final @SortDirection int viewDirection = getDirection(cellMatcher);
+
+            if (viewDirection != direction) {
+                onView(cellMatcher).perform(click());
+            }
+
+            return getDirection(cellMatcher) == direction;
+        }
+
+        private @SortDirection int getDirection(Matcher<View> cellMatcher) {
+            final boolean ascending =
+                    Matchers.present(
+                            allOf(
+                                    withContentDescription(R.string.sort_direction_ascending),
+                                    withParent(cellMatcher)));
+            if (ascending) {
+                return SORT_DIRECTION_ASCENDING;
+            }
+
+            final boolean descending =
+                    Matchers.present(
+                            allOf(
+                                    withContentDescription(R.string.sort_direction_descending),
+                                    withParent(cellMatcher)));
+
+            return descending
+                    ? SortDimension.SORT_DIRECTION_DESCENDING
+                    : SortDimension.SORT_DIRECTION_NONE;
+        }
+    }
+}