Merge "Migrate FlickerPiPTests to WmShellFlickerTests."
This commit is contained in:
committed by
Android (Google) Code Review
commit
b64df77f46
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 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 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(
|
||||
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()) {
|
||||
Assert.fail("IME did not appear")
|
||||
}
|
||||
}
|
||||
|
||||
open fun closeIME(device: UiDevice) {
|
||||
device.pressBack()
|
||||
// Using only the AccessibilityInfo it is not possible to identify if the IME is active
|
||||
device.waitForIdle(1000)
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
|
||||
|
||||
/**
|
||||
* Test Pip launch.
|
||||
* To run this test: `atest FlickerTests:PipToAppTest`
|
||||
* To run this test: `atest WMShellFlickerTests:PipToAppTest`
|
||||
*/
|
||||
@RequiresDevice
|
||||
@RunWith(Parameterized::class)
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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.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
|
||||
import androidx.test.filters.RequiresDevice
|
||||
import com.android.compatibility.common.util.SystemUtil
|
||||
import com.android.server.wm.flicker.dsl.FlickerBuilder
|
||||
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.helpers.ImeAppHelper
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.MethodSorters
|
||||
import org.junit.runners.Parameterized
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Test Pip launch.
|
||||
* To run this test: `atest WMShellFlickerTests:PipKeyboardTest`
|
||||
*/
|
||||
@RequiresDevice
|
||||
@RunWith(Parameterized::class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
class PipKeyboardTest(
|
||||
rotationName: String,
|
||||
rotation: Int
|
||||
) : PipTestBase(rotationName, rotation) {
|
||||
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 keyboardScenario: FlickerBuilder
|
||||
get() = FlickerBuilder(instrumentation).apply {
|
||||
repeat { testRepetitions }
|
||||
// disable layer tracing
|
||||
withLayerTracing { null }
|
||||
setup {
|
||||
test {
|
||||
device.wakeUpAndGoToHomeScreen()
|
||||
device.pressHome()
|
||||
// launch our target pip app
|
||||
testApp.open()
|
||||
this.setRotation(rotation)
|
||||
testApp.clickEnterPipButton(device)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
teardown {
|
||||
test {
|
||||
keyboardApp.exit()
|
||||
|
||||
if (device.hasPipWindow()) {
|
||||
device.closePipWindow()
|
||||
}
|
||||
testApp.exit()
|
||||
this.setRotation(Surface.ROTATION_0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Ensure the pip window remains visible throughout any keyboard interactions. */
|
||||
@Test
|
||||
fun pipWindow_doesNotLeaveTheScreen_onKeyboardOpenClose() {
|
||||
val testTag = "pipWindow_doesNotLeaveTheScreen_onKeyboardOpenClose"
|
||||
runWithFlicker(keyboardScenario) {
|
||||
withTestName { testTag }
|
||||
transitions {
|
||||
// open the soft keyboard
|
||||
keyboardApp.openIME(device)
|
||||
|
||||
// then close it again
|
||||
keyboardApp.closeIME(device)
|
||||
}
|
||||
assertions {
|
||||
windowManagerTrace {
|
||||
all("PiP window must remain inside visible bounds") {
|
||||
coversAtMostRegion(
|
||||
partialWindowTitle = "PipActivity",
|
||||
region = Region(windowManager.maximumWindowMetrics.bounds)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Ensure the pip window does not obscure the keyboard. */
|
||||
@Test
|
||||
fun pipWindow_doesNotObscure_keyboard() {
|
||||
val testTag = "pipWindow_doesNotObscure_keyboard"
|
||||
runWithFlicker(keyboardScenario) {
|
||||
withTestName { testTag }
|
||||
transitions {
|
||||
// open the soft keyboard
|
||||
keyboardApp.openIME(device)
|
||||
}
|
||||
teardown {
|
||||
eachRun {
|
||||
// close the keyboard
|
||||
keyboardApp.closeIME(device)
|
||||
}
|
||||
}
|
||||
assertions {
|
||||
windowManagerTrace {
|
||||
end {
|
||||
isAboveWindow(INPUT_METHOD_WINDOW_NAME, PIP_ACTIVITY_WINDOW_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchActivity(
|
||||
activity: ComponentName? = null,
|
||||
action: String? = null,
|
||||
flags: Set<Int> = setOf(),
|
||||
boolExtras: Map<String, Boolean> = mapOf(),
|
||||
intExtras: Map<String, Int> = mapOf(),
|
||||
stringExtras: Map<String, String> = mapOf()
|
||||
) {
|
||||
require(activity != null || !action.isNullOrBlank()) {
|
||||
"Cannot launch an activity with neither activity name nor action!"
|
||||
}
|
||||
val command = composeCommand(
|
||||
"start", activity, action, flags, boolExtras, intExtras, stringExtras)
|
||||
executeShellCommand(command)
|
||||
}
|
||||
|
||||
private fun composeCommand(
|
||||
command: String,
|
||||
activity: ComponentName?,
|
||||
action: String?,
|
||||
flags: Set<Int>,
|
||||
boolExtras: Map<String, Boolean>,
|
||||
intExtras: Map<String, Int>,
|
||||
stringExtras: Map<String, String>
|
||||
): String = buildString {
|
||||
append("am ")
|
||||
append(command)
|
||||
activity?.let {
|
||||
append(" -n ")
|
||||
append(it.flattenToShortString())
|
||||
}
|
||||
action?.let {
|
||||
append(" -a ")
|
||||
append(it)
|
||||
}
|
||||
flags.forEach {
|
||||
append(" -f ")
|
||||
append(it)
|
||||
}
|
||||
boolExtras.forEach {
|
||||
append(it.withFlag("ez"))
|
||||
}
|
||||
intExtras.forEach {
|
||||
append(it.withFlag("ei"))
|
||||
}
|
||||
stringExtras.forEach {
|
||||
append(it.withFlag("es"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun Map.Entry<String, *>.withFlag(flag: String): String = " --$flag $key $value"
|
||||
|
||||
private fun executeShellCommand(cmd: String): String {
|
||||
try {
|
||||
return SystemUtil.runShellCommand(instrumentation, cmd)
|
||||
} catch (e: IOException) {
|
||||
Log.e("FlickerTests", "Error running shell command: $cmd")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
@JvmStatic
|
||||
fun getParams(): Collection<Array<Any>> {
|
||||
val supportedRotations = intArrayOf(Surface.ROTATION_0)
|
||||
return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,5 +33,14 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ImeActivity"
|
||||
android:taskAffinity="com.android.wm.shell.flicker.testapp.ImeActivity"
|
||||
android:label="ImeApp"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusableInTouchMode="true"
|
||||
android:background="@android:color/holo_green_light">
|
||||
<EditText android:id="@+id/plain_text_input"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:inputType="text"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.flicker.testapp;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
|
||||
public class ImeActivity extends Activity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
WindowManager.LayoutParams p = getWindow().getAttributes();
|
||||
p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
|
||||
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||
getWindow().setAttributes(p);
|
||||
setContentView(R.layout.activity_ime);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user