Merge "Migrate FlickerPiPTests to WmShellFlickerTests."

This commit is contained in:
TreeHugger Robot
2020-10-08 16:53:23 +00:00
committed by Android (Google) Code Review
6 changed files with 340 additions and 1 deletions

View File

@@ -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)
}
}

View File

@@ -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)

View File

@@ -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) }
}
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);
}
}