/* * Copyright (C) 2017 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.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import android.database.Cursor; 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.base.UserId; import com.android.documentsui.testing.ActivityManagers; import com.android.documentsui.testing.TestCursor; 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.documentsui.testing.UserManagers; import com.android.modules.utils.build.SdkLevel; import com.google.common.collect.Lists; 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; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @RunWith(Parameterized.class) @MediumTest public class RecentsLoaderTests { private TestEnv mEnv; private TestActivity mActivity; private RecentsLoader mLoader; private TestConfigStore mTestConfigStore; @Parameter(0) public boolean isPrivateSpaceEnabled; /** * Parameterized test to run all the tests in this class twice, once with private space enabled * and once with private space 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); mActivity.userManager = UserManagers.create(); mTestConfigStore = new TestConfigStore(); mEnv.state.configStore = mTestConfigStore; mEnv.state.action = State.ACTION_BROWSE; mEnv.state.acceptMimes = new String[]{"*/*"}; isPrivateSpaceEnabled = SdkLevel.isAtLeastS() && isPrivateSpaceEnabled; if (isPrivateSpaceEnabled) { mTestConfigStore.enablePrivateSpaceInPhotoPicker(); mEnv.state.canForwardToProfileIdMap.put(UserId.DEFAULT_USER, true); mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, true); } else { mEnv.state.canShareAcrossProfile = true; } mLoader = new RecentsLoader(mActivity, mEnv.providers, mEnv.state, TestImmediateExecutor.createLookup(), new TestFileTypeLookup(), TestProvidersAccess.USER_ID); } @Test public void testNotLocalOnlyRoot_beIgnored() { assertTrue(mLoader.shouldIgnoreRoot(TestProvidersAccess.PICKLES)); } @Test public void testLocalOnlyRoot_supportRecent_notIgnored() { assertFalse(mLoader.shouldIgnoreRoot(TestProvidersAccess.DOWNLOADS)); } @Test public void testLocalOnlyRoot_supportRecent_differentUser_beIgnored() { assertTrue(mLoader.shouldIgnoreRoot(TestProvidersAccess.OtherUser.DOWNLOADS)); } @Test public void testDocumentsNotIncludeDirectory() { final DocumentInfo doc = mEnv.model.createFolder("test"); doc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.HOME.authority) .setNextChildDocumentsReturns(doc); final DirectoryResult result = mLoader.loadInBackground(); final Cursor c = result.getCursor(); assertEquals(0, c.getCount()); } @Test public void testShowOrHideHiddenFiles() { final DocumentInfo doc1 = mEnv.model.createFile(".test"); final DocumentInfo doc2 = mEnv.model.createFile("test"); doc1.documentId = ".test"; doc2.documentId = "parent_folder/.hidden_folder/test"; doc1.lastModified = System.currentTimeMillis(); doc2.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.HOME.authority) .setNextRecentDocumentsReturns(doc1, doc2); assertFalse(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 testDocumentsNotMovable() { final DocumentInfo doc = mEnv.model.createFile("freddy.jpg", Document.FLAG_SUPPORTS_MOVE | Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_REMOVE); doc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.HOME.authority) .setNextRecentDocumentsReturns(doc); final DirectoryResult result = mLoader.loadInBackground(); final Cursor c = result.getCursor(); assertEquals(1, c.getCount()); for (int i = 0; i < c.getCount(); ++i) { 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 testContentsUpdate_observable() throws Exception { final CountDownLatch latch = new CountDownLatch(1); // Please be mindful of the fact that the callback will be invoked on the Main (aka UI) // thread, while the test itself is running on another (dedicated) thread. final Runnable onContentChangedCallback = latch::countDown; mLoader.setObserver(new LockingContentObserver( new ContentLock(), onContentChangedCallback)); final DocumentInfo doc = mEnv.model.createFile("freddy.jpg"); doc.lastModified = System.currentTimeMillis(); mEnv.mockProviders.get(TestProvidersAccess.HOME.authority) .setNextRecentDocumentsReturns(doc); mLoader.loadInBackground(); final TestCursor c = (TestCursor) mEnv.mockProviders.get(TestProvidersAccess.HOME.authority) .queryRecentDocuments(null, null); c.mockOnChange(); final boolean onContentChangedCallbackInvoked = latch.await(1, TimeUnit.SECONDS); assertTrue(onContentChangedCallbackInvoked); } @Test public void testLoaderOnUserWithoutPermission() { if (isPrivateSpaceEnabled) { mEnv.state.canForwardToProfileIdMap.put(TestProvidersAccess.OtherUser.USER_ID, false); } else { mEnv.state.canShareAcrossProfile = false; } mLoader = new RecentsLoader(mActivity, mEnv.providers, mEnv.state, TestImmediateExecutor.createLookup(), new TestFileTypeLookup(), TestProvidersAccess.OtherUser.USER_ID); final DirectoryResult result = mLoader.loadInBackground(); assertThat(result.getCursor()).isNull(); assertThat(result.exception).isInstanceOf(CrossProfileNoPermissionException.class); } @Test public void testLoaderOnUser_quietMode() { when(mActivity.userManager.isQuietModeEnabled(any())).thenReturn(true); final DirectoryResult result = mLoader.loadInBackground(); assertThat(result.getCursor()).isNull(); assertThat(result.exception).isInstanceOf(CrossProfileQuietModeException.class); } }