diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml index 8b2f6681554a4..967e853b6a48a 100644 --- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml @@ -32,6 +32,8 @@ + + diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt new file mode 100644 index 0000000000000..ef0390fc2a730 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 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.wm.shell.flicker + +import android.content.ComponentName + +const val IME_WINDOW_NAME = "InputMethod" +const val PIP_WINDOW_NAME = "PipMenuActivity" + +// Test App +const val TEST_APP_PACKAGE_NAME = "com.android.wm.shell.flicker.testapp" +// Test App > Pip Activity +val TEST_APP_PIP_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative( + TEST_APP_PACKAGE_NAME, ".PipActivity") +const val TEST_APP_PIP_ACTIVITY_LABEL = "PipApp" +const val TEST_APP_PIP_ACTIVITY_WINDOW_NAME = "PipActivity" +// Test App > Ime Activity +val TEST_APP_IME_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative( + TEST_APP_PACKAGE_NAME, ".ImeActivity") +const val TEST_APP_IME_ACTIVITY_LABEL = "ImeApp" + +const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui" \ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt new file mode 100644 index 0000000000000..e8cf7d978420c --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 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.wm.shell.flicker.helpers + +import android.app.ActivityManager +import android.app.Instrumentation +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager.FEATURE_LEANBACK +import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY +import android.support.test.launcherhelper.LauncherStrategyFactory +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.Until +import com.android.server.wm.flicker.helpers.StandardAppHelper +import com.android.wm.shell.flicker.TEST_APP_PACKAGE_NAME + +abstract class BaseAppHelper( + instrumentation: Instrumentation, + launcherName: String, + private val launcherActivityComponent: ComponentName +) : StandardAppHelper( + instrumentation, + TEST_APP_PACKAGE_NAME, + launcherName, + LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy +) { + protected val uiDevice: UiDevice = UiDevice.getInstance(instrumentation) + + private val context: Context + get() = mInstrumentation.context + + private val activityManager: ActivityManager? + get() = context.getSystemService(ActivityManager::class.java) + + private val appSelector = By.pkg(packageName).depth(0) + + protected val isTelevision: Boolean + get() = context.packageManager.run { + hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY) + } + + val label: String + get() = context.packageManager.run { + getApplicationLabel(getApplicationInfo(packageName, 0)).toString() + } + + fun launchViaIntent() { + context.startActivity(openAppIntent) + + uiDevice.wait(Until.hasObject(appSelector), APP_LAUNCH_WAIT_TIME_MS) + } + + fun forceStop() = activityManager?.forceStopPackage(packageName) + + override fun getOpenAppIntent(): Intent { + val intent = Intent() + intent.component = launcherActivityComponent + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + return intent + } + + companion object { + private const val APP_LAUNCH_WAIT_TIME_MS = 10_000L + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt deleted file mode 100644 index 47a62ce92d11a..0000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2020 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.wm.shell.flicker.helpers - -import android.app.Instrumentation -import android.support.test.launcherhelper.ILauncherStrategy -import com.android.server.wm.flicker.helpers.StandardAppHelper - -abstract class FlickerAppHelper( - instr: Instrumentation, - launcherName: String, - launcherStrategy: ILauncherStrategy -) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) { - companion object { - var sFlickerPackage = "com.android.wm.shell.flicker.testapp" - } -} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt index 0cedc0a7147ff..a6650d7f13d1f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt @@ -17,37 +17,36 @@ package com.android.wm.shell.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.UiDevice import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.FIND_TIMEOUT import com.android.server.wm.flicker.helpers.waitForIME +import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME +import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_LABEL import org.junit.Assert open class ImeAppHelper( - instr: Instrumentation, - launcherName: String = "ImeApp", - launcherStrategy: ILauncherStrategy = LauncherStrategyFactory - .getInstance(instr) - .launcherStrategy -) : FlickerAppHelper(instr, launcherName, launcherStrategy) { - open fun openIME(device: UiDevice) { - val editText = device.wait( + instrumentation: Instrumentation +) : BaseAppHelper( + instrumentation, + TEST_APP_IME_ACTIVITY_LABEL, + TEST_APP_IME_ACTIVITY_COMPONENT_NAME +) { + fun openIME() { + val editText = uiDevice.wait( Until.findObject(By.res(getPackage(), "plain_text_input")), FIND_TIMEOUT) Assert.assertNotNull("Text field not found, this usually happens when the device " + "was left in an unknown state (e.g. in split screen)", editText) editText.click() - if (!device.waitForIME()) { + if (!uiDevice.waitForIME()) { Assert.fail("IME did not appear") } } - open fun closeIME(device: UiDevice) { - device.pressBack() + fun closeIME() { + uiDevice.pressBack() // Using only the AccessibilityInfo it is not possible to identify if the IME is active - device.waitForIdle(1000) + uiDevice.waitForIdle(1000) } } \ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt index 539170202b8ad..d5efa409e6adf 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt @@ -17,29 +17,56 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.support.test.launcherhelper.ILauncherStrategy -import android.support.test.launcherhelper.LauncherStrategyFactory +import android.os.SystemClock +import android.view.KeyEvent.KEYCODE_WINDOW import androidx.test.uiautomator.By -import androidx.test.uiautomator.UiDevice -import com.android.server.wm.flicker.helpers.hasPipWindow +import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.closePipWindow -import org.junit.Assert +import com.android.server.wm.flicker.helpers.hasPipWindow +import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME +import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_COMPONENT_NAME +import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_LABEL +import org.junit.Assert.assertNotNull class PipAppHelper( - instr: Instrumentation, - launcherStrategy: ILauncherStrategy = LauncherStrategyFactory - .getInstance(instr) - .launcherStrategy -) : FlickerAppHelper(instr, "PipApp", launcherStrategy) { - fun clickEnterPipButton(device: UiDevice) { - val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip")) - Assert.assertNotNull("Pip button not found, this usually happens when the device " + + instrumentation: Instrumentation +) : BaseAppHelper( + instrumentation, + TEST_APP_PIP_ACTIVITY_LABEL, + TEST_APP_PIP_ACTIVITY_COMPONENT_NAME +) { + fun clickEnterPipButton() { + val enterPipButton = uiDevice.findObject(By.res(packageName, "enter_pip")) + assertNotNull("Pip button not found, this usually happens when the device " + "was left in an unknown state (e.g. in split screen)", enterPipButton) enterPipButton.click() - device.hasPipWindow() + + // TODO(b/172321238): remove this check once hasPipWindow is fixed on TVs + if (!isTelevision) { + uiDevice.hasPipWindow() + } else { + // Simply wait for 3 seconds + SystemClock.sleep(3_000) + } } - fun closePipWindow(device: UiDevice) { - device.closePipWindow() + fun closePipWindow() { + // TODO(b/172321238): remove this check once and simply call closePipWindow once the TV + // logic is integrated there. + if (!isTelevision) { + uiDevice.closePipWindow() + } else { + // Bring up Pip menu + uiDevice.pressKeyCode(KEYCODE_WINDOW) + + // Wait for the menu to come up and render the close button + val closeButton = uiDevice.wait( + Until.findObject(By.res(SYSTEM_UI_PACKAGE_NAME, "close_button")), 3_000) + assertNotNull("Pip menu close button is not found", closeButton) + closeButton.click() + + // Give it 1 second, just in case + SystemClock.sleep(1_000) + } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt index 010aa0d7d8327..a1da7c939f602 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt @@ -31,6 +31,7 @@ import com.android.wm.shell.flicker.noUncoveredRegions import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible import com.android.wm.shell.flicker.statusBarLayerRotatesScales import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.PIP_WINDOW_NAME import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -79,7 +80,7 @@ class EnterPipTest( } } transitions { - testApp.clickEnterPipButton(device) + testApp.clickEnterPipButton() device.expandPipWindow() } assertions { @@ -89,7 +90,7 @@ class EnterPipTest( all("pipWindowBecomesVisible") { this.showsAppWindow(testApp.`package`) .then() - .showsAppWindow(sPipWindowTitle) + .showsAppWindow(PIP_WINDOW_NAME) } } @@ -103,7 +104,7 @@ class EnterPipTest( all("pipLayerBecomesVisible") { this.showsLayer(testApp.launcherName) .then() - .showsLayer(sPipWindowTitle) + .showsLayer(PIP_WINDOW_NAME) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt index 43e0225386855..d343f2a7093ba 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt @@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.pip import android.content.ComponentName import android.graphics.Region -import android.support.test.launcherhelper.LauncherStrategyFactory import android.util.Log import android.view.Surface import android.view.WindowManager @@ -29,6 +28,9 @@ import com.android.server.wm.flicker.dsl.runWithFlicker import com.android.server.wm.flicker.helpers.closePipWindow import com.android.server.wm.flicker.helpers.hasPipWindow import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME +import com.android.wm.shell.flicker.IME_WINDOW_NAME +import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_WINDOW_NAME import com.android.wm.shell.flicker.helpers.ImeAppHelper import org.junit.FixMethodOrder import org.junit.Test @@ -51,19 +53,11 @@ class PipKeyboardTest( private val windowManager: WindowManager = instrumentation.context.getSystemService(WindowManager::class.java) - private val keyboardApp = ImeAppHelper(instrumentation, "ImeApp", - LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy) - - private val KEYBOARD_ACTIVITY: ComponentName = ComponentName.createRelative( - "com.android.wm.shell.flicker.testapp", ".ImeActivity") - private val PIP_ACTIVITY_WINDOW_NAME = "PipActivity" - private val INPUT_METHOD_WINDOW_NAME = "InputMethod" - - private val testRepetitions = 10 + private val keyboardApp = ImeAppHelper(instrumentation) private val keyboardScenario: FlickerBuilder get() = FlickerBuilder(instrumentation).apply { - repeat { testRepetitions } + repeat { TEST_REPETITIONS } // disable layer tracing withLayerTracing { null } setup { @@ -73,11 +67,11 @@ class PipKeyboardTest( // launch our target pip app testApp.open() this.setRotation(rotation) - testApp.clickEnterPipButton(device) + testApp.clickEnterPipButton() // open an app with an input field and a keyboard // UiAutomator doesn't support to launch the multiple Activities in a task. // So use launchActivity() for the Keyboard Activity. - launchActivity(KEYBOARD_ACTIVITY) + launchActivity(TEST_APP_IME_ACTIVITY_COMPONENT_NAME) } } teardown { @@ -101,10 +95,10 @@ class PipKeyboardTest( withTestName { testTag } transitions { // open the soft keyboard - keyboardApp.openIME(device) + keyboardApp.openIME() // then close it again - keyboardApp.closeIME(device) + keyboardApp.closeIME() } assertions { windowManagerTrace { @@ -127,18 +121,18 @@ class PipKeyboardTest( withTestName { testTag } transitions { // open the soft keyboard - keyboardApp.openIME(device) + keyboardApp.openIME() } teardown { eachRun { // close the keyboard - keyboardApp.closeIME(device) + keyboardApp.closeIME() } } assertions { windowManagerTrace { end { - isAboveWindow(INPUT_METHOD_WINDOW_NAME, PIP_ACTIVITY_WINDOW_NAME) + isAboveWindow(IME_WINDOW_NAME, TEST_APP_PIP_ACTIVITY_WINDOW_NAME) } } } @@ -207,6 +201,8 @@ class PipKeyboardTest( } companion object { + private const val TEST_REPETITIONS = 10 + @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection> { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt index 3822d69a65f50..c1c34ecfbaec5 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt @@ -24,8 +24,4 @@ abstract class PipTestBase( rotation: Int ) : NonRotationTestBase(rotationName, rotation) { protected val testApp = PipAppHelper(instrumentation) - - companion object { - const val sPipWindowTitle = "PipMenuActivity" - } }