diff options
Diffstat (limited to 'tests')
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); } } |