1 /* 2 * Copyright (C) 2018 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 static junit.framework.Assert.assertEquals; 22 import static junit.framework.Assert.assertTrue; 23 24 import android.database.Cursor; 25 import android.os.Bundle; 26 import android.provider.DocumentsContract; 27 import android.provider.DocumentsContract.Document; 28 29 import androidx.test.filters.MediumTest; 30 31 import com.android.documentsui.base.DocumentInfo; 32 import com.android.documentsui.base.State; 33 import com.android.documentsui.sorting.SortDimension; 34 import com.android.documentsui.sorting.SortModel; 35 import com.android.documentsui.testing.ActivityManagers; 36 import com.android.documentsui.testing.TestEnv; 37 import com.android.documentsui.testing.TestFileTypeLookup; 38 import com.android.documentsui.testing.TestImmediateExecutor; 39 import com.android.documentsui.testing.TestProvidersAccess; 40 import com.android.modules.utils.build.SdkLevel; 41 42 import com.google.common.collect.Lists; 43 44 import org.junit.After; 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.junit.runners.Parameterized; 49 import org.junit.runners.Parameterized.Parameter; 50 import org.junit.runners.Parameterized.Parameters; 51 52 @RunWith(Parameterized.class) 53 @MediumTest 54 public class GlobalSearchLoaderTest { 55 56 private static final String SEARCH_STRING = "freddy"; 57 private static int FILE_FLAG = Document.FLAG_SUPPORTS_MOVE | Document.FLAG_SUPPORTS_DELETE 58 | Document.FLAG_SUPPORTS_REMOVE; 59 60 private TestEnv mEnv; 61 private TestActivity mActivity; 62 private GlobalSearchLoader mLoader; 63 private TestConfigStore mTestConfigStore; 64 private Bundle mQueryArgs = new Bundle(); 65 66 @Parameter(0) 67 public boolean isPrivateSpaceEnabled; 68 69 /** 70 * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with 71 * private space flag enabled and once with it disabled. 72 */ 73 @Parameters(name = "privateSpaceEnabled={0}") data()74 public static Iterable<?> data() { 75 return Lists.newArrayList(true, false); 76 } 77 78 @Before setUp()79 public void setUp() { 80 mEnv = TestEnv.create(); 81 mActivity = TestActivity.create(mEnv); 82 mActivity.activityManager = ActivityManagers.create(false); 83 mTestConfigStore = new TestConfigStore(); 84 mEnv.state.configStore = mTestConfigStore; 85 86 isPrivateSpaceEnabled &= SdkLevel.isAtLeastS(); 87 if (isPrivateSpaceEnabled) { 88 mTestConfigStore.enablePrivateSpaceInPhotoPicker(); 89 mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); 90 } 91 92 mEnv.state.action = State.ACTION_BROWSE; 93 mEnv.state.acceptMimes = new String[]{"*/*"}; 94 95 mQueryArgs.putString(DocumentsContract.QUERY_ARG_DISPLAY_NAME, SEARCH_STRING); 96 mLoader = new GlobalSearchLoader(mActivity, mEnv.providers, mEnv.state, 97 TestImmediateExecutor.createLookup(), new TestFileTypeLookup(), mQueryArgs, 98 TestProvidersAccess.USER_ID); 99 100 final DocumentInfo doc = mEnv.model.createFile(SEARCH_STRING + ".jpg", FILE_FLAG); 101 doc.lastModified = System.currentTimeMillis(); 102 mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) 103 .setNextChildDocumentsReturns(doc); 104 105 TestProvidersAccess.DOWNLOADS.flags |= DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; 106 } 107 108 @After tearDown()109 public void tearDown() { 110 TestProvidersAccess.DOWNLOADS.flags &= ~DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; 111 } 112 113 @Test testNotSearchableRoot_beIgnored()114 public void testNotSearchableRoot_beIgnored() { 115 TestProvidersAccess.PICKLES.flags |= DocumentsContract.Root.FLAG_LOCAL_ONLY; 116 assertTrue(mLoader.shouldIgnoreRoot(TestProvidersAccess.PICKLES)); 117 TestProvidersAccess.PICKLES.flags &= ~DocumentsContract.Root.FLAG_LOCAL_ONLY; 118 } 119 120 @Test testNotLocalOnlyRoot_beIgnored()121 public void testNotLocalOnlyRoot_beIgnored() { 122 if (isPrivateSpaceEnabled) return; 123 TestProvidersAccess.PICKLES.flags |= DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; 124 assertTrue(mLoader.shouldIgnoreRoot(TestProvidersAccess.PICKLES)); 125 TestProvidersAccess.PICKLES.flags &= ~DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; 126 } 127 128 @Test testShowAdvance_storageRoot_beIgnored()129 public void testShowAdvance_storageRoot_beIgnored() { 130 TestProvidersAccess.HOME.flags |= DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; 131 assertTrue(mLoader.shouldIgnoreRoot(TestProvidersAccess.HOME)); 132 TestProvidersAccess.HOME.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH); 133 } 134 135 @Test testCrossProfileRoot_notInTextSearch_beIgnored()136 public void testCrossProfileRoot_notInTextSearch_beIgnored() { 137 mEnv.state.supportsCrossProfile = true; 138 mQueryArgs.remove(DocumentsContract.QUERY_ARG_DISPLAY_NAME); 139 TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.OtherUser.USER_ID; 140 assertThat(mLoader.shouldIgnoreRoot(TestProvidersAccess.DOWNLOADS)).isTrue(); 141 TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; 142 } 143 144 @Test testCrossProfileRoot_inTextSearch_beIncluded()145 public void testCrossProfileRoot_inTextSearch_beIncluded() { 146 mEnv.state.supportsCrossProfile = true; 147 TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.OtherUser.USER_ID; 148 assertThat(mLoader.shouldIgnoreRoot(TestProvidersAccess.DOWNLOADS)).isFalse(); 149 TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; 150 } 151 152 @Test testSearchResult_includeDirectory()153 public void testSearchResult_includeDirectory() { 154 final DocumentInfo doc = mEnv.model.createFolder(SEARCH_STRING); 155 doc.lastModified = System.currentTimeMillis(); 156 157 mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) 158 .setNextChildDocumentsReturns(doc); 159 160 final DirectoryResult result = mLoader.loadInBackground(); 161 162 final Cursor c = result.getCursor(); 163 assertEquals(1, c.getCount()); 164 165 c.moveToNext(); 166 final String mimeType = c.getString(c.getColumnIndex(Document.COLUMN_MIME_TYPE)); 167 assertEquals(Document.MIME_TYPE_DIR, mimeType); 168 } 169 170 @Test testShowOrHideHiddenFiles()171 public void testShowOrHideHiddenFiles() { 172 final DocumentInfo doc1 = mEnv.model.createFile(".test" + SEARCH_STRING); 173 final DocumentInfo doc2 = mEnv.model.createFile("test" + SEARCH_STRING); 174 doc1.documentId = ".test"; 175 doc2.documentId = "parent_folder/.hidden_folder/test"; 176 mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) 177 .setNextChildDocumentsReturns(doc1, doc2); 178 179 assertEquals(false, mLoader.mState.showHiddenFiles); 180 DirectoryResult result = mLoader.loadInBackground(); 181 assertEquals(0, result.getCursor().getCount()); 182 183 mLoader.mState.showHiddenFiles = true; 184 result = mLoader.loadInBackground(); 185 assertEquals(2, result.getCursor().getCount()); 186 } 187 188 @Test testSearchResult_isNotMovable()189 public void testSearchResult_isNotMovable() { 190 final DirectoryResult result = mLoader.loadInBackground(); 191 192 final Cursor c = result.getCursor(); 193 assertEquals(1, c.getCount()); 194 195 c.moveToNext(); 196 final int flags = c.getInt(c.getColumnIndex(Document.COLUMN_FLAGS)); 197 assertEquals(0, flags & Document.FLAG_SUPPORTS_DELETE); 198 assertEquals(0, flags & Document.FLAG_SUPPORTS_REMOVE); 199 assertEquals(0, flags & Document.FLAG_SUPPORTS_MOVE); 200 } 201 202 @Test testSearchResult_includeDirectory_excludedOtherUsers()203 public void testSearchResult_includeDirectory_excludedOtherUsers() { 204 mEnv.state.canShareAcrossProfile = false; 205 206 TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; 207 TestProvidersAccess.PICKLES.userId = TestProvidersAccess.OtherUser.USER_ID; 208 TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH 209 | DocumentsContract.Root.FLAG_LOCAL_ONLY); 210 211 final DocumentInfo currentUserDoc = mEnv.model.createFile( 212 SEARCH_STRING + "_currentUser.pdf"); 213 currentUserDoc.lastModified = System.currentTimeMillis(); 214 mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) 215 .setNextChildDocumentsReturns(currentUserDoc); 216 217 final DocumentInfo otherUserDoc = mEnv.model.createFile(SEARCH_STRING + "_otherUser.png"); 218 otherUserDoc.lastModified = System.currentTimeMillis(); 219 mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) 220 .setNextChildDocumentsReturns(otherUserDoc); 221 222 final DirectoryResult result = mLoader.loadInBackground(); 223 final Cursor c = result.getCursor(); 224 225 assertThat(c.getCount()).isEqualTo(1); 226 c.moveToNext(); 227 final String docName = c.getString(c.getColumnIndex(Document.COLUMN_DISPLAY_NAME)); 228 assertThat(docName).contains("currentUser"); 229 230 TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; 231 TestProvidersAccess.PICKLES.userId = TestProvidersAccess.USER_ID; 232 TestProvidersAccess.PICKLES.flags &= ~DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; 233 } 234 235 @Test testSearchResult_includeSearchString()236 public void testSearchResult_includeSearchString() { 237 final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); 238 pdfDoc.lastModified = System.currentTimeMillis(); 239 240 final DocumentInfo apkDoc = mEnv.model.createFile(SEARCH_STRING + ".apk"); 241 apkDoc.lastModified = System.currentTimeMillis(); 242 243 final DocumentInfo testApkDoc = mEnv.model.createFile("test.apk"); 244 testApkDoc.lastModified = System.currentTimeMillis(); 245 246 mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) 247 .setNextChildDocumentsReturns(pdfDoc, apkDoc, testApkDoc); 248 249 mEnv.state.sortModel.sortByUser( 250 SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); 251 252 final DirectoryResult result = mLoader.loadInBackground(); 253 final Cursor c = result.getCursor(); 254 255 assertEquals(2, c.getCount()); 256 257 c.moveToNext(); 258 String displayName = c.getString(c.getColumnIndex(Document.COLUMN_DISPLAY_NAME)); 259 assertTrue(displayName.contains(SEARCH_STRING)); 260 261 c.moveToNext(); 262 displayName = c.getString(c.getColumnIndex(Document.COLUMN_DISPLAY_NAME)); 263 assertTrue(displayName.contains(SEARCH_STRING)); 264 } 265 266 @Test testSearchResult_includeDifferentRoot()267 public void testSearchResult_includeDifferentRoot() { 268 final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); 269 pdfDoc.lastModified = System.currentTimeMillis(); 270 271 final DocumentInfo apkDoc = mEnv.model.createFile(SEARCH_STRING + ".apk"); 272 apkDoc.lastModified = System.currentTimeMillis(); 273 274 final DocumentInfo testApkDoc = mEnv.model.createFile("test.apk"); 275 testApkDoc.lastModified = System.currentTimeMillis(); 276 277 mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) 278 .setNextChildDocumentsReturns(pdfDoc, apkDoc, testApkDoc); 279 280 TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH 281 | DocumentsContract.Root.FLAG_LOCAL_ONLY); 282 283 mEnv.state.sortModel.sortByUser( 284 SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); 285 286 final DirectoryResult result = mLoader.loadInBackground(); 287 final Cursor c = result.getCursor(); 288 289 assertEquals(3, c.getCount()); 290 291 TestProvidersAccess.PICKLES.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH 292 | DocumentsContract.Root.FLAG_LOCAL_ONLY); 293 } 294 295 @Test testSearchResult_includeCurrentUserRootOnly()296 public void testSearchResult_includeCurrentUserRootOnly() { 297 mEnv.state.canShareAcrossProfile = false; 298 mEnv.state.supportsCrossProfile = true; 299 300 final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); 301 pdfDoc.lastModified = System.currentTimeMillis(); 302 303 final DocumentInfo apkDoc = mEnv.model.createFile(SEARCH_STRING + ".apk"); 304 apkDoc.lastModified = System.currentTimeMillis(); 305 306 final DocumentInfo testApkDoc = mEnv.model.createFile("test.apk"); 307 testApkDoc.lastModified = System.currentTimeMillis(); 308 309 mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) 310 .setNextChildDocumentsReturns(pdfDoc, apkDoc, testApkDoc); 311 TestProvidersAccess.PICKLES.userId = TestProvidersAccess.OtherUser.USER_ID; 312 313 TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH 314 | DocumentsContract.Root.FLAG_LOCAL_ONLY); 315 mEnv.state.sortModel.sortByUser( 316 SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); 317 318 final DirectoryResult result = mLoader.loadInBackground(); 319 final Cursor c = result.getCursor(); 320 321 assertEquals(1, c.getCount()); 322 323 TestProvidersAccess.PICKLES.userId = TestProvidersAccess.USER_ID; 324 TestProvidersAccess.PICKLES.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH 325 | DocumentsContract.Root.FLAG_LOCAL_ONLY); 326 } 327 328 329 @Test testSearchResult_includeBothUsersRoots()330 public void testSearchResult_includeBothUsersRoots() { 331 if (isPrivateSpaceEnabled) { 332 mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true); 333 } else { 334 mEnv.state.canShareAcrossProfile = true; 335 } 336 mEnv.state.supportsCrossProfile = true; 337 338 final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); 339 pdfDoc.lastModified = System.currentTimeMillis(); 340 341 final DocumentInfo apkDoc = mEnv.model.createFile(SEARCH_STRING + ".apk"); 342 apkDoc.lastModified = System.currentTimeMillis(); 343 344 final DocumentInfo testApkDoc = mEnv.model.createFile("test.apk"); 345 testApkDoc.lastModified = System.currentTimeMillis(); 346 347 mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) 348 .setNextChildDocumentsReturns(pdfDoc, apkDoc, testApkDoc); 349 TestProvidersAccess.PICKLES.userId = TestProvidersAccess.OtherUser.USER_ID; 350 351 TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH 352 | DocumentsContract.Root.FLAG_LOCAL_ONLY); 353 mEnv.state.sortModel.sortByUser( 354 SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); 355 356 final DirectoryResult result = mLoader.loadInBackground(); 357 final Cursor c = result.getCursor(); 358 359 assertEquals(3, c.getCount()); 360 361 TestProvidersAccess.PICKLES.userId = TestProvidersAccess.USER_ID; 362 TestProvidersAccess.PICKLES.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH 363 | DocumentsContract.Root.FLAG_LOCAL_ONLY); 364 } 365 366 367 @Test testSearchResult_emptyCurrentUsersRoot()368 public void testSearchResult_emptyCurrentUsersRoot() { 369 mEnv.state.canShareAcrossProfile = false; 370 mEnv.state.supportsCrossProfile = true; 371 372 final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); 373 pdfDoc.lastModified = System.currentTimeMillis(); 374 375 mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) 376 .setNextChildDocumentsReturns(pdfDoc); 377 378 TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.OtherUser.USER_ID; 379 TestProvidersAccess.PICKLES.userId = TestProvidersAccess.OtherUser.USER_ID; 380 TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH 381 | DocumentsContract.Root.FLAG_LOCAL_ONLY); 382 mEnv.state.sortModel.sortByUser( 383 SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); 384 385 final DirectoryResult result = mLoader.loadInBackground(); 386 assertThat(result.getCursor().getCount()).isEqualTo(0); 387 // We don't expect exception even if all roots are from other users. 388 assertThat(result.exception).isNull(); 389 390 391 TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; 392 TestProvidersAccess.PICKLES.userId = TestProvidersAccess.USER_ID; 393 TestProvidersAccess.PICKLES.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH 394 | DocumentsContract.Root.FLAG_LOCAL_ONLY); 395 } 396 } 397