1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.documentsui;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import android.content.Context;
22 import android.net.Uri;
23 import android.os.UserHandle;
24 import android.view.LayoutInflater;
25 import android.view.View;
26 
27 import androidx.test.InstrumentationRegistry;
28 
29 import com.android.documentsui.base.DocumentInfo;
30 import com.android.documentsui.base.RootInfo;
31 import com.android.documentsui.base.State;
32 import com.android.documentsui.base.UserId;
33 import com.android.documentsui.testing.TestEnv;
34 import com.android.documentsui.testing.TestProvidersAccess;
35 
36 import com.google.android.collect.Lists;
37 import com.google.android.material.tabs.TabLayout;
38 
39 import org.junit.Before;
40 import org.junit.Test;
41 
42 import java.util.Collections;
43 import java.util.List;
44 
45 public class ProfileTabsTest {
46 
47     private final UserId systemUser = UserId.of(UserHandle.SYSTEM);
48     private final UserId managedUser = UserId.of(100);
49 
50     private ProfileTabs mProfileTabs;
51 
52     private Context mContext;
53     private TabLayout mTabLayout;
54     private TestEnvironment mTestEnv;
55     private State mState;
56     private TestUserIdManager mTestUserIdManager;
57     private TestCommonAddons mTestCommonAddons;
58     private boolean mIsListenerInvoked;
59 
60     @Before
setUp()61     public void setUp() {
62         TestEnv.create();
63         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
64         mContext.setTheme(R.style.DocumentsTheme);
65         mContext.getTheme().applyStyle(R.style.DocumentsDefaultTheme, false);
66         LayoutInflater layoutInflater = LayoutInflater.from(mContext);
67         mState = new State();
68         mState.supportsCrossProfile = true;
69         mState.stack.changeRoot(TestProvidersAccess.DOWNLOADS);
70         mState.stack.push(TestEnv.FOLDER_0);
71         View view = layoutInflater.inflate(R.layout.directory_header, null);
72 
73         mTabLayout = view.findViewById(R.id.tabs);
74         mTestEnv = new TestEnvironment();
75         mTestEnv.isSearchExpanded = false;
76 
77         mTestUserIdManager = new TestUserIdManager();
78         mTestCommonAddons = new TestCommonAddons();
79         mTestCommonAddons.mCurrentRoot = TestProvidersAccess.DOWNLOADS;
80     }
81 
82     @Test
testUpdateView_singleUser_shouldHide()83     public void testUpdateView_singleUser_shouldHide() {
84         initializeWithUsers(systemUser);
85 
86         assertThat(mTabLayout.getVisibility()).isEqualTo(View.GONE);
87         assertThat(mTabLayout.getTabCount()).isEqualTo(0);
88     }
89 
90     @Test
testUpdateView_twoUsers_shouldShow()91     public void testUpdateView_twoUsers_shouldShow() {
92         initializeWithUsers(systemUser, managedUser);
93 
94         assertThat(mTabLayout.getVisibility()).isEqualTo(View.VISIBLE);
95         assertThat(mTabLayout.getTabCount()).isEqualTo(2);
96 
97         TabLayout.Tab tab1 = mTabLayout.getTabAt(0);
98         assertThat(tab1.getTag()).isEqualTo(systemUser);
99         assertThat(tab1.getText()).isEqualTo(mContext.getString(R.string.personal_tab));
100 
101         TabLayout.Tab tab2 = mTabLayout.getTabAt(1);
102         assertThat(tab2.getTag()).isEqualTo(managedUser);
103         assertThat(tab2.getText()).isEqualTo(mContext.getString(R.string.work_tab));
104     }
105 
106     @Test
testUpdateView_twoUsers_doesNotSupportCrossProfile_shouldHide()107     public void testUpdateView_twoUsers_doesNotSupportCrossProfile_shouldHide() {
108         initializeWithUsers(systemUser, managedUser);
109 
110         mState.supportsCrossProfile = false;
111         mProfileTabs.updateView();
112 
113         assertThat(mTabLayout.getVisibility()).isEqualTo(View.GONE);
114     }
115 
116     @Test
testUpdateView_twoUsers_subFolder_shouldHide()117     public void testUpdateView_twoUsers_subFolder_shouldHide() {
118         initializeWithUsers(systemUser, managedUser);
119 
120         // Push 1 more folder. Now the stack has size of 2.
121         mState.stack.push(TestEnv.FOLDER_1);
122 
123         mProfileTabs.updateView();
124         assertThat(mTabLayout.getVisibility()).isEqualTo(View.GONE);
125         assertThat(mTabLayout.getTabCount()).isEqualTo(2);
126     }
127 
128     @Test
testUpdateView_twoUsers_recents_subFolder_shouldHide()129     public void testUpdateView_twoUsers_recents_subFolder_shouldHide() {
130         initializeWithUsers(systemUser, managedUser);
131 
132         mState.stack.changeRoot(TestProvidersAccess.RECENTS);
133         // This(stack of size 2 in Recents) may not happen in real world.
134         mState.stack.push((TestEnv.FOLDER_0));
135 
136         mProfileTabs.updateView();
137         assertThat(mTabLayout.getVisibility()).isEqualTo(View.GONE);
138         assertThat(mTabLayout.getTabCount()).isEqualTo(2);
139     }
140 
141     @Test
testUpdateView_twoUsers_thirdParty_shouldHide()142     public void testUpdateView_twoUsers_thirdParty_shouldHide() {
143         initializeWithUsers(systemUser, managedUser);
144 
145         mState.stack.changeRoot(TestProvidersAccess.PICKLES);
146         mState.stack.push((TestEnv.FOLDER_0));
147 
148         mProfileTabs.updateView();
149         assertThat(mTabLayout.getVisibility()).isEqualTo(View.GONE);
150         assertThat(mTabLayout.getTabCount()).isEqualTo(2);
151     }
152 
153     @Test
testUpdateView_twoUsers_isSearching_shouldHide()154     public void testUpdateView_twoUsers_isSearching_shouldHide() {
155         mTestEnv.isSearchExpanded = true;
156         initializeWithUsers(systemUser, managedUser);
157 
158         assertThat(mTabLayout.getVisibility()).isEqualTo(View.GONE);
159         assertThat(mTabLayout.getTabCount()).isEqualTo(2);
160     }
161 
162     @Test
testUpdateView_getSelectedUser_afterUsersChanged()163     public void testUpdateView_getSelectedUser_afterUsersChanged() {
164         initializeWithUsers(systemUser, managedUser);
165         mProfileTabs.updateView();
166         mTabLayout.selectTab(mTabLayout.getTabAt(1));
167         assertThat(mTabLayout.getVisibility()).isEqualTo(View.VISIBLE);
168         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(managedUser);
169 
170         mTestUserIdManager.userIds = Collections.singletonList(systemUser);
171         mProfileTabs.updateView();
172         assertThat(mTabLayout.getVisibility()).isEqualTo(View.GONE);
173         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser);
174     }
175 
176     @Test
testUpdateView_afterCurrentRootChanged_shouldChangeSelectedUser()177     public void testUpdateView_afterCurrentRootChanged_shouldChangeSelectedUser() {
178         initializeWithUsers(systemUser, managedUser);
179         mProfileTabs.updateView();
180 
181         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser);
182 
183         RootInfo newRoot = RootInfo.copyRootInfo(mTestCommonAddons.mCurrentRoot);
184         newRoot.userId = managedUser;
185         mTestCommonAddons.mCurrentRoot = newRoot;
186         mProfileTabs.updateView();
187 
188         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(managedUser);
189         // updating view should not trigger listener callback.
190         assertThat(mIsListenerInvoked).isFalse();
191     }
192 
193     @Test
testgetSelectedUser_twoUsers()194     public void testgetSelectedUser_twoUsers() {
195         initializeWithUsers(systemUser, managedUser);
196 
197         mTabLayout.selectTab(mTabLayout.getTabAt(0));
198         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser);
199 
200         mTabLayout.selectTab(mTabLayout.getTabAt(1));
201         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(managedUser);
202         assertThat(mIsListenerInvoked).isTrue();
203     }
204 
205     @Test
testReselectedUser_doesNotInvokeListener()206     public void testReselectedUser_doesNotInvokeListener() {
207         initializeWithUsers(systemUser, managedUser);
208 
209         assertThat(mTabLayout.getSelectedTabPosition()).isAtLeast(0);
210         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser);
211 
212         mTabLayout.selectTab(mTabLayout.getTabAt(0));
213         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser);
214         assertThat(mIsListenerInvoked).isFalse();
215     }
216 
217     @Test
testgetSelectedUser_singleUsers()218     public void testgetSelectedUser_singleUsers() {
219         initializeWithUsers(systemUser);
220 
221         assertThat(mProfileTabs.getSelectedUser()).isEqualTo(systemUser);
222     }
223 
initializeWithUsers(UserId... userIds)224     private void initializeWithUsers(UserId... userIds) {
225         mTestUserIdManager.userIds = Lists.newArrayList(userIds);
226         for (UserId userId : userIds) {
227             if (userId.isSystem()) {
228                 mTestUserIdManager.systemUser = userId;
229             } else {
230                 mTestUserIdManager.managedUser = userId;
231             }
232         }
233 
234         mProfileTabs = new ProfileTabs(mTabLayout, mState, mTestUserIdManager, mTestEnv,
235                 mTestCommonAddons);
236         mProfileTabs.updateView();
237         mProfileTabs.setListener(userId -> mIsListenerInvoked = true);
238     }
239 
240     /**
241      * A test implementation of {@link NavigationViewManager.Environment}.
242      */
243     private static class TestEnvironment implements NavigationViewManager.Environment {
244 
245         public boolean isSearchExpanded = false;
246 
247         @Override
getCurrentRoot()248         public RootInfo getCurrentRoot() {
249             throw new UnsupportedOperationException("not implemented");
250         }
251 
252         @Override
getDrawerTitle()253         public String getDrawerTitle() {
254             throw new UnsupportedOperationException("not implemented");
255         }
256 
257         @Override
refreshCurrentRootAndDirectory(int animation)258         public void refreshCurrentRootAndDirectory(int animation) {
259             throw new UnsupportedOperationException("not implemented");
260         }
261 
262         @Override
isSearchExpanded()263         public boolean isSearchExpanded() {
264             return isSearchExpanded;
265         }
266     }
267 
268     private static class TestCommonAddons implements AbstractActionHandler.CommonAddons {
269 
270         private RootInfo mCurrentRoot;
271 
272         @Override
restoreRootAndDirectory()273         public void restoreRootAndDirectory() {
274             throw new UnsupportedOperationException("not implemented");
275         }
276 
277         @Override
refreshCurrentRootAndDirectory(int anim)278         public void refreshCurrentRootAndDirectory(int anim) {
279             throw new UnsupportedOperationException("not implemented");
280         }
281 
282         @Override
onRootPicked(RootInfo root)283         public void onRootPicked(RootInfo root) {
284             throw new UnsupportedOperationException("not implemented");
285         }
286 
287         @Override
onDocumentsPicked(List<DocumentInfo> docs)288         public void onDocumentsPicked(List<DocumentInfo> docs) {
289             throw new UnsupportedOperationException("not implemented");
290         }
291 
292         @Override
onDocumentPicked(DocumentInfo doc)293         public void onDocumentPicked(DocumentInfo doc) {
294             throw new UnsupportedOperationException("not implemented");
295         }
296 
297         @Override
getCurrentRoot()298         public RootInfo getCurrentRoot() {
299             return mCurrentRoot;
300         }
301 
302         @Override
getCurrentDirectory()303         public DocumentInfo getCurrentDirectory() {
304             throw new UnsupportedOperationException("not implemented");
305         }
306 
307         @Override
getSelectedUser()308         public UserId getSelectedUser() {
309             throw new UnsupportedOperationException("not implemented");
310         }
311 
312         @Override
isInRecents()313         public boolean isInRecents() {
314             throw new UnsupportedOperationException("not implemented");
315         }
316 
317         @Override
setRootsDrawerOpen(boolean open)318         public void setRootsDrawerOpen(boolean open) {
319             throw new UnsupportedOperationException("not implemented");
320         }
321 
322         @Override
setRootsDrawerLocked(boolean locked)323         public void setRootsDrawerLocked(boolean locked) {
324             throw new UnsupportedOperationException("not implemented");
325         }
326 
327         @Override
updateNavigator()328         public void updateNavigator() {
329             throw new UnsupportedOperationException("not implemented");
330         }
331 
332         @Override
notifyDirectoryNavigated(Uri docUri)333         public void notifyDirectoryNavigated(Uri docUri) {
334             throw new UnsupportedOperationException("not implemented");
335         }
336     }
337 }
338 
339