/* * Copyright (C) 2018 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; import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import android.database.Cursor; import android.os.Bundle; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import androidx.test.filters.MediumTest; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.State; import com.android.documentsui.sorting.SortDimension; import com.android.documentsui.sorting.SortModel; import com.android.documentsui.testing.ActivityManagers; import com.android.documentsui.testing.TestEnv; import com.android.documentsui.testing.TestFileTypeLookup; import com.android.documentsui.testing.TestImmediateExecutor; import com.android.documentsui.testing.TestProvidersAccess; import com.android.modules.utils.build.SdkLevel; import com.google.common.collect.Lists; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) @MediumTest public class GlobalSearchLoaderTest { private static final String SEARCH_STRING = "freddy"; private static int FILE_FLAG = Document.FLAG_SUPPORTS_MOVE | Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_REMOVE; private TestEnv mEnv; private TestActivity mActivity; private GlobalSearchLoader mLoader; private TestConfigStore mTestConfigStore; private Bundle mQueryArgs = new Bundle(); @Parameter(0) public boolean isPrivateSpaceEnabled; /** * Parametrize values for {@code isPrivateSpaceEnabled} to run all the tests twice once with * private space flag enabled and once with it disabled. */ @Parameters(name = "privateSpaceEnabled={0}") public static Iterable data() { return Lists.newArrayList(true, false); } @Before public void setUp() { mEnv = TestEnv.create(); mActivity = TestActivity.create(mEnv); mActivity.activityManager = ActivityManagers.create(false); mTestConfigStore = new TestConfigStore(); mEnv.state.configStore = mTestConfigStore; isPrivateSpaceEnabled &= SdkLevel.isAtLeastS(); if (isPrivateSpaceEnabled) { mTestConfigStore.enablePrivateSpaceInPhotoPicker(); mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.USER_ID, true); } mEnv.state.action = State.ACTION_BROWSE; mEnv.state.acceptMimes = new String[]{"*/*"}; mQueryArgs.putString(DocumentsContract.QUERY_ARG_DISPLAY_NAME, SEARCH_STRING); mLoader = new GlobalSearchLoader(mActivity, mEnv.providers, mEnv.state, TestImmediateExecutor.createLookup(), new TestFileTypeLookup(), mQueryArgs, TestProvidersAccess.USER_ID); final DocumentInfo doc = mEnv.model.createFile(SEARCH_STRING + ".jpg", FILE_FLAG); doc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) .setNextChildDocumentsReturns(doc); TestProvidersAccess.DOWNLOADS.flags |= DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; } @After public void tearDown() { TestProvidersAccess.DOWNLOADS.flags &= ~DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; } @Test public void testNotSearchableRoot_beIgnored() { TestProvidersAccess.PICKLES.flags |= DocumentsContract.Root.FLAG_LOCAL_ONLY; assertTrue(mLoader.shouldIgnoreRoot(TestProvidersAccess.PICKLES)); TestProvidersAccess.PICKLES.flags &= ~DocumentsContract.Root.FLAG_LOCAL_ONLY; } @Test public void testNotLocalOnlyRoot_beIgnored() { if (isPrivateSpaceEnabled) return; TestProvidersAccess.PICKLES.flags |= DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; assertTrue(mLoader.shouldIgnoreRoot(TestProvidersAccess.PICKLES)); TestProvidersAccess.PICKLES.flags &= ~DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; } @Test public void testShowAdvance_storageRoot_beIgnored() { TestProvidersAccess.HOME.flags |= DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; assertTrue(mLoader.shouldIgnoreRoot(TestProvidersAccess.HOME)); TestProvidersAccess.HOME.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH); } @Test public void testCrossProfileRoot_notInTextSearch_beIgnored() { mEnv.state.supportsCrossProfile = true; mQueryArgs.remove(DocumentsContract.QUERY_ARG_DISPLAY_NAME); TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.OtherUser.USER_ID; assertThat(mLoader.shouldIgnoreRoot(TestProvidersAccess.DOWNLOADS)).isTrue(); TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; } @Test public void testCrossProfileRoot_inTextSearch_beIncluded() { mEnv.state.supportsCrossProfile = true; TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.OtherUser.USER_ID; assertThat(mLoader.shouldIgnoreRoot(TestProvidersAccess.DOWNLOADS)).isFalse(); TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; } @Test public void testSearchResult_includeDirectory() { final DocumentInfo doc = mEnv.model.createFolder(SEARCH_STRING); doc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) .setNextChildDocumentsReturns(doc); final DirectoryResult result = mLoader.loadInBackground(); final Cursor c = result.getCursor(); assertEquals(1, c.getCount()); c.moveToNext(); final String mimeType = c.getString(c.getColumnIndex(Document.COLUMN_MIME_TYPE)); assertEquals(Document.MIME_TYPE_DIR, mimeType); } @Test public void testShowOrHideHiddenFiles() { final DocumentInfo doc1 = mEnv.model.createFile(".test" + SEARCH_STRING); final DocumentInfo doc2 = mEnv.model.createFile("test" + SEARCH_STRING); doc1.documentId = ".test"; doc2.documentId = "parent_folder/.hidden_folder/test"; mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) .setNextChildDocumentsReturns(doc1, doc2); assertEquals(false, mLoader.mState.showHiddenFiles); DirectoryResult result = mLoader.loadInBackground(); assertEquals(0, result.getCursor().getCount()); mLoader.mState.showHiddenFiles = true; result = mLoader.loadInBackground(); assertEquals(2, result.getCursor().getCount()); } @Test public void testSearchResult_isNotMovable() { final DirectoryResult result = mLoader.loadInBackground(); final Cursor c = result.getCursor(); assertEquals(1, c.getCount()); c.moveToNext(); final int flags = c.getInt(c.getColumnIndex(Document.COLUMN_FLAGS)); assertEquals(0, flags & Document.FLAG_SUPPORTS_DELETE); assertEquals(0, flags & Document.FLAG_SUPPORTS_REMOVE); assertEquals(0, flags & Document.FLAG_SUPPORTS_MOVE); } @Test public void testSearchResult_includeDirectory_excludedOtherUsers() { mEnv.state.canShareAcrossProfile = false; TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; TestProvidersAccess.PICKLES.userId = TestProvidersAccess.OtherUser.USER_ID; TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH | DocumentsContract.Root.FLAG_LOCAL_ONLY); final DocumentInfo currentUserDoc = mEnv.model.createFile( SEARCH_STRING + "_currentUser.pdf"); currentUserDoc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) .setNextChildDocumentsReturns(currentUserDoc); final DocumentInfo otherUserDoc = mEnv.model.createFile(SEARCH_STRING + "_otherUser.png"); otherUserDoc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) .setNextChildDocumentsReturns(otherUserDoc); final DirectoryResult result = mLoader.loadInBackground(); final Cursor c = result.getCursor(); assertThat(c.getCount()).isEqualTo(1); c.moveToNext(); final String docName = c.getString(c.getColumnIndex(Document.COLUMN_DISPLAY_NAME)); assertThat(docName).contains("currentUser"); TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; TestProvidersAccess.PICKLES.userId = TestProvidersAccess.USER_ID; TestProvidersAccess.PICKLES.flags &= ~DocumentsContract.Root.FLAG_SUPPORTS_SEARCH; } @Test public void testSearchResult_includeSearchString() { final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); pdfDoc.lastModified = System.currentTimeMillis(); final DocumentInfo apkDoc = mEnv.model.createFile(SEARCH_STRING + ".apk"); apkDoc.lastModified = System.currentTimeMillis(); final DocumentInfo testApkDoc = mEnv.model.createFile("test.apk"); testApkDoc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.DOWNLOADS.authority) .setNextChildDocumentsReturns(pdfDoc, apkDoc, testApkDoc); mEnv.state.sortModel.sortByUser( SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); final DirectoryResult result = mLoader.loadInBackground(); final Cursor c = result.getCursor(); assertEquals(2, c.getCount()); c.moveToNext(); String displayName = c.getString(c.getColumnIndex(Document.COLUMN_DISPLAY_NAME)); assertTrue(displayName.contains(SEARCH_STRING)); c.moveToNext(); displayName = c.getString(c.getColumnIndex(Document.COLUMN_DISPLAY_NAME)); assertTrue(displayName.contains(SEARCH_STRING)); } @Test public void testSearchResult_includeDifferentRoot() { final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); pdfDoc.lastModified = System.currentTimeMillis(); final DocumentInfo apkDoc = mEnv.model.createFile(SEARCH_STRING + ".apk"); apkDoc.lastModified = System.currentTimeMillis(); final DocumentInfo testApkDoc = mEnv.model.createFile("test.apk"); testApkDoc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) .setNextChildDocumentsReturns(pdfDoc, apkDoc, testApkDoc); TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH | DocumentsContract.Root.FLAG_LOCAL_ONLY); mEnv.state.sortModel.sortByUser( SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); final DirectoryResult result = mLoader.loadInBackground(); final Cursor c = result.getCursor(); assertEquals(3, c.getCount()); TestProvidersAccess.PICKLES.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH | DocumentsContract.Root.FLAG_LOCAL_ONLY); } @Test public void testSearchResult_includeCurrentUserRootOnly() { mEnv.state.canShareAcrossProfile = false; mEnv.state.supportsCrossProfile = true; final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); pdfDoc.lastModified = System.currentTimeMillis(); final DocumentInfo apkDoc = mEnv.model.createFile(SEARCH_STRING + ".apk"); apkDoc.lastModified = System.currentTimeMillis(); final DocumentInfo testApkDoc = mEnv.model.createFile("test.apk"); testApkDoc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) .setNextChildDocumentsReturns(pdfDoc, apkDoc, testApkDoc); TestProvidersAccess.PICKLES.userId = TestProvidersAccess.OtherUser.USER_ID; TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH | DocumentsContract.Root.FLAG_LOCAL_ONLY); mEnv.state.sortModel.sortByUser( SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); final DirectoryResult result = mLoader.loadInBackground(); final Cursor c = result.getCursor(); assertEquals(1, c.getCount()); TestProvidersAccess.PICKLES.userId = TestProvidersAccess.USER_ID; TestProvidersAccess.PICKLES.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH | DocumentsContract.Root.FLAG_LOCAL_ONLY); } @Test public void testSearchResult_includeBothUsersRoots() { if (isPrivateSpaceEnabled) { mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true); } else { mEnv.state.canShareAcrossProfile = true; } mEnv.state.supportsCrossProfile = true; final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); pdfDoc.lastModified = System.currentTimeMillis(); final DocumentInfo apkDoc = mEnv.model.createFile(SEARCH_STRING + ".apk"); apkDoc.lastModified = System.currentTimeMillis(); final DocumentInfo testApkDoc = mEnv.model.createFile("test.apk"); testApkDoc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) .setNextChildDocumentsReturns(pdfDoc, apkDoc, testApkDoc); TestProvidersAccess.PICKLES.userId = TestProvidersAccess.OtherUser.USER_ID; TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH | DocumentsContract.Root.FLAG_LOCAL_ONLY); mEnv.state.sortModel.sortByUser( SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); final DirectoryResult result = mLoader.loadInBackground(); final Cursor c = result.getCursor(); assertEquals(3, c.getCount()); TestProvidersAccess.PICKLES.userId = TestProvidersAccess.USER_ID; TestProvidersAccess.PICKLES.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH | DocumentsContract.Root.FLAG_LOCAL_ONLY); } @Test public void testSearchResult_emptyCurrentUsersRoot() { mEnv.state.canShareAcrossProfile = false; mEnv.state.supportsCrossProfile = true; final DocumentInfo pdfDoc = mEnv.model.createFile(SEARCH_STRING + ".pdf"); pdfDoc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.PICKLES.authority) .setNextChildDocumentsReturns(pdfDoc); TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.OtherUser.USER_ID; TestProvidersAccess.PICKLES.userId = TestProvidersAccess.OtherUser.USER_ID; TestProvidersAccess.PICKLES.flags |= (DocumentsContract.Root.FLAG_SUPPORTS_SEARCH | DocumentsContract.Root.FLAG_LOCAL_ONLY); mEnv.state.sortModel.sortByUser( SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING); final DirectoryResult result = mLoader.loadInBackground(); assertThat(result.getCursor().getCount()).isEqualTo(0); // We don't expect exception even if all roots are from other users. assertThat(result.exception).isNull(); TestProvidersAccess.DOWNLOADS.userId = TestProvidersAccess.USER_ID; TestProvidersAccess.PICKLES.userId = TestProvidersAccess.USER_ID; TestProvidersAccess.PICKLES.flags &= ~(DocumentsContract.Root.FLAG_SUPPORTS_SEARCH | DocumentsContract.Root.FLAG_LOCAL_ONLY); } }