summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/Android.bp3
-rw-r--r--tests/functional/com/android/documentsui/ActivityTestJunit4.kt211
-rw-r--r--tests/functional/com/android/documentsui/SortDocumentUiTest.java39
3 files changed, 245 insertions, 8 deletions
diff --git a/tests/Android.bp b/tests/Android.bp
index 2b2daa45d..f67d344dd 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -25,9 +25,11 @@ java_defaults {
],
static_libs: [
+ "androidx.test.core",
"androidx.test.espresso.core",
"androidx.test.ext.truth",
"androidx.test.rules",
+ "androidx.test.ext.junit",
"androidx.test.uiautomator_uiautomator",
"docsui-flags-aconfig-java-lib",
"flag-junit",
@@ -93,6 +95,7 @@ android_library {
srcs: [
"common/**/*.java",
"functional/**/*.java",
+ "functional/**/*.kt",
"unit/**/*.java",
],
diff --git a/tests/functional/com/android/documentsui/ActivityTestJunit4.kt b/tests/functional/com/android/documentsui/ActivityTestJunit4.kt
new file mode 100644
index 000000000..daab0cdb4
--- /dev/null
+++ b/tests/functional/com/android/documentsui/ActivityTestJunit4.kt
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2024 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 android.app.Activity
+import android.app.UiAutomation
+import android.content.ContentResolver
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.RemoteException
+import android.provider.DocumentsContract
+import android.view.KeyEvent
+import android.view.MotionEvent
+import androidx.test.core.app.ActivityScenario
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.Configurator
+import androidx.test.uiautomator.UiDevice
+import com.android.documentsui.base.Features
+import com.android.documentsui.base.Features.RuntimeFeatures
+import com.android.documentsui.base.RootInfo
+import com.android.documentsui.base.UserId
+import com.android.documentsui.bots.Bots
+import com.android.documentsui.files.FilesActivity
+import java.io.IOException
+import java.util.Objects
+
+/**
+ * Provides basic test environment for UI tests:
+ * - Launches activity
+ * - Creates and gives access to test root directories and test files
+ * - Cleans up the test environment
+ */
+abstract class ActivityTestJunit4<T : Activity?> {
+ @JvmField
+ var bots: Bots? = null
+ var device: UiDevice? = null
+ var context: Context? = null
+ var userId: UserId? = null
+ var automation: UiAutomation? = null
+
+ var features: Features? = null
+
+ /**
+ * Returns the root that will be opened within the activity.
+ * By default tests are started with one of the test roots.
+ * Override the method if you want to open different root on start.
+ * @return Root that will be opened. Return null if you want to open activity's default root.
+ */
+ protected var initialRoot: RootInfo? = null
+ var rootDir1: RootInfo? = null
+ protected var mResolver: ContentResolver? = null
+
+ @JvmField
+ protected var mDocsHelper: DocumentsProviderHelper? = null
+ protected var mActivityScenario: ActivityScenario<T?>? = null
+ private var initialScreenOffTimeoutValue: String? = null
+ private var initialSleepTimeoutValue: String? = null
+
+ protected val testingProviderAuthority: String
+ /**
+ * Returns the authority of the testing provider begin used.
+ * By default it's StubProvider's authority.
+ * @return Authority of the provider.
+ */
+ get() = StubProvider.DEFAULT_AUTHORITY
+
+ /**
+ * Resolves testing roots.
+ */
+ @Throws(RemoteException::class)
+ protected fun setupTestingRoots() {
+ this.initialRoot = mDocsHelper!!.getRoot(StubProvider.ROOT_0_ID)
+ rootDir1 = mDocsHelper!!.getRoot(StubProvider.ROOT_1_ID)
+ }
+
+ @Throws(Exception::class)
+ open fun setUp() {
+ device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ // NOTE: Must be the "target" context, else security checks in content provider will fail.
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext()
+ userId = UserId.DEFAULT_USER
+ automation = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ features = RuntimeFeatures(context!!.getResources(), null)
+
+ bots = Bots(device, automation, context, TIMEOUT)
+
+ Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE)
+
+ mResolver = context!!.getContentResolver()
+ mDocsHelper = DocumentsProviderHelper(
+ userId, this.testingProviderAuthority, context,
+ this.testingProviderAuthority
+ )
+
+ device!!.setOrientationNatural()
+ device!!.pressKeyCode(KeyEvent.KEYCODE_WAKEUP)
+
+ disableScreenOffAndSleepTimeouts()
+
+ setupTestingRoots()
+
+ launchActivity()
+ resetStorage()
+
+ // Since at the launch of activity, ROOT_0 and ROOT_1 have no files, drawer will
+ // automatically open for phone devices. Espresso register click() as (x, y) MotionEvents,
+ // so if a drawer is on top of a file we want to select, it will actually click the drawer.
+ // Thus to start a clean state, we always try to close first.
+ bots!!.roots!!.closeDrawer()
+
+ // Configure the provider back to default.
+ mDocsHelper!!.configure(null, Bundle.EMPTY)
+ }
+
+ @Throws(Exception::class)
+ open fun tearDown() {
+ device!!.unfreezeRotation()
+ mDocsHelper!!.cleanUp()
+ restoreScreenOffAndSleepTimeouts()
+ mActivityScenario!!.close()
+ }
+
+ protected fun launchActivity() {
+ val intent = Intent(context, FilesActivity::class.java)
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
+ if (this.initialRoot != null) {
+ intent.setAction(Intent.ACTION_VIEW)
+ intent.setDataAndType(
+ this.initialRoot!!.uri,
+ DocumentsContract.Root.MIME_TYPE_ITEM
+ )
+ }
+ mActivityScenario = ActivityScenario.launch(intent)
+ }
+
+ @Throws(RemoteException::class)
+ protected fun resetStorage() {
+ mDocsHelper!!.clear(null, null)
+ device!!.waitForIdle()
+ }
+
+ @Throws(RemoteException::class)
+ protected fun initTestFiles() {
+ mDocsHelper!!.createFolder(this.initialRoot, dirName1)
+ mDocsHelper!!.createDocument(this.initialRoot, "text/plain", fileName1)
+ mDocsHelper!!.createDocument(this.initialRoot, "image/png", fileName2)
+ mDocsHelper!!.createDocumentWithFlags(
+ initialRoot!!.documentId,
+ "text/plain",
+ fileNameNoRename,
+ DocumentsContract.Document.FLAG_SUPPORTS_WRITE
+ )
+
+ mDocsHelper!!.createDocument(rootDir1, "text/plain", fileName3)
+ mDocsHelper!!.createDocument(rootDir1, "text/plain", fileName4)
+ }
+
+ @Throws(IOException::class)
+ private fun disableScreenOffAndSleepTimeouts() {
+ initialScreenOffTimeoutValue = device!!.executeShellCommand(
+ "settings get system screen_off_timeout"
+ )
+ initialSleepTimeoutValue = device!!.executeShellCommand(
+ "settings get secure sleep_timeout"
+ )
+ device!!.executeShellCommand("settings put system screen_off_timeout -1")
+ device!!.executeShellCommand("settings put secure sleep_timeout -1")
+ }
+
+ @Throws(IOException::class)
+ private fun restoreScreenOffAndSleepTimeouts() {
+ Objects.requireNonNull<String?>(initialScreenOffTimeoutValue)
+ Objects.requireNonNull<String?>(initialSleepTimeoutValue)
+ try {
+ device!!.executeShellCommand(
+ "settings put system screen_off_timeout $initialScreenOffTimeoutValue"
+ )
+ device!!.executeShellCommand(
+ "settings put secure sleep_timeout $initialSleepTimeoutValue"
+ )
+ } finally {
+ initialScreenOffTimeoutValue = null
+ initialSleepTimeoutValue = null
+ }
+ }
+
+ companion object {
+ // Testing files. For custom ones, override initTestFiles().
+ const val dirName1 = "Dir1"
+ const val fileName1 = "file1.log"
+ const val fileName2 = "file12.png"
+ const val fileName3 = "anotherFile0.log"
+ const val fileName4 = "poodles.text"
+ const val fileNameNoRename = "NO_RENAMEfile.txt"
+ const val TIMEOUT = 5000
+ }
+}
diff --git a/tests/functional/com/android/documentsui/SortDocumentUiTest.java b/tests/functional/com/android/documentsui/SortDocumentUiTest.java
index a6907d680..53bc372e0 100644
--- a/tests/functional/com/android/documentsui/SortDocumentUiTest.java
+++ b/tests/functional/com/android/documentsui/SortDocumentUiTest.java
@@ -19,13 +19,20 @@ package com.android.documentsui;
import android.net.Uri;
import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import com.android.documentsui.files.FilesActivity;
import com.android.documentsui.sorting.SortDimension;
import com.android.documentsui.sorting.SortModel;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
@LargeTest
-public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
+@RunWith(AndroidJUnit4.class)
+public class SortDocumentUiTest extends ActivityTestJunit4<FilesActivity> {
private static final String DIR_1 = "folder_1";
private static final String DIR_2 = "dir_2";
@@ -52,10 +59,6 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
private static final String[] FILES_IN_TYPE_ASC = {FILE_2, FILE_3, FILE_1};
private static final String[] FILES_IN_TYPE_DESC = reverse(FILES_IN_TYPE_ASC);
- public SortDocumentUiTest() {
- super(FilesActivity.class);
- }
-
private static String[] reverse(String[] array) {
String[] ret = new String[array.length];
@@ -66,12 +69,17 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
return ret;
}
- @Override
+ @Before
public void setUp() throws Exception {
super.setUp();
bots.roots.closeDrawer();
}
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
private void initFiles() throws Exception {
initFiles(0);
}
@@ -84,24 +92,26 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
*/
private void initFiles(long sleep) throws Exception {
for (int i = 0; i < FILES.length; ++i) {
- Uri uri = mDocsHelper.createDocument(rootDir0, MIMES[i], FILES[i]);
+ Uri uri = mDocsHelper.createDocument(getInitialRoot(), MIMES[i], FILES[i]);
mDocsHelper.writeDocument(uri, FILES[i].getBytes());
Thread.sleep(sleep);
}
for (String dir : DIRS) {
- mDocsHelper.createFolder(rootDir0, dir);
+ mDocsHelper.createFolder(getInitialRoot(), dir);
Thread.sleep(sleep);
}
}
+ @Test
public void testDefaultSortByNameAscending() throws Exception {
initFiles();
bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_NAME_ASC);
}
+ @Test
public void testSortByName_Descending_listMode() throws Exception {
initFiles();
@@ -112,6 +122,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_NAME_DESC, FILES_IN_NAME_DESC);
}
+ @Test
public void testSortBySize_Ascending_listMode() throws Exception {
initFiles();
@@ -121,6 +132,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_ASC);
}
+ @Test
public void testSortBySize_Descending_listMode() throws Exception {
initFiles();
@@ -130,6 +142,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_DESC);
}
+ @Test
public void testSortByModified_Ascending_listMode() throws Exception {
initFiles(1000);
@@ -139,6 +152,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS, FILES);
}
+ @Test
public void testSortByModified_Descending_listMode() throws Exception {
initFiles(1000);
@@ -148,6 +162,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_MODIFIED_DESC, FILES_IN_MODIFIED_DESC);
}
+ @Test
public void testSortByType_Ascending_listMode() throws Exception {
initFiles();
@@ -158,6 +173,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_TYPE_ASC);
}
+ @Test
public void testSortByType_Descending_listMode() throws Exception {
initFiles();
@@ -168,6 +184,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_TYPE_DESC);
}
+ @Test
public void testSortByName_Descending_gridMode() throws Exception {
initFiles();
@@ -178,6 +195,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_NAME_DESC, FILES_IN_NAME_DESC);
}
+ @Test
public void testSortBySize_Ascending_gridMode() throws Exception {
initFiles();
@@ -187,6 +205,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_ASC);
}
+ @Test
public void testSortBySize_Descending_gridMode() throws Exception {
initFiles();
@@ -196,6 +215,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_SIZE_DESC);
}
+ @Test
public void testSortByModified_Ascending_gridMode() throws Exception {
initFiles(1000);
@@ -205,6 +225,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS, FILES);
}
+ @Test
public void testSortByModified_Descending_gridMode() throws Exception {
initFiles(1000);
@@ -214,6 +235,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_MODIFIED_DESC, FILES_IN_MODIFIED_DESC);
}
+ @Test
public void testSortByType_Ascending_gridMode() throws Exception {
initFiles();
@@ -224,6 +246,7 @@ public class SortDocumentUiTest extends ActivityTest<FilesActivity> {
bots.directory.assertOrder(DIRS_IN_NAME_ASC, FILES_IN_TYPE_ASC);
}
+ @Test
public void testSortByType_Descending_gridMode() throws Exception {
initFiles();