summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt46
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt80
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt108
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt14
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt70
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt34
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt129
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt16
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt16
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/Android.bp14
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml52
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/anim/slide_in_from_bottom.xml25
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml31
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml34
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml28
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/assistant_session.xml26
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_content.xml21
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml25
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml37
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml36
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml24
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/xml/interaction_service.xml20
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/xml/recognition_service.xml17
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java18
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionService.java22
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionSession.java53
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionSessionService.java28
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantRecognitionService.java37
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java77
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java16
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java31
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java134
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.java36
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java49
-rw-r--r--tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java2
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt1
-rw-r--r--tests/WindowInsetsTests/res/layout/controller_activity.xml2
-rw-r--r--tests/WindowInsetsTests/res/values/strings.xml2
-rw-r--r--tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java46
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java13
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java10
-rw-r--r--tests/testables/src/android/testing/TestableContext.java82
-rw-r--r--tests/testables/src/android/testing/TestableLooper.java44
-rw-r--r--tests/testables/src/android/testing/TestableSettingsProvider.java11
-rw-r--r--tests/testables/tests/src/android/testing/TestableLooperTest.java65
-rw-r--r--tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java47
47 files changed, 1639 insertions, 94 deletions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 7f309e1974e1..315c40ffa9ba 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -18,10 +18,13 @@
package com.android.server.wm.flicker
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.traces.region.RegionSubject
import com.android.server.wm.traces.common.FlickerComponentName
-val LAUNCHER_COMPONENT = FlickerComponentName("com.google.android.apps.nexuslauncher",
- "com.google.android.apps.nexuslauncher.NexusLauncherActivity")
+val LAUNCHER_COMPONENT = FlickerComponentName(
+ "com.google.android.apps.nexuslauncher",
+ "com.google.android.apps.nexuslauncher.NexusLauncherActivity"
+)
/**
* Checks that [FlickerComponentName.STATUS_BAR] window is visible and above the app windows in
@@ -109,9 +112,9 @@ fun FlickerTestParameter.statusBarLayerIsVisible() {
fun FlickerTestParameter.navBarLayerPositionStart() {
assertLayersStart {
val display = this.entry.displays.minByOrNull { it.id }
- ?: throw RuntimeException("There is no display!")
+ ?: throw RuntimeException("There is no display!")
this.visibleRegion(FlickerComponentName.NAV_BAR)
- .coversExactly(WindowUtils.getNavigationBarPosition(display))
+ .coversExactly(WindowUtils.getNavigationBarPosition(display, isGesturalNavigation))
}
}
@@ -122,9 +125,9 @@ fun FlickerTestParameter.navBarLayerPositionStart() {
fun FlickerTestParameter.navBarLayerPositionEnd() {
assertLayersEnd {
val display = this.entry.displays.minByOrNull { it.id }
- ?: throw RuntimeException("There is no display!")
+ ?: throw RuntimeException("There is no display!")
this.visibleRegion(FlickerComponentName.NAV_BAR)
- .coversExactly(WindowUtils.getNavigationBarPosition(display))
+ .coversExactly(WindowUtils.getNavigationBarPosition(display, isGesturalNavigation))
}
}
@@ -173,6 +176,33 @@ fun FlickerTestParameter.statusBarLayerRotatesScales() {
}
/**
+ * Asserts that the visibleRegion of the [FlickerComponentName.SNAPSHOT] layer can cover
+ * the visibleRegion of the given app component exactly
+ */
+fun FlickerTestParameter.snapshotStartingWindowLayerCoversExactlyOnApp(
+ component: FlickerComponentName) {
+ assertLayers {
+ invoke("snapshotStartingWindowLayerCoversExactlyOnApp") {
+ val snapshotLayers = it.subjects.filter { subject ->
+ subject.name.contains(
+ FlickerComponentName.SNAPSHOT.toLayerName()) && subject.isVisible
+ }
+ // Verify the size of snapshotRegion covers appVisibleRegion exactly in animation.
+ if (snapshotLayers.isNotEmpty()) {
+ val visibleAreas = snapshotLayers.mapNotNull { snapshotLayer ->
+ snapshotLayer.layer?.visibleRegion
+ }.toTypedArray()
+ val snapshotRegion = RegionSubject.assertThat(visibleAreas, this, timestamp)
+ val appVisibleRegion = it.visibleRegion(component)
+ if (snapshotRegion.region.isNotEmpty) {
+ snapshotRegion.coversExactly(appVisibleRegion.region)
+ }
+ }
+ }
+ }
+}
+
+/**
* Asserts that:
* [originalLayer] is visible at the start of the trace
* [originalLayer] becomes invisible during the trace and (in the same entry) [newLayer]
@@ -216,11 +246,11 @@ fun FlickerTestParameter.replacesLayer(
assertLayersStart {
this.isVisible(originalLayer)
- .isInvisible(newLayer)
+ .isInvisible(newLayer)
}
assertLayersEnd {
this.isInvisible(originalLayer)
- .isVisible(newLayer)
+ .isVisible(newLayer)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
new file mode 100644
index 000000000000..efb92f208bde
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.provider.Settings
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.Assert.assertNotNull
+
+class AssistantAppHelper @JvmOverloads constructor(
+ val instr: Instrumentation,
+ val component: ComponentName = ActivityOptions.ASSISTANT_SERVICE_COMPONENT_NAME,
+) {
+ protected val uiDevice: UiDevice = UiDevice.getInstance(instr)
+ protected val defaultAssistant: String? = Settings.Secure.getString(
+ instr.targetContext.contentResolver,
+ Settings.Secure.ASSISTANT)
+ protected val defaultVoiceInteractionService: String? = Settings.Secure.getString(
+ instr.targetContext.contentResolver,
+ Settings.Secure.VOICE_INTERACTION_SERVICE)
+
+ fun setDefaultAssistant() {
+ Settings.Secure.putString(
+ instr.targetContext.contentResolver,
+ Settings.Secure.VOICE_INTERACTION_SERVICE,
+ component.flattenToString())
+ Settings.Secure.putString(
+ instr.targetContext.contentResolver,
+ Settings.Secure.ASSISTANT,
+ component.flattenToString())
+ }
+
+ fun resetDefaultAssistant() {
+ Settings.Secure.putString(
+ instr.targetContext.contentResolver,
+ Settings.Secure.VOICE_INTERACTION_SERVICE,
+ defaultVoiceInteractionService)
+ Settings.Secure.putString(
+ instr.targetContext.contentResolver,
+ Settings.Secure.ASSISTANT,
+ defaultAssistant)
+ }
+
+ /**
+ * Open Assistance UI.
+ *
+ * @param longpress open the UI by long pressing power button.
+ * Otherwise open the UI through vioceinteraction shell command directly.
+ */
+ @JvmOverloads
+ fun openUI(longpress: Boolean = false) {
+ if (longpress) {
+ uiDevice.executeShellCommand("input keyevent --longpress KEYCODE_POWER")
+ } else {
+ uiDevice.executeShellCommand("cmd voiceinteraction show")
+ }
+ val ui = uiDevice.wait(
+ Until.findObject(By.res(ActivityOptions.FLICKER_APP_PACKAGE, "vis_frame")),
+ FIND_TIMEOUT)
+ assertNotNull("Can't find Assistant UI after long pressing power button.", ui)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
new file mode 100644
index 000000000000..fa83f227e80d
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 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.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Direction
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class GameAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.GAME_ACTIVITY_LAUNCHER_NAME,
+ component: FlickerComponentName =
+ ActivityOptions.GAME_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
+ launcherStrategy: ILauncherStrategy =
+ LauncherStrategyFactory.getInstance(instr).launcherStrategy,
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+ /**
+ * Swipes down in the mock game app.
+ *
+ * @return true if the swipe operation is successful.
+ */
+ fun swipeDown(): Boolean {
+ val gameView = uiDevice.wait(
+ Until.findObject(By.res(getPackage(), GAME_APP_VIEW_RES)), WAIT_TIME_MS)
+ require(gameView != null) { "Mock game app view not found." }
+
+ val bound = gameView.getVisibleBounds()
+ return uiDevice.swipe(
+ bound.centerX(), bound.top, bound.centerX(), bound.centerY(), SWIPE_STEPS)
+ }
+
+ /**
+ * Switches to a recent app by quick switch gesture. This function can be used in both portrait
+ * and landscape mode.
+ *
+ * @param wmHelper Helper used to get window region.
+ * @param direction UiAutomator Direction enum to indicate the swipe direction.
+ *
+ * @return true if the swipe operation is successful.
+ */
+ fun switchToPreviousAppByQuickSwitchGesture(
+ wmHelper: WindowManagerStateHelper,
+ direction: Direction
+ ): Boolean {
+ val ratioForScreenBottom = 0.99
+ val fullView = wmHelper.getWindowRegion(component)
+ require(!fullView.isEmpty) { "Target $component view not found." }
+
+ val bound = fullView.bounds
+ val targetYPos = bound.bottom * ratioForScreenBottom
+ val endX = when (direction) {
+ Direction.LEFT -> bound.left
+ Direction.RIGHT -> bound.right
+ else -> {
+ throw IllegalStateException("Only left or right direction is allowed.")
+ }
+ }
+ return uiDevice.swipe(
+ bound.centerX(), targetYPos.toInt(), endX, targetYPos.toInt(), SWIPE_STEPS)
+ }
+
+ /**
+ * Waits for view idel with timeout, then checkes the target object whether visible on screen.
+ *
+ * @param packageName The targe application's package name.
+ * @param identifier The resource id of the target object.
+ * @param timeout The timeout duration in milliseconds.
+ *
+ * @return true if the target object exists.
+ */
+ @JvmOverloads
+ fun isTargetObjVisible(
+ packageName: String,
+ identifier: String,
+ timeout: Long = WAIT_TIME_MS
+ ): Boolean {
+ uiDevice.waitForIdle(timeout)
+ return uiDevice.hasObject(By.res(packageName, identifier))
+ }
+
+ companion object {
+ private const val GAME_APP_VIEW_RES = "container"
+ private const val WAIT_TIME_MS = 3_000L
+ private const val SWIPE_STEPS = 30
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
index aacc17a49a24..3361502f2ea0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
@@ -113,4 +113,18 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor(
}
return false
}
+
+ fun toggleFixPortraitOrientation(wmHelper: WindowManagerStateHelper) {
+ val button = uiDevice.wait(Until.findObject(By.res(getPackage(),
+ "toggle_fixed_portrait_btn")), FIND_TIMEOUT)
+ require(button != null) {
+ "Button not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. Screen turned off)"
+ }
+ button.click()
+ mInstrumentation.waitForIdleSync()
+ // Ensure app relaunching transition finish and the IME has shown
+ wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitImeShown()
+ }
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
new file mode 100644
index 000000000000..3385784de8af
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Direction
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.parser.toFlickerComponent
+
+class MailAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.MAIL_ACTIVITY_LAUNCHER_NAME,
+ component: FlickerComponentName =
+ ActivityOptions.MAIL_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+ fun openMail(rowIdx: Int) {
+ val rowSel = By.res(getPackage(), "mail_row_item_text")
+ .textEndsWith(String.format("%04d", rowIdx))
+ var row: UiObject2? = null
+ for (i in 1..1000) {
+ row = uiDevice.wait(Until.findObject(rowSel), SHORT_WAIT_TIME_MS)
+ if (row != null) break
+ scrollDown()
+ }
+ require(row != null) {""}
+ row.click()
+ uiDevice.wait(Until.gone(By.res(getPackage(), MAIL_LIST_RES_ID)), FIND_TIMEOUT)
+ }
+
+ fun scrollDown() {
+ val listView = waitForMailList()
+ listView.scroll(Direction.DOWN, 1.0f)
+ }
+
+ fun waitForMailList(): UiObject2 {
+ var sel = By.res(getPackage(), MAIL_LIST_RES_ID).scrollable(true)
+ val ret = uiDevice.wait(Until.findObject(sel), FIND_TIMEOUT)
+ require(ret != null) {""}
+ return ret
+ }
+
+ companion object {
+ private const val SHORT_WAIT_TIME_MS = 5000L
+ private const val MAIL_LIST_RES_ID = "mail_recycle_view"
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
index 6257484be9bd..2e29b3e314ca 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
@@ -59,7 +59,7 @@ class CloseImeEditorPopupDialogTest(private val testSpec: FlickerTestParameter)
}
transitions {
imeTestApp.dismissDialog(wmHelper)
- instrumentation.uiAutomation.syncInputTransactions()
+ wmHelper.waitImeGone()
}
teardown {
eachRun {
@@ -91,7 +91,7 @@ class CloseImeEditorPopupDialogTest(private val testSpec: FlickerTestParameter)
.then()
.isVisible(FlickerComponentName.IME_SNAPSHOT)
.then()
- .isInvisible(FlickerComponentName.IME_SNAPSHOT)
+ .isInvisible(FlickerComponentName.IME_SNAPSHOT, isOptional = true)
.isInvisible(FlickerComponentName.IME)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
index 78aea1f1fb17..88fb1a220910 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
@@ -17,23 +17,25 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresDevice
import android.view.Surface
import android.view.WindowManagerPolicyConstants
import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarLayerPositionEnd
import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.snapshotStartingWindowLayerCoversExactlyOnApp
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import org.junit.FixMethodOrder
@@ -43,7 +45,8 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
- * Test IME window layer will become visible when switching from the fixed orientation activity.
+ * Test IME window layer will become visible when switching from the fixed orientation activity
+ * (e.g. Launcher activity).
* To run this test: `atest FlickerTests:OpenImeWindowFromFixedOrientationAppTest`
*/
@RequiresDevice
@@ -53,24 +56,31 @@ import org.junit.runners.Parameterized
@Group2
class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val fixedOrientationApp = FixedOrientationAppHelper(instrumentation)
private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+ private val taplInstrumentation = LauncherInstrumentation()
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
+ test {
+ // Launch the activity with expecting IME will be shown.
+ imeTestApp.launchViaIntent(wmHelper)
+ }
eachRun {
- fixedOrientationApp.launchViaIntent(wmHelper)
- this.setRotation(Surface.ROTATION_90)
+ // Swiping out the IME activity to home.
+ taplInstrumentation.goHome()
+ wmHelper.waitForHomeActivityVisible()
}
}
transitions {
+ // Bring the exist IME activity to the front in landscape mode device rotation.
+ setRotation(Surface.ROTATION_90)
imeTestApp.launchViaIntent(wmHelper)
}
teardown {
test {
- fixedOrientationApp.exit(wmHelper)
+ imeTestApp.exit(wmHelper)
}
}
}
@@ -90,7 +100,7 @@ class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTest
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
+ fun navBarLayerRotatesAndScales() = testSpec.navBarLayerPositionEnd()
@FlakyTest(bugId = 206753786)
fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@@ -99,6 +109,12 @@ class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTest
@Test
fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+ @Postsubmit
+ @Test
+ fun snapshotStartingWindowLayerCoversExactlyOnApp() {
+ testSpec.snapshotStartingWindowLayerCoversExactlyOnApp(imeTestApp.component)
+ }
+
companion object {
/**
* Creates the test configurations.
@@ -112,7 +128,7 @@ class OpenImeWindowFromFixedOrientationAppTest(private val testSpec: FlickerTest
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(
repetitions = 3,
- supportedRotations = listOf(Surface.ROTATION_0),
+ supportedRotations = listOf(Surface.ROTATION_90),
supportedNavigationModes = listOf(
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
new file mode 100644
index 000000000000..3b3bce6f39ba
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 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.server.wm.flicker.ime
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.traces.region.RegionSubject
+import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test IME window shown on the app with fixing portrait orientation.
+ * To run this test: `atest FlickerTests:OpenImeWindowToFixedPortraitAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class OpenImeWindowToFixedPortraitAppTest (private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ // Enable letterbox when the app calls setRequestedOrientation
+ device.executeShellCommand("cmd window set-ignore-orientation-request true")
+ }
+ }
+ transitions {
+ testApp.toggleFixPortraitOrientation(wmHelper)
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ device.executeShellCommand("cmd window set-ignore-orientation-request false")
+ }
+ }
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun imeLayerVisibleStart() {
+ testSpec.assertLayersStart {
+ this.isVisible(FlickerComponentName.IME)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun imeLayerExistsEnd() {
+ testSpec.assertLayersEnd {
+ this.isVisible(FlickerComponentName.IME)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun imeLayerVisibleRegionKeepsTheSame() {
+ var imeLayerVisibleRegionBeforeTransition: RegionSubject? = null
+ testSpec.assertLayersStart {
+ imeLayerVisibleRegionBeforeTransition = this.visibleRegion(FlickerComponentName.IME)
+ }
+ testSpec.assertLayersEnd {
+ this.visibleRegion(FlickerComponentName.IME)
+ .coversExactly(imeLayerVisibleRegionBeforeTransition!!.region)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun appWindowWithLetterboxCoversExactlyOnScreen() {
+ val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
+ testSpec.assertLayersEnd {
+ this.visibleRegion(testApp.component, FlickerComponentName.LETTERBOX)
+ .coversExactly(displayBounds)
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_90, Surface.ROTATION_270),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index a8cbc5dc922c..e05312fe8cc5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -18,12 +18,15 @@ package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.RequiresDevice
+import android.platform.test.rule.SettingOverrideRule
+import android.provider.Settings
import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.ClassRule
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -98,5 +101,16 @@ open class OpenAppFromLockNotificationCold(testSpec: FlickerTestParameter)
return com.android.server.wm.flicker.FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(repetitions = 3)
}
+
+ /**
+ * Ensures that posted notifications will be visible on the lockscreen and not
+ * suppressed due to being marked as seen.
+ */
+ @ClassRule
+ @JvmField
+ val disableUnseenNotifFilterRule = SettingOverrideRule(
+ Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
+ /* value= */ "0",
+ )
}
-} \ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index cd8dea012db5..fcec79f4d7f5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -18,6 +18,8 @@ package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.RequiresDevice
+import android.platform.test.rule.SettingOverrideRule
+import android.provider.Settings
import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -25,6 +27,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.ClassRule
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -124,5 +127,16 @@ open class OpenAppFromLockNotificationWarm(testSpec: FlickerTestParameter)
return com.android.server.wm.flicker.FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(repetitions = 3)
}
+
+ /**
+ * Ensures that posted notifications will be visible on the lockscreen and not
+ * suppressed due to being marked as seen.
+ */
+ @ClassRule
+ @JvmField
+ val disableUnseenNotifFilterRule = SettingOverrideRule(
+ Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS,
+ /* value= */ "0",
+ )
}
-} \ No newline at end of file
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 78660c04d8d4..fffe33a019c1 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -24,6 +24,20 @@ package {
android_test {
name: "FlickerTestApp",
srcs: ["**/*.java"],
+ static_libs: [
+ "androidx.annotation_annotation",
+ "androidx.appcompat_appcompat",
+ "androidx-constraintlayout_constraintlayout",
+ "androidx.core_core",
+ "androidx.fragment_fragment",
+ "androidx.recyclerview_recyclerview",
+ "androidx.navigation_navigation-common-ktx",
+ "androidx.navigation_navigation-fragment-ktx",
+ "androidx.navigation_navigation-runtime-ktx",
+ "androidx.navigation_navigation-ui-ktx",
+ "kotlin-stdlib",
+ "kotlinx-coroutines-android",
+ ],
sdk_version: "current",
test_suites: ["device-tests"],
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 43aa4b151548..efd80f252e86 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -45,6 +45,7 @@
android:theme="@style/CutoutShortEdges"
android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
android:windowSoftInputMode="stateVisible"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:label="ImeAppAutoFocus"
android:exported="true">
<intent-filter>
@@ -162,5 +163,56 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name=".MailActivity"
+ android:exported="true"
+ android:label="MailApp"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.MailActivity"
+ android:theme="@style/Theme.AppCompat.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity android:name=".GameActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.GameActivity"
+ android:immersive="true"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:configChanges="screenSize"
+ android:label="GameApp"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <service
+ android:name=".AssistantInteractionSessionService"
+ android:exported="true"
+ android:permission="android.permission.BIND_VOICE_INTERACTION" />
+ <service
+ android:name=".AssistantRecognitionService"
+ android:exported="true"
+ android:label="Test Voice Interaction Service">
+ <intent-filter>
+ <action android:name="android.speech.RecognitionService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data
+ android:name="android.speech"
+ android:resource="@xml/recognition_service" />
+ </service>
+ <service
+ android:name=".AssistantInteractionService"
+ android:exported="true"
+ android:label="Test Voice Interaction Service"
+ android:permission="android.permission.BIND_VOICE_INTERACTION">
+ <intent-filter>
+ <action android:name="android.service.voice.VoiceInteractionService" />
+ </intent-filter>
+ <meta-data
+ android:name="android.voice_interaction"
+ android:resource="@xml/interaction_service" />
+ </service>
</application>
+ <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/anim/slide_in_from_bottom.xml b/tests/FlickerTests/test-apps/flickerapp/res/anim/slide_in_from_bottom.xml
new file mode 100644
index 000000000000..c0165e5c1086
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/anim/slide_in_from_bottom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:shareInterpolator="false">
+ <translate
+ android:duration="500"
+ android:fromYDelta="100%p"
+ android:toYDelta="0%p" />
+</set>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
index baaf7073b3a6..e71fe801e11a 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
@@ -26,14 +26,27 @@
android:layout_width="match_parent"
android:imeOptions="flagNoExtractUi"
android:inputType="text"/>
- <Button
- android:id="@+id/finish_activity_btn"
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Finish activity" />
- <Button
- android:id="@+id/start_dialog_themed_activity_btn"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Start dialog themed activity" />
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/finish_activity_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Finish activity" />
+ <Button
+ android:id="@+id/start_dialog_themed_activity_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Dialog activity" />
+ <ToggleButton
+ android:id="@+id/toggle_fixed_portrait_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textOn="Portrait (On)"
+ android:textOff="Portrait (Off)"
+ />
+ </LinearLayout>
</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml
new file mode 100644
index 000000000000..8a97433ede04
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <fragment
+ android:id="@+id/main_fragment"
+ android:name="androidx.navigation.fragment.NavHostFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:defaultNavHost="true"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:navGraph="@navigation/mail_navigation"></fragment>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
new file mode 100644
index 000000000000..0b4693dec6e1
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/holo_orange_light">
+
+ <SurfaceView
+ android:id="@+id/surface_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/assistant_session.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/assistant_session.xml
new file mode 100644
index 000000000000..eb7f3074ebfb
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/assistant_session.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <FrameLayout
+ android:id="@+id/vis_frame"
+ android:layout_width="match_parent"
+ android:layout_height="300dp"
+ android:layout_gravity="bottom"
+ android:background="#37474F"/>
+</FrameLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_content.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_content.xml
new file mode 100644
index 000000000000..fbbdc5b812ad
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_content.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml
new file mode 100644
index 000000000000..0e30745bdfc9
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/mail_recycle_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml
new file mode 100644
index 000000000000..c39bfb35e9b0
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/list_item_height"
+ android:layout_marginLeft="@dimen/margin_medium"
+ android:layout_marginRight="@dimen/margin_medium">
+ <ImageView
+ android:id="@+id/mail_row_item_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/padding_small"
+ android:paddingEnd="@dimen/padding_small"
+ android:paddingStart="@dimen/padding_small"
+ android:paddingTop="@dimen/padding_small"/>
+ <TextView
+ android:id="@+id/mail_row_item_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingEnd="@dimen/padding_small"
+ android:textSize="@dimen/list_item_text_size" />
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml b/tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml
new file mode 100644
index 000000000000..d12707a7a123
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/mail_navigation"
+ app:startDestination="@id/fragment_mail_list">
+ <fragment
+ android:id="@+id/fragment_mail_list"
+ android:name=".MailListFragment"
+ android:label="Mail List">
+ <action
+ android:id="@+id/action_mail_list_to_mail_content"
+ app:destination="@id/fragment_mail_content"
+ app:enterAnim="@anim/slide_in_from_bottom" />
+ </fragment>
+ <fragment
+ android:id="@+id/fragment_mail_content"
+ android:name=".MailContentFragment"
+ android:label="Mail Content">
+ </fragment>
+</navigation>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml b/tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml
new file mode 100644
index 000000000000..0b0763d7071d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<resources>
+ <dimen name="padding_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="list_item_height">72dp</dimen>
+ <dimen name="list_item_text_size">24dp</dimen>
+ <dimen name="icon_size">64dp</dimen>
+ <dimen name="icon_text_size">36dp</dimen>
+</resources>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/xml/interaction_service.xml b/tests/FlickerTests/test-apps/flickerapp/res/xml/interaction_service.xml
new file mode 100644
index 000000000000..2e661fbd3122
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/xml/interaction_service.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:recognitionService="com.android.server.wm.flicker.testapp.AssistantRecognitionService"
+ android:sessionService="com.android.server.wm.flicker.testapp.AssistantInteractionSessionService"
+ android:supportsAssist="true" />
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/xml/recognition_service.xml b/tests/FlickerTests/test-apps/flickerapp/res/xml/recognition_service.xml
new file mode 100644
index 000000000000..2e124982084f
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/xml/recognition_service.xml
@@ -0,0 +1,17 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<recognition-service xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 6cda482dd30a..e90eed15ecfe 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -80,11 +80,21 @@ public class ActivityOptions {
public static final String SHOW_WHEN_LOCKED_ACTIVITY_LAUNCHER_NAME = "ShowWhenLockedApp";
public static final ComponentName SHOW_WHEN_LOCKED_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".ShowWhenLockedActivity");
+ new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".ShowWhenLockedActivity");
public static final String NOTIFICATION_ACTIVITY_LAUNCHER_NAME = "NotificationApp";
public static final ComponentName NOTIFICATION_ACTIVITY_COMPONENT_NAME =
- new ComponentName(FLICKER_APP_PACKAGE,
- FLICKER_APP_PACKAGE + ".NotificationActivity");
+ new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".NotificationActivity");
+
+ public static final String MAIL_ACTIVITY_LAUNCHER_NAME = "MailActivity";
+ public static final ComponentName MAIL_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".MailActivity");
+
+ public static final String GAME_ACTIVITY_LAUNCHER_NAME = "GameApp";
+ public static final ComponentName GAME_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".GameActivity");
+
+ public static final ComponentName ASSISTANT_SERVICE_COMPONENT_NAME =
+ new ComponentName(
+ FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".AssistantInteractionService");
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionService.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionService.java
new file mode 100644
index 000000000000..d60143cdf40a
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionService.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.testapp;
+
+import android.service.voice.VoiceInteractionService;
+
+public class AssistantInteractionService extends VoiceInteractionService {
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionSession.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionSession.java
new file mode 100644
index 000000000000..d2c9b37704b8
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionSession.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.testapp;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionSession;
+import android.view.View;
+import android.view.Window;
+
+public class AssistantInteractionSession extends VoiceInteractionSession {
+
+ public AssistantInteractionSession(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onCreate() {
+ Window window = getWindow().getWindow();
+ if (window != null) {
+ window.getDecorView().setBackgroundColor(Color.TRANSPARENT);
+
+ }
+ View rootView = getLayoutInflater().inflate(R.layout.assistant_session, null);
+ setContentView(rootView);
+ setUiEnabled(false);
+ }
+
+ @Override
+ public void onShow(Bundle args, int showFlags) {
+ setUiEnabled(true);
+ }
+
+ @Override
+ public void onHide() {
+ setUiEnabled(false);
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionSessionService.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionSessionService.java
new file mode 100644
index 000000000000..4d6125c9a5d8
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantInteractionSessionService.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.testapp;
+
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionSession;
+import android.service.voice.VoiceInteractionSessionService;
+
+public class AssistantInteractionSessionService extends VoiceInteractionSessionService {
+ @Override
+ public VoiceInteractionSession onNewSession(Bundle args) {
+ return new AssistantInteractionSession(this);
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantRecognitionService.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantRecognitionService.java
new file mode 100644
index 000000000000..68aae4520fe9
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/AssistantRecognitionService.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.testapp;
+
+import android.content.Intent;
+import android.speech.RecognitionService;
+
+public class AssistantRecognitionService extends RecognitionService {
+ @Override
+ protected void onStartListening(Intent recognizerIntent, Callback listener) {
+
+ }
+
+ @Override
+ protected void onCancel(Callback listener) {
+
+ }
+
+ @Override
+ protected void onStopListening(Callback listener) {
+
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java
new file mode 100644
index 000000000000..ef75d4ddcdcd
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 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.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.core.view.WindowInsetsControllerCompat;
+
+public class GameActivity extends Activity implements SurfaceHolder.Callback {
+ private SurfaceHolder mSurfaceHolder;
+ private SurfaceView mSurfaceView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_surfaceview);
+
+ mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
+ mSurfaceView.setZOrderOnTop(true);
+ mSurfaceHolder = mSurfaceView.getHolder();
+ mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
+ mSurfaceHolder.addCallback(this);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ hideSystemBars();
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Canvas canvas = holder.lockCanvas();
+ canvas.drawColor(Color.BLUE);
+ holder.unlockCanvasAndPost(canvas);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+
+ private void hideSystemBars() {
+ WindowInsetsControllerCompat windowInsetsController =
+ ViewCompat.getWindowInsetsController(getWindow().getDecorView());
+ if (windowInsetsController == null) {
+ return;
+ }
+ // Configure the behavior of the hidden system bars.
+ windowInsetsController.setSystemBarsBehavior(
+ WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ );
+ // Hide both the status bar and the navigation bar.
+ windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java
index bb200f125507..7ee8debddcf1 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java
@@ -16,21 +16,29 @@
package com.android.server.wm.flicker.testapp;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
import android.content.Intent;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.ToggleButton;
public class ImeActivityAutoFocus extends ImeActivity {
-
@Override
protected void onStart() {
super.onStart();
- EditText editTextField = findViewById(R.id.plain_text_input);
- editTextField.requestFocus();
-
Button startThemedActivityButton = findViewById(R.id.start_dialog_themed_activity_btn);
startThemedActivityButton.setOnClickListener(
button -> startActivity(new Intent(this, DialogThemedActivity.class)));
+
+ ToggleButton toggleFixedPortraitButton = findViewById(R.id.toggle_fixed_portrait_btn);
+ toggleFixedPortraitButton.setOnCheckedChangeListener(
+ (button, isChecked) -> setRequestedOrientation(
+ isChecked ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_UNSPECIFIED));
+
+ EditText editTextField = findViewById(R.id.plain_text_input);
+ editTextField.requestFocus();
}
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java
new file mode 100644
index 000000000000..419d438baf69
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.testapp;
+
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+public class MailActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_mail);
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java
new file mode 100644
index 000000000000..984263acebac
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.testapp;
+
+import static androidx.navigation.fragment.NavHostFragment.findNavController;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.OvalShape;
+import android.graphics.drawable.shapes.Shape;
+import android.util.DisplayMetrics;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.navigation.NavController;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class MailAdapter extends RecyclerView.Adapter<MailAdapter.ViewHolder> {
+
+ private final Fragment mFragment;
+ private final int mSize;
+
+ static class BadgeShape extends OvalShape {
+ Context mContext;
+ String mLabel;
+
+ BadgeShape(Context context, String label) {
+ mContext = context;
+ mLabel = label;
+ }
+
+ @Override
+ public void draw(Canvas canvas, Paint paint) {
+ final Resources resources = mContext.getResources();
+ int textSize = resources.getDimensionPixelSize(R.dimen.icon_text_size);
+ paint.setColor(Color.BLACK);
+ super.draw(canvas, paint);
+ paint.setColor(Color.WHITE);
+ paint.setTextSize(textSize);
+ paint.setTypeface(Typeface.DEFAULT_BOLD);
+ paint.setTextAlign(Paint.Align.CENTER);
+ Paint.FontMetrics fontMetrics = paint.getFontMetrics();
+ float distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
+ canvas.drawText(
+ mLabel,
+ rect().centerX(),
+ rect().centerY() + distance,
+ paint);
+ }
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+
+ NavController mNavController;
+ ImageView mImageView;
+ TextView mTextView;
+ DisplayMetrics mDisplayMetrics;
+
+ ViewHolder(@NonNull View itemView, NavController navController) {
+ super(itemView);
+ mNavController = navController;
+ itemView.setOnClickListener(this::onClick);
+ mImageView = itemView.findViewById(R.id.mail_row_item_icon);
+ mTextView = itemView.findViewById(R.id.mail_row_item_text);
+ mDisplayMetrics = itemView.getContext().getResources().getDisplayMetrics();
+ }
+
+ void onClick(View v) {
+ mNavController.navigate(R.id.action_mail_list_to_mail_content);
+ }
+
+ public void setContent(int i) {
+ final Resources resources = mImageView.getContext().getResources();
+ final int badgeSize = resources.getDimensionPixelSize(R.dimen.icon_size);
+ final char c = (char) ('A' + i % 26);
+ final Shape badge = new BadgeShape(mImageView.getContext(), String.valueOf(c));
+ ShapeDrawable drawable = new ShapeDrawable();
+ drawable.setIntrinsicHeight(badgeSize);
+ drawable.setIntrinsicWidth(badgeSize);
+ drawable.setShape(badge);
+ mImageView.setImageDrawable(drawable);
+ mTextView.setText(String.format("%s-%04d", c, i));
+ }
+ }
+
+ public MailAdapter(Fragment fragment, int size) {
+ super();
+ mFragment = fragment;
+ mSize = size;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ View v = LayoutInflater
+ .from(viewGroup.getContext())
+ .inflate(R.layout.mail_row_item, viewGroup, false);
+ return new ViewHolder(v, findNavController(mFragment));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
+ viewHolder.setContent(i);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mSize;
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.java
new file mode 100644
index 000000000000..278b92e4b353
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.testapp;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+public class MailContentFragment extends Fragment {
+ public MailContentFragment() {
+ super(R.layout.fragment_mail_content);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ view.setBackgroundColor(Color.LTGRAY);
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java
new file mode 100644
index 000000000000..551820c3322b
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.server.wm.flicker.testapp;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class MailListFragment extends Fragment {
+
+ protected RecyclerView mRecyclerView;
+ protected RecyclerView.LayoutManager mLayoutManager;
+ protected MailAdapter mAdapter;
+
+ public MailListFragment() {
+ super(R.layout.fragment_mail_list);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_mail_list, container, false);
+ mRecyclerView = rootView.findViewById(R.id.mail_recycle_view);
+ mAdapter = new MailAdapter(this, 1000);
+ mRecyclerView.setAdapter(mAdapter);
+ mLayoutManager = new LinearLayoutManager(getActivity());
+ mRecyclerView.setLayoutManager(mLayoutManager);
+ return rootView;
+ }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
index 3db011683a86..fdd919412e55 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
@@ -86,7 +86,7 @@ public class ProtoLogImplTest {
mFile = testContext.getFileStreamPath("tracing_test.dat");
//noinspection ResultOfMethodCallIgnored
mFile.delete();
- mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader);
+ mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader, 1024);
}
@After
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index 2031af2cf0c9..1930a1c8bbb2 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -63,6 +63,7 @@ class LockStateTrackingRule : TestRule {
inner class Listener : TrustListener {
override fun onTrustChanged(
enabled: Boolean,
+ newlyUnlocked: Boolean,
userId: Int,
flags: Int,
trustGrantedMessages: MutableList<String>
diff --git a/tests/WindowInsetsTests/res/layout/controller_activity.xml b/tests/WindowInsetsTests/res/layout/controller_activity.xml
index d51a4ddd43e8..5550eab61a33 100644
--- a/tests/WindowInsetsTests/res/layout/controller_activity.xml
+++ b/tests/WindowInsetsTests/res/layout/controller_activity.xml
@@ -88,7 +88,7 @@
<TextView
android:id="@+id/textViewControllableInsets"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp" />
diff --git a/tests/WindowInsetsTests/res/values/strings.xml b/tests/WindowInsetsTests/res/values/strings.xml
index d6355f5a0464..516d4584426e 100644
--- a/tests/WindowInsetsTests/res/values/strings.xml
+++ b/tests/WindowInsetsTests/res/values/strings.xml
@@ -22,7 +22,7 @@
<!-- The item positions should match the flag values respectively. -->
<string-array name="behaviors">
- <item>BEHAVIOR_SHOW_BARS_BY_TOUCH</item>
+ <item>BEHAVIOR_SHOW_BARS_BY_TOUCH (deprecated)</item>
<item>BEHAVIOR_DEFAULT</item>
<item>BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE</item>
</string-array>
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
index 95fd959e5587..e6b60cfbe84f 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
@@ -83,7 +83,51 @@ public class ControllerActivity extends Activity implements View.OnApplyWindowIn
final View contentView = findViewById(R.id.content);
contentView.setOnApplyWindowInsetsListener(this);
contentView.getWindowInsetsController().addOnControllableInsetsChangedListener(
- (c, types) -> mTextControllableInsets.setText("ControllableInsetsTypes=" + types));
+ (c, types) -> mTextControllableInsets.setText(
+ "ControllableInsetsTypes:\n" + insetsTypesToString(types)));
+ }
+
+ private static String insetsTypesToString(int types) {
+ if (types == 0) {
+ return "none";
+ }
+ final StringBuilder sb = new StringBuilder();
+ if ((types & Type.statusBars()) != 0) {
+ types &= ~Type.statusBars();
+ sb.append("statusBars ");
+ }
+ if ((types & Type.navigationBars()) != 0) {
+ types &= ~Type.navigationBars();
+ sb.append("navigationBars ");
+ }
+ if ((types & Type.captionBar()) != 0) {
+ types &= ~Type.captionBar();
+ sb.append("captionBar ");
+ }
+ if ((types & Type.ime()) != 0) {
+ types &= ~Type.ime();
+ sb.append("ime ");
+ }
+ if ((types & Type.systemGestures()) != 0) {
+ types &= ~Type.systemGestures();
+ sb.append("systemGestures ");
+ }
+ if ((types & Type.mandatorySystemGestures()) != 0) {
+ types &= ~Type.mandatorySystemGestures();
+ sb.append("mandatorySystemGestures ");
+ }
+ if ((types & Type.tappableElement()) != 0) {
+ types &= ~Type.tappableElement();
+ sb.append("tappableElement ");
+ }
+ if ((types & Type.displayCutout()) != 0) {
+ types &= ~Type.displayCutout();
+ sb.append("displayCutout ");
+ }
+ if (types != 0) {
+ sb.append("unknownTypes:").append(types);
+ }
+ return sb.toString();
}
@Override
diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
index e0f3f03e9cb7..421ceb797c15 100644
--- a/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
+++ b/tests/permission/src/com/android/framework/permission/tests/VibratorManagerServicePermissionTest.java
@@ -50,6 +50,7 @@ import org.junit.runners.JUnit4;
public class VibratorManagerServicePermissionTest {
private static final String PACKAGE_NAME = "com.android.framework.permission.tests";
+ private static final int DISPLAY_ID = 1;
private static final CombinedVibration EFFECT =
CombinedVibration.createParallel(
VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
@@ -106,7 +107,8 @@ public class VibratorManagerServicePermissionTest {
@Test
public void testVibrateWithoutPermissionFails() throws RemoteException {
expectSecurityException("VIBRATE");
- mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
+ mVibratorService.vibrate(Process.myUid(), DISPLAY_ID, PACKAGE_NAME, EFFECT, ATTRS,
+ "testVibrate",
new Binder());
}
@@ -115,7 +117,8 @@ public class VibratorManagerServicePermissionTest {
throws RemoteException {
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
Manifest.permission.VIBRATE);
- mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
+ mVibratorService.vibrate(Process.myUid(), DISPLAY_ID, PACKAGE_NAME, EFFECT, ATTRS,
+ "testVibrate",
new Binder());
}
@@ -124,7 +127,8 @@ public class VibratorManagerServicePermissionTest {
expectSecurityException("UPDATE_APP_OPS_STATS");
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
Manifest.permission.VIBRATE);
- mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
+ mVibratorService.vibrate(Process.SYSTEM_UID, DISPLAY_ID, "android", EFFECT, ATTRS,
+ "testVibrate",
new Binder());
}
@@ -133,7 +137,8 @@ public class VibratorManagerServicePermissionTest {
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
Manifest.permission.VIBRATE,
Manifest.permission.UPDATE_APP_OPS_STATS);
- mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
+ mVibratorService.vibrate(Process.SYSTEM_UID, DISPLAY_ID, "android", EFFECT, ATTRS,
+ "testVibrate",
new Binder());
}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 1fe13fe97fbe..06cbeb5368a5 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -124,16 +124,6 @@ public class WindowManagerPermissionTests extends TestCase {
@SmallTest
public void testSET_ORIENTATION() {
try {
- mWm.updateRotation(true, false);
- fail("IWindowManager.updateRotation did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
mWm.freezeRotation(-1);
fail("IWindowManager.freezeRotation did not throw SecurityException as"
+ " expected");
diff --git a/tests/testables/src/android/testing/TestableContext.java b/tests/testables/src/android/testing/TestableContext.java
index e2668bc4281f..0f04d6ae1721 100644
--- a/tests/testables/src/android/testing/TestableContext.java
+++ b/tests/testables/src/android/testing/TestableContext.java
@@ -33,11 +33,15 @@ import android.provider.Settings;
import android.util.ArrayMap;
import android.view.LayoutInflater;
+import androidx.annotation.Nullable;
+
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import java.util.ArrayList;
+
/**
* A ContextWrapper with utilities specifically designed to make Testing easier.
*
@@ -61,6 +65,7 @@ public class TestableContext extends ContextWrapper implements TestRule {
private final TestableContentResolver mTestableContentResolver;
private final TestableSettingsProvider mSettingsProvider;
+ private ArrayList<MockServiceResolver> mMockServiceResolvers;
private ArrayMap<String, Object> mMockSystemServices;
private ArrayMap<ComponentName, IBinder> mMockServices;
private ArrayMap<ServiceConnection, ComponentName> mActiveServices;
@@ -214,12 +219,15 @@ public class TestableContext extends ContextWrapper implements TestRule {
/**
* Adds a mock service to be connected to by a bindService call.
* <p>
- * Normally a TestableContext will pass through all bind requests to the base context
- * but when addMockService has been called for a ComponentName being bound, then
- * TestableContext will immediately trigger a {@link ServiceConnection#onServiceConnected}
- * with the specified service, and will call {@link ServiceConnection#onServiceDisconnected}
- * when the service is unbound.
+ * Normally a TestableContext will pass through all bind requests to the base context
+ * but when addMockService has been called for a ComponentName being bound, then
+ * TestableContext will immediately trigger a {@link ServiceConnection#onServiceConnected}
+ * with the specified service, and will call {@link ServiceConnection#onServiceDisconnected}
+ * when the service is unbound.
* </p>
+ *
+ * @see #addMockServiceResolver(MockServiceResolver) for custom resolution of service Intents to
+ * ComponentNames
*/
public void addMockService(ComponentName component, IBinder service) {
if (mMockServices == null) mMockServices = new ArrayMap<>();
@@ -227,12 +235,38 @@ public class TestableContext extends ContextWrapper implements TestRule {
}
/**
+ * Strategy to resolve a service {@link Intent} to a mock service {@link ComponentName}.
+ */
+ public interface MockServiceResolver {
+ @Nullable
+ ComponentName resolve(Intent service);
+ }
+
+ /**
+ * Registers a strategy to resolve service intents to registered mock services.
+ * <p>
+ * The result of the first {@link MockServiceResolver} to return a non-null
+ * {@link ComponentName} is used to look up a mock service. The mock service must be registered
+ * via {@link #addMockService(ComponentName, IBinder)} separately, using the same component
+ * name.
+ *
+ * If none of the resolvers return a non-null value, or the first returned component name
+ * does not link to a registered mock service, the bind requests are passed to the base context
+ *
+ * The resolvers are queried in order of registration.
+ */
+ public void addMockServiceResolver(MockServiceResolver resolver) {
+ if (mMockServiceResolvers == null) mMockServiceResolvers = new ArrayList<>();
+ mMockServiceResolvers.add(resolver);
+ }
+
+ /**
* @see #addMockService(ComponentName, IBinder)
*/
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
- if (checkMocks(service.getComponent(), conn)) return true;
+ if (checkMocks(service, conn)) return true;
return super.bindService(service, conn, flags);
}
@@ -243,7 +277,7 @@ public class TestableContext extends ContextWrapper implements TestRule {
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
Handler handler, UserHandle user) {
if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
- if (checkMocks(service.getComponent(), conn)) return true;
+ if (checkMocks(service, conn)) return true;
return super.bindServiceAsUser(service, conn, flags, handler, user);
}
@@ -254,18 +288,36 @@ public class TestableContext extends ContextWrapper implements TestRule {
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
- if (checkMocks(service.getComponent(), conn)) return true;
+ if (checkMocks(service, conn)) return true;
return super.bindServiceAsUser(service, conn, flags, user);
}
- private boolean checkMocks(ComponentName component, ServiceConnection conn) {
- if (mMockServices != null && component != null && mMockServices.containsKey(component)) {
- if (mActiveServices == null) mActiveServices = new ArrayMap<>();
- mActiveServices.put(conn, component);
- conn.onServiceConnected(component, mMockServices.get(component));
- return true;
+ private boolean checkMocks(Intent service, ServiceConnection conn) {
+ if (mMockServices == null) return false;
+
+ ComponentName serviceComponent = resolveMockServiceComponent(service);
+ if (serviceComponent == null) return false;
+
+ IBinder serviceImpl = mMockServices.get(serviceComponent);
+ if (serviceImpl == null) return false;
+
+ if (mActiveServices == null) mActiveServices = new ArrayMap<>();
+ mActiveServices.put(conn, serviceComponent);
+ conn.onServiceConnected(serviceComponent, serviceImpl);
+ return true;
+ }
+
+ private ComponentName resolveMockServiceComponent(Intent service) {
+ ComponentName specifiedComponentName = service.getComponent();
+ if (specifiedComponentName != null) return specifiedComponentName;
+
+ if (mMockServiceResolvers == null) return null;
+
+ for (MockServiceResolver resolver : mMockServiceResolvers) {
+ ComponentName resolvedComponent = resolver.resolve(service);
+ if (resolvedComponent != null) return resolvedComponent;
}
- return false;
+ return null;
}
/**
diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java
index ebe9b5706bf8..edd6dd3468ef 100644
--- a/tests/testables/src/android/testing/TestableLooper.java
+++ b/tests/testables/src/android/testing/TestableLooper.java
@@ -30,6 +30,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.lang.reflect.Field;
import java.util.Map;
/**
@@ -45,6 +46,9 @@ public class TestableLooper {
* catch crashes.
*/
public static final boolean HOLD_MAIN_THREAD = false;
+ private static final Field MESSAGE_QUEUE_MESSAGES_FIELD;
+ private static final Field MESSAGE_NEXT_FIELD;
+ private static final Field MESSAGE_WHEN_FIELD;
private Looper mLooper;
private MessageQueue mQueue;
@@ -54,6 +58,19 @@ public class TestableLooper {
private Runnable mEmptyMessage;
private TestLooperManager mQueueWrapper;
+ static {
+ try {
+ MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages");
+ MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true);
+ MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next");
+ MESSAGE_NEXT_FIELD.setAccessible(true);
+ MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when");
+ MESSAGE_WHEN_FIELD.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException("Failed to initialize TestableLooper", e);
+ }
+ }
+
public TestableLooper(Looper l) throws Exception {
this(acquireLooperManager(l), l);
}
@@ -119,6 +136,33 @@ public class TestableLooper {
while (processQueuedMessages() != 0) ;
}
+ public void moveTimeForward(long milliSeconds) {
+ try {
+ Message msg = getMessageLinkedList();
+ while (msg != null) {
+ long updatedWhen = msg.getWhen() - milliSeconds;
+ if (updatedWhen < 0) {
+ updatedWhen = 0;
+ }
+ MESSAGE_WHEN_FIELD.set(msg, updatedWhen);
+ msg = (Message) MESSAGE_NEXT_FIELD.get(msg);
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Access failed in TestableLooper: set - Message.when", e);
+ }
+ }
+
+ private Message getMessageLinkedList() {
+ try {
+ MessageQueue queue = mLooper.getQueue();
+ return (Message) MESSAGE_QUEUE_MESSAGES_FIELD.get(queue);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "Access failed in TestableLooper: get - MessageQueue.mMessages",
+ e);
+ }
+ }
+
private int processQueuedMessages() {
int count = 0;
mEmptyMessage = () -> { };
diff --git a/tests/testables/src/android/testing/TestableSettingsProvider.java b/tests/testables/src/android/testing/TestableSettingsProvider.java
index fd92c657cb2e..c6f18fd453c5 100644
--- a/tests/testables/src/android/testing/TestableSettingsProvider.java
+++ b/tests/testables/src/android/testing/TestableSettingsProvider.java
@@ -49,14 +49,15 @@ public class TestableSettingsProvider extends MockContentProvider {
}
void clearValuesAndCheck(Context context) {
- int userId = UserHandle.myUserId();
- mValues.put(key("global", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
- mValues.put(key("secure", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
- mValues.put(key("system", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
-
+ // Ensure we swapped over to use TestableSettingsProvider
Settings.Global.clearProviderForTest();
Settings.Secure.clearProviderForTest();
Settings.System.clearProviderForTest();
+
+ // putString will eventually invoking the mocked call() method and update mValues
+ Settings.Global.putString(context.getContentResolver(), MY_UNIQUE_KEY, MY_UNIQUE_KEY);
+ Settings.Secure.putString(context.getContentResolver(), MY_UNIQUE_KEY, MY_UNIQUE_KEY);
+ Settings.System.putString(context.getContentResolver(), MY_UNIQUE_KEY, MY_UNIQUE_KEY);
// Verify that if any test is using TestableContext, they all have the correct settings
// provider.
assertEquals("Incorrect settings provider, test using incorrect Context?", MY_UNIQUE_KEY,
diff --git a/tests/testables/tests/src/android/testing/TestableLooperTest.java b/tests/testables/tests/src/android/testing/TestableLooperTest.java
index 25f6a48871d3..0f491b86626c 100644
--- a/tests/testables/tests/src/android/testing/TestableLooperTest.java
+++ b/tests/testables/tests/src/android/testing/TestableLooperTest.java
@@ -19,15 +19,19 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import android.os.Handler;
import android.os.Looper;
@@ -162,7 +166,7 @@ public class TestableLooperTest {
@Test
public void testCorrectLooperExecution() throws Exception {
- boolean[] hasRun = new boolean[] { false };
+ boolean[] hasRun = new boolean[]{false};
Runnable r = () -> {
assertEquals("Should run on main looper", Looper.getMainLooper(), Looper.myLooper());
hasRun[0] = true;
@@ -177,4 +181,63 @@ public class TestableLooperTest {
testableLooper.destroy();
}
}
+
+ @Test
+ public void testDelayedDispatchNoTimeMove() {
+ Handler handler = spy(new Handler(mTestableLooper.getLooper()));
+ InOrder inOrder = inOrder(handler);
+
+ final Message messageA = handler.obtainMessage(1);
+ final Message messageB = handler.obtainMessage(2);
+
+ handler.sendMessageDelayed(messageA, 0);
+ handler.sendMessageDelayed(messageB, 0);
+
+ mTestableLooper.processAllMessages();
+
+ inOrder.verify(handler).dispatchMessage(messageA);
+ inOrder.verify(handler).dispatchMessage(messageB);
+ }
+
+ @Test
+ public void testDelayedMessageDoesntSend() {
+ Handler handler = spy(new Handler(mTestableLooper.getLooper()));
+ InOrder inOrder = inOrder(handler);
+
+ final Message messageA = handler.obtainMessage(1);
+ final Message messageB = handler.obtainMessage(2);
+ final Message messageC = handler.obtainMessage(3);
+
+ handler.sendMessageDelayed(messageA, 0);
+ handler.sendMessageDelayed(messageB, 0);
+ handler.sendMessageDelayed(messageC, 500);
+
+ mTestableLooper.processAllMessages();
+
+ inOrder.verify(handler).dispatchMessage(messageA);
+ inOrder.verify(handler).dispatchMessage(messageB);
+ verify(handler, never()).dispatchMessage(messageC);
+ }
+
+ @Test
+ public void testMessageSendsAfterDelay() {
+ Handler handler = spy(new Handler(mTestableLooper.getLooper()));
+ InOrder inOrder = inOrder(handler);
+
+ final Message messageA = handler.obtainMessage(1);
+ final Message messageB = handler.obtainMessage(2);
+ final Message messageC = handler.obtainMessage(3);
+
+ handler.sendMessageDelayed(messageA, 0);
+ handler.sendMessageDelayed(messageB, 0);
+ handler.sendMessageDelayed(messageC, 500);
+
+ mTestableLooper.moveTimeForward(500);
+ mTestableLooper.processAllMessages();
+
+ inOrder.verify(handler).dispatchMessage(messageA);
+ inOrder.verify(handler).dispatchMessage(messageB);
+ inOrder.verify(handler).dispatchMessage(messageC);
+ }
+
}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
index 3b201f9d20dd..e4add8098105 100644
--- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java
@@ -16,6 +16,9 @@
package android.net.vcn.persistablebundleutils;
+import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION;
+import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES;
+import static android.net.vcn.persistablebundleutils.IkeSessionParamsUtils.isIkeOptionValid;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
import static android.telephony.TelephonyManager.APPTYPE_USIM;
@@ -134,15 +137,37 @@ public class IkeSessionParamsUtilsTest {
verifyPersistableBundleEncodeDecodeIsLossless(params);
}
+ private static IkeSessionParams.Builder createBuilderMinimumWithEap() throws Exception {
+ final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
+
+ final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII);
+ final int subId = 1;
+ final EapSessionConfig eapConfig =
+ new EapSessionConfig.Builder()
+ .setEapIdentity(eapId)
+ .setEapSimConfig(subId, APPTYPE_USIM)
+ .setEapAkaConfig(subId, APPTYPE_USIM)
+ .build();
+ return createBuilderMinimum().setAuthEap(serverCaCert, eapConfig);
+ }
+
@Test
public void testEncodeDecodeParamsWithIkeOptions() throws Exception {
- final IkeSessionParams params =
- createBuilderMinimum()
+ final IkeSessionParams.Builder builder =
+ createBuilderMinimumWithEap()
.addIkeOption(IkeSessionParams.IKE_OPTION_ACCEPT_ANY_REMOTE_ID)
+ .addIkeOption(IkeSessionParams.IKE_OPTION_EAP_ONLY_AUTH)
.addIkeOption(IkeSessionParams.IKE_OPTION_MOBIKE)
+ .addIkeOption(IkeSessionParams.IKE_OPTION_FORCE_PORT_4500)
.addIkeOption(IkeSessionParams.IKE_OPTION_INITIAL_CONTACT)
- .build();
- verifyPersistableBundleEncodeDecodeIsLossless(params);
+ .addIkeOption(IkeSessionParams.IKE_OPTION_REKEY_MOBILITY);
+ if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION)) {
+ builder.addIkeOption(IKE_OPTION_AUTOMATIC_ADDRESS_FAMILY_SELECTION);
+ }
+ if (isIkeOptionValid(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES)) {
+ builder.addIkeOption(IKE_OPTION_AUTOMATIC_NATT_KEEPALIVES);
+ }
+ verifyPersistableBundleEncodeDecodeIsLossless(builder.build());
}
private static InputStream openAssetsFile(String fileName) throws Exception {
@@ -176,19 +201,7 @@ public class IkeSessionParamsUtilsTest {
@Test
public void testEncodeRecodeParamsWithEapAuth() throws Exception {
- final X509Certificate serverCaCert = createCertFromPemFile("self-signed-ca.pem");
-
- final byte[] eapId = "test@android.net".getBytes(StandardCharsets.US_ASCII);
- final int subId = 1;
- final EapSessionConfig eapConfig =
- new EapSessionConfig.Builder()
- .setEapIdentity(eapId)
- .setEapSimConfig(subId, APPTYPE_USIM)
- .setEapAkaConfig(subId, APPTYPE_USIM)
- .build();
-
- final IkeSessionParams params =
- createBuilderMinimum().setAuthEap(serverCaCert, eapConfig).build();
+ final IkeSessionParams params = createBuilderMinimumWithEap().build();
verifyPersistableBundleEncodeDecodeIsLossless(params);
}
}