Enable DirectoryFragment.onRefresh works when there is no root doc.

This enables us to reload the directory correctly. On next CL,
we will refresh directory when we listened to some event. (e.g. work
profile is unlocked)

Also now we can perform search in directory loader on a disabled user.

* In DirectoryFragment, refresh stack without root doc
DirectoryFragment will now try to reload rootDoc and push it to stack
onRefresh. This is useful when the root doc was temporarily unable to
load (e.g. work profile was turned off)

* Search across profile on an empty stack
Directory takes care of empty stack now. We will restart loader in
loadDocumentsForCurrentStack. If there is only one queriable user,
the same exception message will be updated.

* ProfileTabs
The tab layout will be updated if the current root does not match.
This could happen when opening a search folder from the other user.

* QuickViewIntentBuilder
Now use a correct packageManager to test intent

Bug: 148270816
Bug: 150600030
Bug: 150799134
Test: atest DocumentsUIGoogleTests
Test: manual

Change-Id: Ib6684e4dd2a257f92ee3784297b5568cbd3d21b2
diff --git a/tests/unit/com/android/documentsui/ProfileTabsTest.java b/tests/unit/com/android/documentsui/ProfileTabsTest.java
index 5330e9c..156c7ca 100644
--- a/tests/unit/com/android/documentsui/ProfileTabsTest.java
+++ b/tests/unit/com/android/documentsui/ProfileTabsTest.java
@@ -19,12 +19,14 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
+import android.net.Uri;
 import android.os.UserHandle;
 import android.view.LayoutInflater;
 import android.view.View;
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.RootInfo;
 import com.android.documentsui.base.State;
 import com.android.documentsui.base.UserId;
@@ -38,6 +40,7 @@
 import org.junit.Test;
 
 import java.util.Collections;
+import java.util.List;
 
 public class ProfileTabsTest {
 
@@ -51,6 +54,8 @@
     private TestEnvironment mTestEnv;
     private State mState;
     private TestUserIdManager mTestUserIdManager;
+    private TestCommonAddons mTestCommonAddons;
+    private boolean mIsListenerInvoked;
 
     @Before
     public void setUp() {
@@ -70,6 +75,8 @@
         mTestEnv.isSearching = false;
 
         mTestUserIdManager = new TestUserIdManager();
+        mTestCommonAddons = new TestCommonAddons();
+        mTestCommonAddons.mCurrentRoot = TestProvidersAccess.DOWNLOADS;
     }
 
     @Test
@@ -167,6 +174,23 @@
     }
 
     @Test
+    public void testUpdateView_afterCurrentRootChanged_shouldChangeSelectedUser() {
+        initializeWithUsers(systemUser, managedUser);
+        mProfileTabs.updateView();
+
+        assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser);
+
+        RootInfo newRoot = RootInfo.copyRootInfo(mTestCommonAddons.mCurrentRoot);
+        newRoot.userId = managedUser;
+        mTestCommonAddons.mCurrentRoot = newRoot;
+        mProfileTabs.updateView();
+
+        assertThat(mProfileTabs.getSelectedUser()).isEqualTo(managedUser);
+        // updating view should not trigger listener callback.
+        assertThat(mIsListenerInvoked).isFalse();
+    }
+
+    @Test
     public void testgetSelectedUser_twoUsers() {
         initializeWithUsers(systemUser, managedUser);
 
@@ -175,6 +199,19 @@
 
         mTabLayout.selectTab(mTabLayout.getTabAt(1));
         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(managedUser);
+        assertThat(mIsListenerInvoked).isTrue();
+    }
+
+    @Test
+    public void testReselectedUser_doesNotInvokeListener() {
+        initializeWithUsers(systemUser, managedUser);
+
+        assertThat(mTabLayout.getSelectedTabPosition()).isAtLeast(0);
+        assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser);
+
+        mTabLayout.selectTab(mTabLayout.getTabAt(0));
+        assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser);
+        assertThat(mIsListenerInvoked).isFalse();
     }
 
     @Test
@@ -194,8 +231,10 @@
             }
         }
 
-        mProfileTabs = new ProfileTabs(mTabLayout, mState, mTestUserIdManager, mTestEnv);
+        mProfileTabs = new ProfileTabs(mTabLayout, mState, mTestUserIdManager, mTestEnv,
+                mTestCommonAddons);
         mProfileTabs.updateView();
+        mProfileTabs.setListener(userId -> mIsListenerInvoked = true);
     }
 
     /**
@@ -231,5 +270,70 @@
         }
 
     }
+
+    private static class TestCommonAddons implements AbstractActionHandler.CommonAddons {
+
+        private RootInfo mCurrentRoot;
+
+        @Override
+        public void restoreRootAndDirectory() {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public void refreshCurrentRootAndDirectory(int anim) {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public void onRootPicked(RootInfo root) {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public void onDocumentsPicked(List<DocumentInfo> docs) {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public void onDocumentPicked(DocumentInfo doc) {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public RootInfo getCurrentRoot() {
+            return mCurrentRoot;
+        }
+
+        @Override
+        public DocumentInfo getCurrentDirectory() {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public UserId getSelectedUser() {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public boolean isInRecents() {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public void setRootsDrawerOpen(boolean open) {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public void updateNavigator() {
+            throw new UnsupportedOperationException("not implemented");
+        }
+
+        @Override
+        public void notifyDirectoryNavigated(Uri docUri) {
+            throw new UnsupportedOperationException("not implemented");
+        }
+    }
 }