2/ Update app helpers for new apps
Migrate helpers from WMShell app helpers to flicker test packages Test: atest FlickerLibTest && atest FlickerTests Change-Id: I98cd3b850e8b873f09c3df2ac5f079b3209a6b44
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.app.Instrumentation
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import com.android.compatibility.common.util.SystemUtil
|
||||
import java.io.IOException
|
||||
|
||||
object MultiWindowUtils {
|
||||
private fun executeShellCommand(instrumentation: Instrumentation, cmd: String) {
|
||||
try {
|
||||
SystemUtil.runShellCommand(instrumentation, cmd)
|
||||
} catch (e: IOException) {
|
||||
Log.e(MultiWindowUtils::class.simpleName, "executeShellCommand error! $e")
|
||||
}
|
||||
}
|
||||
|
||||
fun getDevEnableNonResizableMultiWindow(context: Context): Int =
|
||||
Settings.Global.getInt(context.contentResolver,
|
||||
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
|
||||
|
||||
fun setDevEnableNonResizableMultiWindow(context: Context, configValue: Int) =
|
||||
Settings.Global.putInt(context.contentResolver,
|
||||
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, configValue)
|
||||
|
||||
fun setSupportsNonResizableMultiWindow(instrumentation: Instrumentation, configValue: Int) =
|
||||
executeShellCommand(
|
||||
instrumentation,
|
||||
createConfigSupportsNonResizableMultiWindowCommand(configValue))
|
||||
|
||||
fun resetMultiWindowConfig(instrumentation: Instrumentation) =
|
||||
executeShellCommand(instrumentation, resetMultiWindowConfigCommand)
|
||||
|
||||
private fun createConfigSupportsNonResizableMultiWindowCommand(configValue: Int): String =
|
||||
"wm set-multi-window-config --supportsNonResizable $configValue"
|
||||
|
||||
private const val resetMultiWindowConfigCommand: String = "wm reset-multi-window-config"
|
||||
}
|
||||
@@ -1,67 +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.content.pm.PackageManager.FEATURE_LEANBACK
|
||||
import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
|
||||
import android.support.test.launcherhelper.LauncherStrategyFactory
|
||||
import android.util.Log
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.UiObject2
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.android.compatibility.common.util.SystemUtil
|
||||
import com.android.server.wm.flicker.helpers.StandardAppHelper
|
||||
import com.android.server.wm.traces.common.IComponentNameMatcher
|
||||
import java.io.IOException
|
||||
|
||||
abstract class BaseAppHelper(
|
||||
instrumentation: Instrumentation,
|
||||
launcherName: String,
|
||||
component: IComponentNameMatcher
|
||||
) : StandardAppHelper(
|
||||
instrumentation,
|
||||
launcherName,
|
||||
component,
|
||||
LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy
|
||||
) {
|
||||
private val appSelector = By.pkg(`package`).depth(0)
|
||||
|
||||
protected val isTelevision: Boolean
|
||||
get() = context.packageManager.run {
|
||||
hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY)
|
||||
}
|
||||
|
||||
val ui: UiObject2?
|
||||
get() = uiDevice.findObject(appSelector)
|
||||
|
||||
fun waitUntilClosed(): Boolean {
|
||||
return uiDevice.wait(Until.gone(appSelector), APP_CLOSE_WAIT_TIME_MS)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val APP_CLOSE_WAIT_TIME_MS = 3_000L
|
||||
|
||||
fun executeShellCommand(instrumentation: Instrumentation, cmd: String) {
|
||||
try {
|
||||
SystemUtil.runShellCommand(instrumentation, cmd)
|
||||
} catch (e: IOException) {
|
||||
Log.e("BaseAppHelper", "executeShellCommand error! $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +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 com.android.server.wm.traces.parser.toFlickerComponent
|
||||
import com.android.wm.shell.flicker.testapp.Components
|
||||
|
||||
class FixedAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
instrumentation,
|
||||
Components.FixedActivity.LABEL,
|
||||
Components.FixedActivity.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
@@ -1,76 +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 androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
|
||||
import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
|
||||
import com.android.wm.shell.flicker.testapp.Components
|
||||
|
||||
open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
instrumentation,
|
||||
Components.ImeActivity.LABEL,
|
||||
Components.ImeActivity.COMPONENT.toFlickerComponent()
|
||||
) {
|
||||
/**
|
||||
* Opens the IME and wait for it to be displayed
|
||||
*
|
||||
* @param wmHelper Helper used to wait for WindowManager states
|
||||
*/
|
||||
open fun openIME(wmHelper: WindowManagerStateHelper) {
|
||||
if (!isTelevision) {
|
||||
val editText = uiDevice.wait(
|
||||
Until.findObject(By.res(getPackage(), "plain_text_input")),
|
||||
FIND_TIMEOUT)
|
||||
|
||||
require(editText != null) {
|
||||
"Text field not found, this usually happens when the device " +
|
||||
"was left in an unknown state (e.g. in split screen)"
|
||||
}
|
||||
editText.click()
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withImeShown()
|
||||
.waitForAndVerify()
|
||||
} else {
|
||||
// If we do the same thing as above - editText.click() - on TV, that's going to force TV
|
||||
// into the touch mode. We really don't want that.
|
||||
launchViaIntent(action = Components.ImeActivity.ACTION_OPEN_IME)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the IME and wait for it to be gone
|
||||
*
|
||||
* @param wmHelper Helper used to wait for WindowManager states
|
||||
*/
|
||||
open fun closeIME(wmHelper: WindowManagerStateHelper) {
|
||||
if (!isTelevision) {
|
||||
uiDevice.pressBack()
|
||||
// Using only the AccessibilityInfo it is not possible to identify if the IME is active
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withImeGone()
|
||||
.waitForAndVerify()
|
||||
} else {
|
||||
// While pressing the back button should close the IME on TV as well, it may also lead
|
||||
// to the app closing. So let's instead just ask the app to close the IME.
|
||||
launchViaIntent(action = Components.ImeActivity.ACTION_CLOSE_IME)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.wm.shell.flicker.helpers
|
||||
|
||||
import android.app.Instrumentation
|
||||
import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
import com.android.wm.shell.flicker.testapp.Components
|
||||
|
||||
class LaunchBubbleHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
instrumentation,
|
||||
Components.LaunchBubbleActivity.LABEL,
|
||||
Components.LaunchBubbleActivity.COMPONENT.toFlickerComponent()
|
||||
) {
|
||||
|
||||
companion object {
|
||||
const val TIMEOUT_MS = 3_000L
|
||||
}
|
||||
}
|
||||
@@ -1,354 +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.graphics.Point
|
||||
import android.os.SystemClock
|
||||
import android.view.InputDevice
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewConfiguration
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.BySelector
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation
|
||||
import com.android.server.wm.traces.common.IComponentMatcher
|
||||
import com.android.server.wm.traces.common.IComponentNameMatcher
|
||||
import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
|
||||
import com.android.wm.shell.flicker.SPLIT_DECOR_MANAGER
|
||||
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
|
||||
import com.android.wm.shell.flicker.testapp.Components
|
||||
|
||||
class SplitScreenHelper(
|
||||
instrumentation: Instrumentation,
|
||||
activityLabel: String,
|
||||
componentInfo: IComponentNameMatcher
|
||||
) : BaseAppHelper(instrumentation, activityLabel, componentInfo) {
|
||||
|
||||
companion object {
|
||||
const val TIMEOUT_MS = 3_000L
|
||||
const val DRAG_DURATION_MS = 1_000L
|
||||
const val NOTIFICATION_SCROLLER = "notification_stack_scroller"
|
||||
const val DIVIDER_BAR = "docked_divider_handle"
|
||||
const val GESTURE_STEP_MS = 16L
|
||||
const val LONG_PRESS_TIME_MS = 100L
|
||||
|
||||
private val notificationScrollerSelector: BySelector
|
||||
get() = By.res(SYSTEM_UI_PACKAGE_NAME, NOTIFICATION_SCROLLER)
|
||||
private val notificationContentSelector: BySelector
|
||||
get() = By.text("Notification content")
|
||||
private val dividerBarSelector: BySelector
|
||||
get() = By.res(SYSTEM_UI_PACKAGE_NAME, DIVIDER_BAR)
|
||||
|
||||
fun getPrimary(instrumentation: Instrumentation): SplitScreenHelper =
|
||||
SplitScreenHelper(
|
||||
instrumentation,
|
||||
Components.SplitScreenActivity.LABEL,
|
||||
Components.SplitScreenActivity.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
|
||||
fun getSecondary(instrumentation: Instrumentation): SplitScreenHelper =
|
||||
SplitScreenHelper(
|
||||
instrumentation,
|
||||
Components.SplitScreenSecondaryActivity.LABEL,
|
||||
Components.SplitScreenSecondaryActivity.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
|
||||
fun getNonResizeable(instrumentation: Instrumentation): SplitScreenHelper =
|
||||
SplitScreenHelper(
|
||||
instrumentation,
|
||||
Components.NonResizeableActivity.LABEL,
|
||||
Components.NonResizeableActivity.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
|
||||
fun getSendNotification(instrumentation: Instrumentation): SplitScreenHelper =
|
||||
SplitScreenHelper(
|
||||
instrumentation,
|
||||
Components.SendNotificationActivity.LABEL,
|
||||
Components.SendNotificationActivity.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
|
||||
fun getIme(instrumentation: Instrumentation): SplitScreenHelper =
|
||||
SplitScreenHelper(
|
||||
instrumentation,
|
||||
Components.ImeActivity.LABEL,
|
||||
Components.ImeActivity.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
|
||||
fun waitForSplitComplete(
|
||||
wmHelper: WindowManagerStateHelper,
|
||||
primaryApp: IComponentMatcher,
|
||||
secondaryApp: IComponentMatcher,
|
||||
) {
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withWindowSurfaceAppeared(primaryApp)
|
||||
.withWindowSurfaceAppeared(secondaryApp)
|
||||
.withSplitDividerVisible()
|
||||
.waitForAndVerify()
|
||||
}
|
||||
|
||||
fun enterSplit(
|
||||
wmHelper: WindowManagerStateHelper,
|
||||
tapl: LauncherInstrumentation,
|
||||
primaryApp: SplitScreenHelper,
|
||||
secondaryApp: SplitScreenHelper
|
||||
) {
|
||||
tapl.workspace.switchToOverview().dismissAllTasks()
|
||||
primaryApp.launchViaIntent(wmHelper)
|
||||
secondaryApp.launchViaIntent(wmHelper)
|
||||
tapl.goHome()
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withHomeActivityVisible()
|
||||
.waitForAndVerify()
|
||||
splitFromOverview(tapl)
|
||||
waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
|
||||
}
|
||||
|
||||
fun splitFromOverview(tapl: LauncherInstrumentation) {
|
||||
// Note: The initial split position in landscape is different between tablet and phone.
|
||||
// In landscape, tablet will let the first app split to right side, and phone will
|
||||
// split to left side.
|
||||
if (tapl.isTablet) {
|
||||
tapl.workspace.switchToOverview().overviewActions
|
||||
.clickSplit()
|
||||
.currentTask
|
||||
.open()
|
||||
} else {
|
||||
tapl.workspace.switchToOverview().currentTask
|
||||
.tapMenu()
|
||||
.tapSplitMenuItem()
|
||||
.currentTask
|
||||
.open()
|
||||
}
|
||||
SystemClock.sleep(TIMEOUT_MS)
|
||||
}
|
||||
|
||||
fun dragFromNotificationToSplit(
|
||||
instrumentation: Instrumentation,
|
||||
device: UiDevice,
|
||||
wmHelper: WindowManagerStateHelper
|
||||
) {
|
||||
val displayBounds = wmHelper.currentState.layerState
|
||||
.displays.firstOrNull { !it.isVirtual }
|
||||
?.layerStackSpace
|
||||
?: error("Display not found")
|
||||
|
||||
// Pull down the notifications
|
||||
device.swipe(
|
||||
displayBounds.centerX(), 5,
|
||||
displayBounds.centerX(), displayBounds.bottom, 20 /* steps */
|
||||
)
|
||||
SystemClock.sleep(TIMEOUT_MS)
|
||||
|
||||
// Find the target notification
|
||||
val notificationScroller = device.wait(
|
||||
Until.findObject(notificationScrollerSelector), TIMEOUT_MS
|
||||
)
|
||||
var notificationContent = notificationScroller.findObject(notificationContentSelector)
|
||||
|
||||
while (notificationContent == null) {
|
||||
device.swipe(
|
||||
displayBounds.centerX(), displayBounds.centerY(),
|
||||
displayBounds.centerX(), displayBounds.centerY() - 150, 20 /* steps */
|
||||
)
|
||||
notificationContent = notificationScroller.findObject(notificationContentSelector)
|
||||
}
|
||||
|
||||
// Drag to split
|
||||
val dragStart = notificationContent.visibleCenter
|
||||
val dragMiddle = Point(dragStart.x + 50, dragStart.y)
|
||||
val dragEnd = Point(displayBounds.width / 4, displayBounds.width / 4)
|
||||
val downTime = SystemClock.uptimeMillis()
|
||||
|
||||
touch(
|
||||
instrumentation, MotionEvent.ACTION_DOWN, downTime, downTime,
|
||||
TIMEOUT_MS, dragStart
|
||||
)
|
||||
// It needs a horizontal movement to trigger the drag
|
||||
touchMove(
|
||||
instrumentation, downTime, SystemClock.uptimeMillis(),
|
||||
DRAG_DURATION_MS, dragStart, dragMiddle
|
||||
)
|
||||
touchMove(
|
||||
instrumentation, downTime, SystemClock.uptimeMillis(),
|
||||
DRAG_DURATION_MS, dragMiddle, dragEnd
|
||||
)
|
||||
// Wait for a while to start splitting
|
||||
SystemClock.sleep(TIMEOUT_MS)
|
||||
touch(
|
||||
instrumentation, MotionEvent.ACTION_UP, downTime, SystemClock.uptimeMillis(),
|
||||
GESTURE_STEP_MS, dragEnd
|
||||
)
|
||||
SystemClock.sleep(TIMEOUT_MS)
|
||||
}
|
||||
|
||||
fun touch(
|
||||
instrumentation: Instrumentation,
|
||||
action: Int,
|
||||
downTime: Long,
|
||||
eventTime: Long,
|
||||
duration: Long,
|
||||
point: Point
|
||||
) {
|
||||
val motionEvent = MotionEvent.obtain(
|
||||
downTime, eventTime, action, point.x.toFloat(), point.y.toFloat(), 0
|
||||
)
|
||||
motionEvent.source = InputDevice.SOURCE_TOUCHSCREEN
|
||||
instrumentation.uiAutomation.injectInputEvent(motionEvent, true)
|
||||
motionEvent.recycle()
|
||||
SystemClock.sleep(duration)
|
||||
}
|
||||
|
||||
fun touchMove(
|
||||
instrumentation: Instrumentation,
|
||||
downTime: Long,
|
||||
eventTime: Long,
|
||||
duration: Long,
|
||||
from: Point,
|
||||
to: Point
|
||||
) {
|
||||
val steps: Long = duration / GESTURE_STEP_MS
|
||||
var currentTime = eventTime
|
||||
var currentX = from.x.toFloat()
|
||||
var currentY = from.y.toFloat()
|
||||
val stepX = (to.x.toFloat() - from.x.toFloat()) / steps.toFloat()
|
||||
val stepY = (to.y.toFloat() - from.y.toFloat()) / steps.toFloat()
|
||||
|
||||
for (i in 1..steps) {
|
||||
val motionMove = MotionEvent.obtain(
|
||||
downTime, currentTime, MotionEvent.ACTION_MOVE, currentX, currentY, 0
|
||||
)
|
||||
motionMove.source = InputDevice.SOURCE_TOUCHSCREEN
|
||||
instrumentation.uiAutomation.injectInputEvent(motionMove, true)
|
||||
motionMove.recycle()
|
||||
|
||||
currentTime += GESTURE_STEP_MS
|
||||
if (i == steps - 1) {
|
||||
currentX = to.x.toFloat()
|
||||
currentY = to.y.toFloat()
|
||||
} else {
|
||||
currentX += stepX
|
||||
currentY += stepY
|
||||
}
|
||||
SystemClock.sleep(GESTURE_STEP_MS)
|
||||
}
|
||||
}
|
||||
|
||||
fun longPress(
|
||||
instrumentation: Instrumentation,
|
||||
point: Point
|
||||
) {
|
||||
val downTime = SystemClock.uptimeMillis()
|
||||
touch(instrumentation, MotionEvent.ACTION_DOWN, downTime, downTime, TIMEOUT_MS, point)
|
||||
SystemClock.sleep(LONG_PRESS_TIME_MS)
|
||||
touch(instrumentation, MotionEvent.ACTION_UP, downTime, downTime, TIMEOUT_MS, point)
|
||||
}
|
||||
|
||||
fun createShortcutOnHotseatIfNotExist(
|
||||
tapl: LauncherInstrumentation,
|
||||
appName: String
|
||||
) {
|
||||
tapl.workspace.deleteAppIcon(tapl.workspace.getHotseatAppIcon(0))
|
||||
val allApps = tapl.workspace.switchToAllApps()
|
||||
allApps.freeze()
|
||||
try {
|
||||
allApps.getAppIcon(appName).dragToHotseat(0)
|
||||
} finally {
|
||||
allApps.unfreeze()
|
||||
}
|
||||
}
|
||||
|
||||
fun dragDividerToResizeAndWait(
|
||||
device: UiDevice,
|
||||
wmHelper: WindowManagerStateHelper
|
||||
) {
|
||||
val displayBounds = wmHelper.currentState.layerState
|
||||
.displays.firstOrNull { !it.isVirtual }
|
||||
?.layerStackSpace
|
||||
?: error("Display not found")
|
||||
val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS)
|
||||
dividerBar.drag(Point(displayBounds.width * 1 / 3, displayBounds.height * 2 / 3))
|
||||
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withWindowSurfaceDisappeared(SPLIT_DECOR_MANAGER)
|
||||
.waitForAndVerify()
|
||||
}
|
||||
|
||||
fun dragDividerToDismissSplit(
|
||||
device: UiDevice,
|
||||
wmHelper: WindowManagerStateHelper,
|
||||
dragToRight: Boolean,
|
||||
dragToBottom: Boolean
|
||||
) {
|
||||
val displayBounds = wmHelper.currentState.layerState
|
||||
.displays.firstOrNull { !it.isVirtual }
|
||||
?.layerStackSpace
|
||||
?: error("Display not found")
|
||||
val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS)
|
||||
dividerBar.drag(Point(
|
||||
if (dragToRight) {
|
||||
displayBounds.width * 4 / 5
|
||||
} else {
|
||||
displayBounds.width * 1 / 5
|
||||
},
|
||||
if (dragToBottom) {
|
||||
displayBounds.height * 4 / 5
|
||||
} else {
|
||||
displayBounds.height * 1 / 5
|
||||
}))
|
||||
}
|
||||
|
||||
fun doubleTapDividerToSwitch(device: UiDevice) {
|
||||
val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS)
|
||||
val interval = (ViewConfiguration.getDoubleTapTimeout() +
|
||||
ViewConfiguration.getDoubleTapMinTime()) / 2
|
||||
dividerBar.click()
|
||||
SystemClock.sleep(interval.toLong())
|
||||
dividerBar.click()
|
||||
}
|
||||
|
||||
fun copyContentInSplit(
|
||||
instrumentation: Instrumentation,
|
||||
device: UiDevice,
|
||||
sourceApp: IComponentNameMatcher,
|
||||
destinationApp: IComponentNameMatcher,
|
||||
) {
|
||||
// Copy text from sourceApp
|
||||
val textView = device.wait(Until.findObject(
|
||||
By.res(sourceApp.packageName, "SplitScreenTest")), TIMEOUT_MS)
|
||||
longPress(instrumentation, textView.getVisibleCenter())
|
||||
|
||||
val copyBtn = device.wait(Until.findObject(By.text("Copy")), TIMEOUT_MS)
|
||||
copyBtn.click()
|
||||
|
||||
// Paste text to destinationApp
|
||||
val editText = device.wait(Until.findObject(
|
||||
By.res(destinationApp.packageName, "plain_text_input")), TIMEOUT_MS)
|
||||
longPress(instrumentation, editText.getVisibleCenter())
|
||||
|
||||
val pasteBtn = device.wait(Until.findObject(By.text("Paste")), TIMEOUT_MS)
|
||||
pasteBtn.click()
|
||||
|
||||
// Verify text
|
||||
if (!textView.getText().contentEquals(editText.getText())) {
|
||||
error("Fail to copy content in split")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.tv
|
||||
|
||||
import android.app.Instrumentation
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.BySelector
|
||||
import androidx.test.uiautomator.UiObject2
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.android.server.wm.flicker.helpers.PipAppHelper
|
||||
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
|
||||
|
||||
/**
|
||||
* Helper class for PIP app on AndroidTV
|
||||
*/
|
||||
open class PipAppHelperTv(instrumentation: Instrumentation) : PipAppHelper(instrumentation) {
|
||||
private val appSelector = By.pkg(`package`).depth(0)
|
||||
|
||||
val ui: UiObject2?
|
||||
get() = uiDevice.findObject(appSelector)
|
||||
|
||||
private fun focusOnObject(selector: BySelector): Boolean {
|
||||
// We expect all the focusable UI elements to be arranged in a way so that it is possible
|
||||
// to "cycle" over all them by clicking the D-Pad DOWN button, going back up to "the top"
|
||||
// from "the bottom".
|
||||
repeat(FOCUS_ATTEMPTS) {
|
||||
uiDevice.findObject(selector)?.apply { if (isFocusedOrHasFocusedChild) return true }
|
||||
?: error("The object we try to focus on is gone.")
|
||||
|
||||
uiDevice.pressDPadDown()
|
||||
uiDevice.waitForIdle()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun clickObject(resId: String) {
|
||||
val selector = By.res(`package`, resId)
|
||||
focusOnObject(selector) || error("Could not focus on `$resId` object")
|
||||
uiDevice.pressDPadCenter()
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"Use PipAppHelper.closePipWindow(wmHelper) instead",
|
||||
ReplaceWith("closePipWindow(wmHelper)")
|
||||
)
|
||||
override fun closePipWindow() {
|
||||
uiDevice.closeTvPipWindow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Taps the pip window and dismisses it by clicking on the X button.
|
||||
*/
|
||||
override fun closePipWindow(wmHelper: WindowManagerStateHelper) {
|
||||
uiDevice.closeTvPipWindow()
|
||||
|
||||
// Wait for animation to complete.
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withPipGone()
|
||||
.withHomeActivityVisible()
|
||||
.waitForAndVerify()
|
||||
}
|
||||
|
||||
fun waitUntilClosed(): Boolean {
|
||||
val appSelector = By.pkg(`package`).depth(0)
|
||||
return uiDevice.wait(Until.gone(appSelector), APP_CLOSE_WAIT_TIME_MS)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val FOCUS_ATTEMPTS = 20
|
||||
private const val APP_CLOSE_WAIT_TIME_MS = 3_000L
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* 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.wm.shell.flicker.splitscreen
|
||||
|
||||
import android.app.Instrumentation
|
||||
import android.graphics.Point
|
||||
import android.os.SystemClock
|
||||
import android.view.InputDevice
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewConfiguration
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.BySelector
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation
|
||||
import com.android.server.wm.flicker.helpers.ImeAppHelper
|
||||
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
|
||||
import com.android.server.wm.flicker.helpers.NotificationAppHelper
|
||||
import com.android.server.wm.flicker.helpers.SimpleAppHelper
|
||||
import com.android.server.wm.flicker.helpers.StandardAppHelper
|
||||
import com.android.server.wm.flicker.testapp.ActivityOptions
|
||||
import com.android.server.wm.traces.common.ComponentNameMatcher
|
||||
import com.android.server.wm.traces.common.IComponentMatcher
|
||||
import com.android.server.wm.traces.common.IComponentNameMatcher
|
||||
import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
|
||||
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
|
||||
|
||||
internal object SplitScreenHelper {
|
||||
internal const val TIMEOUT_MS = 3_000L
|
||||
private const val DRAG_DURATION_MS = 1_000L
|
||||
private const val NOTIFICATION_SCROLLER = "notification_stack_scroller"
|
||||
private const val DIVIDER_BAR = "docked_divider_handle"
|
||||
private const val GESTURE_STEP_MS = 16L
|
||||
private const val LONG_PRESS_TIME_MS = 100L
|
||||
private val SPLIT_DECOR_MANAGER = ComponentNameMatcher("", "SplitDecorManager#")
|
||||
|
||||
private val notificationScrollerSelector: BySelector
|
||||
get() = By.res(SYSTEM_UI_PACKAGE_NAME, NOTIFICATION_SCROLLER)
|
||||
private val notificationContentSelector: BySelector
|
||||
get() = By.text("Notification content")
|
||||
private val dividerBarSelector: BySelector
|
||||
get() = By.res(SYSTEM_UI_PACKAGE_NAME, DIVIDER_BAR)
|
||||
|
||||
fun getPrimary(instrumentation: Instrumentation): StandardAppHelper =
|
||||
SimpleAppHelper(
|
||||
instrumentation,
|
||||
ActivityOptions.SplitScreen.Primary.LABEL,
|
||||
ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
|
||||
fun getSecondary(instrumentation: Instrumentation): StandardAppHelper =
|
||||
SimpleAppHelper(
|
||||
instrumentation,
|
||||
ActivityOptions.SplitScreen.Secondary.LABEL,
|
||||
ActivityOptions.SplitScreen.Secondary.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
|
||||
fun getNonResizeable(instrumentation: Instrumentation): NonResizeableAppHelper =
|
||||
NonResizeableAppHelper(instrumentation)
|
||||
|
||||
fun getSendNotification(instrumentation: Instrumentation): NotificationAppHelper =
|
||||
NotificationAppHelper(instrumentation)
|
||||
|
||||
fun getIme(instrumentation: Instrumentation): ImeAppHelper =
|
||||
ImeAppHelper(instrumentation)
|
||||
|
||||
fun waitForSplitComplete(
|
||||
wmHelper: WindowManagerStateHelper,
|
||||
primaryApp: IComponentMatcher,
|
||||
secondaryApp: IComponentMatcher,
|
||||
) {
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withWindowSurfaceAppeared(primaryApp)
|
||||
.withWindowSurfaceAppeared(secondaryApp)
|
||||
.withSplitDividerVisible()
|
||||
.waitForAndVerify()
|
||||
}
|
||||
|
||||
fun enterSplit(
|
||||
wmHelper: WindowManagerStateHelper,
|
||||
tapl: LauncherInstrumentation,
|
||||
primaryApp: StandardAppHelper,
|
||||
secondaryApp: StandardAppHelper
|
||||
) {
|
||||
tapl.workspace.switchToOverview().dismissAllTasks()
|
||||
primaryApp.launchViaIntent(wmHelper)
|
||||
secondaryApp.launchViaIntent(wmHelper)
|
||||
tapl.goHome()
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withHomeActivityVisible()
|
||||
.waitForAndVerify()
|
||||
splitFromOverview(tapl)
|
||||
waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
|
||||
}
|
||||
|
||||
fun splitFromOverview(tapl: LauncherInstrumentation) {
|
||||
// Note: The initial split position in landscape is different between tablet and phone.
|
||||
// In landscape, tablet will let the first app split to right side, and phone will
|
||||
// split to left side.
|
||||
if (tapl.isTablet) {
|
||||
tapl.workspace.switchToOverview().overviewActions
|
||||
.clickSplit()
|
||||
.currentTask
|
||||
.open()
|
||||
} else {
|
||||
tapl.workspace.switchToOverview().currentTask
|
||||
.tapMenu()
|
||||
.tapSplitMenuItem()
|
||||
.currentTask
|
||||
.open()
|
||||
}
|
||||
SystemClock.sleep(TIMEOUT_MS)
|
||||
}
|
||||
|
||||
fun dragFromNotificationToSplit(
|
||||
instrumentation: Instrumentation,
|
||||
device: UiDevice,
|
||||
wmHelper: WindowManagerStateHelper
|
||||
) {
|
||||
val displayBounds = wmHelper.currentState.layerState
|
||||
.displays.firstOrNull { !it.isVirtual }
|
||||
?.layerStackSpace
|
||||
?: error("Display not found")
|
||||
|
||||
// Pull down the notifications
|
||||
device.swipe(
|
||||
displayBounds.centerX(), 5,
|
||||
displayBounds.centerX(), displayBounds.bottom, 20 /* steps */
|
||||
)
|
||||
SystemClock.sleep(TIMEOUT_MS)
|
||||
|
||||
// Find the target notification
|
||||
val notificationScroller = device.wait(
|
||||
Until.findObject(notificationScrollerSelector), TIMEOUT_MS
|
||||
)
|
||||
var notificationContent = notificationScroller.findObject(notificationContentSelector)
|
||||
|
||||
while (notificationContent == null) {
|
||||
device.swipe(
|
||||
displayBounds.centerX(), displayBounds.centerY(),
|
||||
displayBounds.centerX(), displayBounds.centerY() - 150, 20 /* steps */
|
||||
)
|
||||
notificationContent = notificationScroller.findObject(notificationContentSelector)
|
||||
}
|
||||
|
||||
// Drag to split
|
||||
val dragStart = notificationContent.visibleCenter
|
||||
val dragMiddle = Point(dragStart.x + 50, dragStart.y)
|
||||
val dragEnd = Point(displayBounds.width / 4, displayBounds.width / 4)
|
||||
val downTime = SystemClock.uptimeMillis()
|
||||
|
||||
touch(
|
||||
instrumentation, MotionEvent.ACTION_DOWN, downTime, downTime,
|
||||
TIMEOUT_MS, dragStart
|
||||
)
|
||||
// It needs a horizontal movement to trigger the drag
|
||||
touchMove(
|
||||
instrumentation, downTime, SystemClock.uptimeMillis(),
|
||||
DRAG_DURATION_MS, dragStart, dragMiddle
|
||||
)
|
||||
touchMove(
|
||||
instrumentation, downTime, SystemClock.uptimeMillis(),
|
||||
DRAG_DURATION_MS, dragMiddle, dragEnd
|
||||
)
|
||||
// Wait for a while to start splitting
|
||||
SystemClock.sleep(TIMEOUT_MS)
|
||||
touch(
|
||||
instrumentation, MotionEvent.ACTION_UP, downTime, SystemClock.uptimeMillis(),
|
||||
GESTURE_STEP_MS, dragEnd
|
||||
)
|
||||
SystemClock.sleep(TIMEOUT_MS)
|
||||
}
|
||||
|
||||
fun touch(
|
||||
instrumentation: Instrumentation,
|
||||
action: Int,
|
||||
downTime: Long,
|
||||
eventTime: Long,
|
||||
duration: Long,
|
||||
point: Point
|
||||
) {
|
||||
val motionEvent = MotionEvent.obtain(
|
||||
downTime, eventTime, action, point.x.toFloat(), point.y.toFloat(), 0
|
||||
)
|
||||
motionEvent.source = InputDevice.SOURCE_TOUCHSCREEN
|
||||
instrumentation.uiAutomation.injectInputEvent(motionEvent, true)
|
||||
motionEvent.recycle()
|
||||
SystemClock.sleep(duration)
|
||||
}
|
||||
|
||||
fun touchMove(
|
||||
instrumentation: Instrumentation,
|
||||
downTime: Long,
|
||||
eventTime: Long,
|
||||
duration: Long,
|
||||
from: Point,
|
||||
to: Point
|
||||
) {
|
||||
val steps: Long = duration / GESTURE_STEP_MS
|
||||
var currentTime = eventTime
|
||||
var currentX = from.x.toFloat()
|
||||
var currentY = from.y.toFloat()
|
||||
val stepX = (to.x.toFloat() - from.x.toFloat()) / steps.toFloat()
|
||||
val stepY = (to.y.toFloat() - from.y.toFloat()) / steps.toFloat()
|
||||
|
||||
for (i in 1..steps) {
|
||||
val motionMove = MotionEvent.obtain(
|
||||
downTime, currentTime, MotionEvent.ACTION_MOVE, currentX, currentY, 0
|
||||
)
|
||||
motionMove.source = InputDevice.SOURCE_TOUCHSCREEN
|
||||
instrumentation.uiAutomation.injectInputEvent(motionMove, true)
|
||||
motionMove.recycle()
|
||||
|
||||
currentTime += GESTURE_STEP_MS
|
||||
if (i == steps - 1) {
|
||||
currentX = to.x.toFloat()
|
||||
currentY = to.y.toFloat()
|
||||
} else {
|
||||
currentX += stepX
|
||||
currentY += stepY
|
||||
}
|
||||
SystemClock.sleep(GESTURE_STEP_MS)
|
||||
}
|
||||
}
|
||||
|
||||
fun longPress(
|
||||
instrumentation: Instrumentation,
|
||||
point: Point
|
||||
) {
|
||||
val downTime = SystemClock.uptimeMillis()
|
||||
touch(instrumentation, MotionEvent.ACTION_DOWN, downTime, downTime, TIMEOUT_MS, point)
|
||||
SystemClock.sleep(LONG_PRESS_TIME_MS)
|
||||
touch(instrumentation, MotionEvent.ACTION_UP, downTime, downTime, TIMEOUT_MS, point)
|
||||
}
|
||||
|
||||
fun createShortcutOnHotseatIfNotExist(
|
||||
tapl: LauncherInstrumentation,
|
||||
appName: String
|
||||
) {
|
||||
tapl.workspace.deleteAppIcon(tapl.workspace.getHotseatAppIcon(0))
|
||||
val allApps = tapl.workspace.switchToAllApps()
|
||||
allApps.freeze()
|
||||
try {
|
||||
allApps.getAppIcon(appName).dragToHotseat(0)
|
||||
} finally {
|
||||
allApps.unfreeze()
|
||||
}
|
||||
}
|
||||
|
||||
fun dragDividerToResizeAndWait(
|
||||
device: UiDevice,
|
||||
wmHelper: WindowManagerStateHelper
|
||||
) {
|
||||
val displayBounds = wmHelper.currentState.layerState
|
||||
.displays.firstOrNull { !it.isVirtual }
|
||||
?.layerStackSpace
|
||||
?: error("Display not found")
|
||||
val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS)
|
||||
dividerBar.drag(Point(displayBounds.width * 1 / 3, displayBounds.height * 2 / 3))
|
||||
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withWindowSurfaceDisappeared(SPLIT_DECOR_MANAGER)
|
||||
.waitForAndVerify()
|
||||
}
|
||||
|
||||
fun dragDividerToDismissSplit(
|
||||
device: UiDevice,
|
||||
wmHelper: WindowManagerStateHelper,
|
||||
dragToRight: Boolean,
|
||||
dragToBottom: Boolean
|
||||
) {
|
||||
val displayBounds = wmHelper.currentState.layerState
|
||||
.displays.firstOrNull { !it.isVirtual }
|
||||
?.layerStackSpace
|
||||
?: error("Display not found")
|
||||
val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS)
|
||||
dividerBar.drag(Point(
|
||||
if (dragToRight) {
|
||||
displayBounds.width * 4 / 5
|
||||
} else {
|
||||
displayBounds.width * 1 / 5
|
||||
},
|
||||
if (dragToBottom) {
|
||||
displayBounds.height * 4 / 5
|
||||
} else {
|
||||
displayBounds.height * 1 / 5
|
||||
}))
|
||||
}
|
||||
|
||||
fun doubleTapDividerToSwitch(device: UiDevice) {
|
||||
val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS)
|
||||
val interval = (ViewConfiguration.getDoubleTapTimeout() +
|
||||
ViewConfiguration.getDoubleTapMinTime()) / 2
|
||||
dividerBar.click()
|
||||
SystemClock.sleep(interval.toLong())
|
||||
dividerBar.click()
|
||||
}
|
||||
|
||||
fun copyContentInSplit(
|
||||
instrumentation: Instrumentation,
|
||||
device: UiDevice,
|
||||
sourceApp: IComponentNameMatcher,
|
||||
destinationApp: IComponentNameMatcher,
|
||||
) {
|
||||
// Copy text from sourceApp
|
||||
val textView = device.wait(Until.findObject(
|
||||
By.res(sourceApp.packageName, "SplitScreenTest")), TIMEOUT_MS)
|
||||
longPress(instrumentation, textView.visibleCenter)
|
||||
|
||||
val copyBtn = device.wait(Until.findObject(By.text("Copy")), TIMEOUT_MS)
|
||||
copyBtn.click()
|
||||
|
||||
// Paste text to destinationApp
|
||||
val editText = device.wait(Until.findObject(
|
||||
By.res(destinationApp.packageName, "plain_text_input")), TIMEOUT_MS)
|
||||
longPress(instrumentation, editText.visibleCenter)
|
||||
|
||||
val pasteBtn = device.wait(Until.findObject(By.text("Paste")), TIMEOUT_MS)
|
||||
pasteBtn.click()
|
||||
|
||||
// Verify text
|
||||
if (!textView.text.contentEquals(editText.text)) {
|
||||
error("Fail to copy content in split")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,12 +33,12 @@ import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelpe
|
||||
import org.junit.Assume.assumeNotNull
|
||||
|
||||
class ActivityEmbeddingAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.ACTIVITY_EMBEDDING_LAUNCHER_NAME,
|
||||
component: ComponentNameMatcher = MAIN_ACTIVITY_COMPONENT,
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.ActivityEmbedding.MainActivity.LABEL,
|
||||
component: ComponentNameMatcher = MAIN_ACTIVITY_COMPONENT,
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
|
||||
|
||||
/**
|
||||
@@ -47,8 +47,8 @@ class ActivityEmbeddingAppHelper @JvmOverloads constructor(
|
||||
*/
|
||||
fun launchPlaceholderSplit(wmHelper: WindowManagerStateHelper) {
|
||||
val launchButton = uiDevice.wait(
|
||||
Until.findObject(By.res(getPackage(), "launch_placeholder_split_button")),
|
||||
FIND_TIMEOUT)
|
||||
Until.findObject(By.res(getPackage(), "launch_placeholder_split_button")),
|
||||
FIND_TIMEOUT)
|
||||
require(launchButton != null) {
|
||||
"Can't find launch placeholder split button on screen."
|
||||
}
|
||||
@@ -62,14 +62,15 @@ class ActivityEmbeddingAppHelper @JvmOverloads constructor(
|
||||
companion object {
|
||||
private const val TAG = "ActivityEmbeddingAppHelper"
|
||||
|
||||
val MAIN_ACTIVITY_COMPONENT = ActivityOptions
|
||||
.ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
|
||||
val MAIN_ACTIVITY_COMPONENT =
|
||||
ActivityOptions.ActivityEmbedding.MainActivity.COMPONENT.toFlickerComponent()
|
||||
|
||||
val PLACEHOLDER_PRIMARY_COMPONENT = ActivityOptions
|
||||
.ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
|
||||
val PLACEHOLDER_PRIMARY_COMPONENT =
|
||||
ActivityOptions.ActivityEmbedding.PlaceholderPrimaryActivity.COMPONENT
|
||||
.toFlickerComponent()
|
||||
|
||||
val PLACEHOLDER_SECONDARY_COMPONENT = ActivityOptions
|
||||
.ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME
|
||||
val PLACEHOLDER_SECONDARY_COMPONENT =
|
||||
ActivityOptions.ActivityEmbedding.PlaceholderSecondaryActivity.COMPONENT
|
||||
.toFlickerComponent()
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.flicker.helpers
|
||||
package com.android.server.wm.flicker.helpers
|
||||
|
||||
import android.app.Instrumentation
|
||||
import com.android.server.wm.traces.common.ComponentNameMatcher
|
||||
@@ -23,4 +23,4 @@ class AppPairsHelper(
|
||||
instrumentation: Instrumentation,
|
||||
activityLabel: String,
|
||||
component: ComponentNameMatcher
|
||||
) : BaseAppHelper(instrumentation, activityLabel, component)
|
||||
) : StandardAppHelper(instrumentation, activityLabel, component)
|
||||
@@ -24,11 +24,11 @@ import com.android.server.wm.traces.common.ComponentNameMatcher
|
||||
import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
|
||||
class FixedOrientationAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.PORTRAIT_ONLY_ACTIVITY_LAUNCHER_NAME,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.PORTRAIT_ONLY_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.PortraitOnlyActivity.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.PortraitOnlyActivity.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
|
||||
|
||||
@@ -29,9 +29,8 @@ import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelpe
|
||||
|
||||
class GameAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.GAME_ACTIVITY_LAUNCHER_NAME,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.GAME_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherName: String = ActivityOptions.Game.LABEL,
|
||||
component: ComponentNameMatcher = ActivityOptions.Game.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy =
|
||||
LauncherStrategyFactory.getInstance(instr).launcherStrategy,
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
|
||||
|
||||
@@ -32,9 +32,9 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
private val rotation: Int,
|
||||
private val imePackageName: String = IME_PACKAGE,
|
||||
launcherName: String = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.Ime.AutoFocusActivity.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent()
|
||||
ActivityOptions.Ime.AutoFocusActivity.COMPONENT.toFlickerComponent()
|
||||
) : ImeAppHelper(instr, launcherName, component) {
|
||||
override fun openIME(wmHelper: WindowManagerStateHelper) {
|
||||
// do nothing (the app is focused automatically)
|
||||
@@ -62,21 +62,22 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor(
|
||||
|
||||
fun startDialogThemedActivity(wmHelper: WindowManagerStateHelper) {
|
||||
val button = uiDevice.wait(Until.findObject(By.res(getPackage(),
|
||||
"start_dialog_themed_activity_btn")), FIND_TIMEOUT)
|
||||
"start_dialog_themed_activity_btn")), FIND_TIMEOUT)
|
||||
|
||||
requireNotNull(button) {
|
||||
"Button not found, this usually happens when the device " +
|
||||
"was left in an unknown state (e.g. Screen turned off)"
|
||||
"was left in an unknown state (e.g. Screen turned off)"
|
||||
}
|
||||
button.click()
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withFullScreenApp(
|
||||
ActivityOptions.DIALOG_THEMED_ACTIVITY_COMPONENT_NAME.toFlickerComponent())
|
||||
ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent())
|
||||
.waitForAndVerify()
|
||||
}
|
||||
|
||||
fun dismissDialog(wmHelper: WindowManagerStateHelper) {
|
||||
val dialog = uiDevice.wait(
|
||||
Until.findObject(By.text("Dialog for test")), FIND_TIMEOUT)
|
||||
Until.findObject(By.text("Dialog for test")), FIND_TIMEOUT)
|
||||
|
||||
// Pressing back key to dismiss the dialog
|
||||
if (dialog != null) {
|
||||
@@ -86,9 +87,10 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor(
|
||||
.waitForAndVerify()
|
||||
}
|
||||
}
|
||||
|
||||
fun getInsetsVisibleFromDialog(type: Int): Boolean {
|
||||
val insetsVisibilityTextView = uiDevice.wait(
|
||||
Until.findObject(By.res("android:id/text1")), FIND_TIMEOUT)
|
||||
Until.findObject(By.res("android:id/text1")), FIND_TIMEOUT)
|
||||
if (insetsVisibilityTextView != null) {
|
||||
val visibility = insetsVisibilityTextView.text.toString()
|
||||
val matcher = when (type) {
|
||||
|
||||
@@ -28,12 +28,11 @@ import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelpe
|
||||
|
||||
open class ImeAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.IME_ACTIVITY_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.Ime.Default.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.IME_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
ActivityOptions.Ime.Default.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy =
|
||||
LauncherStrategyFactory.getInstance(instr).launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
|
||||
/**
|
||||
* Opens the IME and wait for it to be displayed
|
||||
@@ -73,8 +72,8 @@ open class ImeAppHelper @JvmOverloads constructor(
|
||||
|
||||
open fun finishActivity(wmHelper: WindowManagerStateHelper) {
|
||||
val finishButton = uiDevice.wait(
|
||||
Until.findObject(By.res(getPackage(), "finish_activity_btn")),
|
||||
FIND_TIMEOUT)
|
||||
Until.findObject(By.res(getPackage(), "finish_activity_btn")),
|
||||
FIND_TIMEOUT)
|
||||
requireNotNull(finishButton) {
|
||||
"Finish activity button not found, probably IME activity is not on the screen?"
|
||||
}
|
||||
|
||||
@@ -26,16 +26,16 @@ import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelpe
|
||||
|
||||
class ImeEditorPopupDialogAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.EDITOR_POPUP_DIALOG_ACTIVITY_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.Ime.AutoFocusActivity.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.EDITOR_POPUP_DIALOG_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
|
||||
ActivityOptions.Ime.AutoFocusActivity.COMPONENT.toFlickerComponent()
|
||||
) : ImeAppHelper(instr, launcherName, component) {
|
||||
override fun openIME(wmHelper: WindowManagerStateHelper) {
|
||||
val editText = uiDevice.wait(Until.findObject(By.text("focused editText")), FIND_TIMEOUT)
|
||||
|
||||
require(editText != null) {
|
||||
requireNotNull(editText) {
|
||||
"Text field not found, this usually happens when the device " +
|
||||
"was left in an unknown state (e.g. in split screen)"
|
||||
"was left in an unknown state (e.g. in split screen)"
|
||||
}
|
||||
editText.click()
|
||||
waitIMEShown(wmHelper)
|
||||
@@ -43,7 +43,7 @@ class ImeEditorPopupDialogAppHelper @JvmOverloads constructor(
|
||||
|
||||
fun dismissDialog(wmHelper: WindowManagerStateHelper) {
|
||||
val dismissButton = uiDevice.wait(
|
||||
Until.findObject(By.text("Dismiss")), FIND_TIMEOUT)
|
||||
Until.findObject(By.text("Dismiss")), FIND_TIMEOUT)
|
||||
|
||||
// Pressing back key to dismiss the dialog
|
||||
if (dismissButton != null) {
|
||||
|
||||
@@ -25,10 +25,9 @@ import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
|
||||
class ImeStateInitializeHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.IME_ACTIVITY_INITIALIZE_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.Ime.StateInitializeActivity.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.IME_ACTIVITY_INITIALIZE_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
ActivityOptions.Ime.StateInitializeActivity.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy =
|
||||
LauncherStrategyFactory.getInstance(instr).launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.flicker.helpers
|
||||
package com.android.server.wm.flicker.helpers
|
||||
|
||||
import android.app.Instrumentation
|
||||
import com.android.server.wm.flicker.testapp.ActivityOptions
|
||||
import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
import com.android.wm.shell.flicker.testapp.Components
|
||||
|
||||
class SimpleAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
class LaunchBubbleHelper(instrumentation: Instrumentation) : StandardAppHelper(
|
||||
instrumentation,
|
||||
Components.SimpleActivity.LABEL,
|
||||
Components.SimpleActivity.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
ActivityOptions.Bubbles.LaunchBubble.LABEL,
|
||||
ActivityOptions.Bubbles.LaunchBubble.COMPONENT.toFlickerComponent()
|
||||
)
|
||||
@@ -28,13 +28,13 @@ import com.android.server.wm.traces.common.ComponentNameMatcher
|
||||
import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
|
||||
class MailAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.MAIL_ACTIVITY_LAUNCHER_NAME,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.MAIL_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.Mail.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.Mail.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
|
||||
|
||||
fun openMail(rowIdx: Int) {
|
||||
@@ -46,7 +46,7 @@ class MailAppHelper @JvmOverloads constructor(
|
||||
if (row != null) break
|
||||
scrollDown()
|
||||
}
|
||||
require(row != null) {""}
|
||||
require(row != null) { "" }
|
||||
row.click()
|
||||
uiDevice.wait(Until.gone(By.res(getPackage(), MAIL_LIST_RES_ID)), FIND_TIMEOUT)
|
||||
}
|
||||
@@ -57,9 +57,9 @@ class MailAppHelper @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun waitForMailList(): UiObject2 {
|
||||
var sel = By.res(getPackage(), MAIL_LIST_RES_ID).scrollable(true)
|
||||
val sel = By.res(getPackage(), MAIL_LIST_RES_ID).scrollable(true)
|
||||
val ret = uiDevice.wait(Until.findObject(sel), FIND_TIMEOUT)
|
||||
require(ret != null) {""}
|
||||
requireNotNull(ret) { "Unable to find $MAIL_LIST_RES_ID object" }
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
@@ -14,20 +14,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.flicker.helpers
|
||||
package com.android.server.wm.flicker.helpers
|
||||
|
||||
import android.app.Instrumentation
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import com.android.compatibility.common.util.SystemUtil
|
||||
import com.android.server.wm.traces.common.ComponentNameMatcher
|
||||
import java.io.IOException
|
||||
|
||||
class MultiWindowHelper(
|
||||
class MultiWindowUtils(
|
||||
instrumentation: Instrumentation,
|
||||
activityLabel: String,
|
||||
componentsInfo: ComponentNameMatcher
|
||||
) : BaseAppHelper(instrumentation, activityLabel, componentsInfo) {
|
||||
) : StandardAppHelper(instrumentation, activityLabel, componentsInfo) {
|
||||
|
||||
companion object {
|
||||
fun executeShellCommand(instrumentation: Instrumentation, cmd: String) {
|
||||
try {
|
||||
SystemUtil.runShellCommand(instrumentation, cmd)
|
||||
} catch (e: IOException) {
|
||||
Log.e(MultiWindowUtils::class.simpleName, "executeShellCommand error! $e")
|
||||
}
|
||||
}
|
||||
|
||||
fun getDevEnableNonResizableMultiWindow(context: Context): Int =
|
||||
Settings.Global.getInt(context.contentResolver,
|
||||
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW)
|
||||
@@ -29,9 +29,9 @@ import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelpe
|
||||
|
||||
class NewTasksAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.LaunchNewTask.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.LAUNCH_NEW_TASK_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
ActivityOptions.LaunchNewTask.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
@@ -43,7 +43,7 @@ class NewTasksAppHelper @JvmOverloads constructor(
|
||||
|
||||
requireNotNull(button) {
|
||||
"Button not found, this usually happens when the device " +
|
||||
"was left in an unknown state (e.g. in split screen)"
|
||||
"was left in an unknown state (e.g. in split screen)"
|
||||
}
|
||||
button.click()
|
||||
wmHelper.StateSyncBuilder()
|
||||
|
||||
@@ -25,10 +25,9 @@ import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
|
||||
class NonResizeableAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.NonResizeableActivity.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
ActivityOptions.NonResizeableActivity.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy =
|
||||
LauncherStrategyFactory.getInstance(instr).launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
|
||||
|
||||
@@ -28,25 +28,28 @@ import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelpe
|
||||
|
||||
class NotificationAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.NOTIFICATION_ACTIVITY_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.Notification.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.NOTIFICATION_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
ActivityOptions.Notification.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
|
||||
fun postNotification(wmHelper: WindowManagerStateHelper) {
|
||||
val button = uiDevice.wait(
|
||||
Until.findObject(By.res(getPackage(), "post_notification")),
|
||||
FIND_TIMEOUT)
|
||||
Until.findObject(By.res(getPackage(), "post_notification")),
|
||||
FIND_TIMEOUT)
|
||||
|
||||
require(button != null) {
|
||||
requireNotNull(button) {
|
||||
"Post notification button not found, this usually happens when the device " +
|
||||
"was left in an unknown state (e.g. in split screen)"
|
||||
"was left in an unknown state (e.g. in split screen)"
|
||||
}
|
||||
button.click()
|
||||
|
||||
uiDevice.wait(Until.findObject(By.text("Flicker Test Notification")), FIND_TIMEOUT)
|
||||
?: error("Flicker Notification not found")
|
||||
?: error("Flicker Notification not found")
|
||||
wmHelper.StateSyncBuilder()
|
||||
.withAppTransitionIdle()
|
||||
.waitForAndVerify()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,28 +14,23 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.flicker.helpers
|
||||
package com.android.server.wm.flicker.helpers
|
||||
|
||||
import android.app.Instrumentation
|
||||
import android.media.session.MediaController
|
||||
import android.media.session.MediaSessionManager
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.BySelector
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
|
||||
import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE
|
||||
import com.android.server.wm.flicker.testapp.ActivityOptions
|
||||
import com.android.server.wm.traces.common.Rect
|
||||
import com.android.server.wm.traces.common.WindowManagerConditionsFactory
|
||||
import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
|
||||
import com.android.wm.shell.flicker.pip.tv.closeTvPipWindow
|
||||
import com.android.wm.shell.flicker.pip.tv.isFocusedOrHasFocusedChild
|
||||
import com.android.wm.shell.flicker.testapp.Components
|
||||
|
||||
class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
open class PipAppHelper(instrumentation: Instrumentation) : StandardAppHelper(
|
||||
instrumentation,
|
||||
Components.PipActivity.LABEL,
|
||||
Components.PipActivity.COMPONENT.toFlickerComponent()
|
||||
ActivityOptions.Pip.LABEL,
|
||||
ActivityOptions.Pip.COMPONENT.toFlickerComponent()
|
||||
) {
|
||||
private val mediaSessionManager: MediaSessionManager
|
||||
get() = context.getSystemService(MediaSessionManager::class.java)
|
||||
@@ -46,16 +41,11 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
it.packageName == `package`
|
||||
}
|
||||
|
||||
fun clickObject(resId: String) {
|
||||
open fun clickObject(resId: String) {
|
||||
val selector = By.res(`package`, resId)
|
||||
val obj = uiDevice.findObject(selector) ?: error("Could not find `$resId` object")
|
||||
|
||||
if (!isTelevision) {
|
||||
obj.click()
|
||||
} else {
|
||||
focusOnObject(selector) || error("Could not focus on `$resId` object")
|
||||
uiDevice.pressDPadCenter()
|
||||
}
|
||||
obj.click()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,20 +75,6 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
fun exitPipToFullScreenViaIntent(wmHelper: WindowManagerStateHelper) =
|
||||
launchViaIntentAndWaitShown(wmHelper)
|
||||
|
||||
private fun focusOnObject(selector: BySelector): Boolean {
|
||||
// We expect all the focusable UI elements to be arranged in a way so that it is possible
|
||||
// to "cycle" over all them by clicking the D-Pad DOWN button, going back up to "the top"
|
||||
// from "the bottom".
|
||||
repeat(FOCUS_ATTEMPTS) {
|
||||
uiDevice.findObject(selector)?.apply { if (isFocusedOrHasFocusedChild) return true }
|
||||
?: error("The object we try to focus on is gone.")
|
||||
|
||||
uiDevice.pressDPadDown()
|
||||
uiDevice.waitForIdle()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun clickEnterPipButton(wmHelper: WindowManagerStateHelper) {
|
||||
clickObject(ENTER_PIP_BUTTON_ID)
|
||||
|
||||
@@ -140,12 +116,8 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
"Use PipAppHelper.closePipWindow(wmHelper) instead",
|
||||
ReplaceWith("closePipWindow(wmHelper)")
|
||||
)
|
||||
fun closePipWindow() {
|
||||
if (isTelevision) {
|
||||
uiDevice.closeTvPipWindow()
|
||||
} else {
|
||||
closePipWindow(WindowManagerStateHelper(mInstrumentation))
|
||||
}
|
||||
open fun closePipWindow() {
|
||||
closePipWindow(WindowManagerStateHelper(mInstrumentation))
|
||||
}
|
||||
|
||||
private fun getWindowRect(wmHelper: WindowManagerStateHelper): Rect {
|
||||
@@ -159,20 +131,16 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
/**
|
||||
* Taps the pip window and dismisses it by clicking on the X button.
|
||||
*/
|
||||
fun closePipWindow(wmHelper: WindowManagerStateHelper) {
|
||||
if (isTelevision) {
|
||||
uiDevice.closeTvPipWindow()
|
||||
} else {
|
||||
val windowRect = getWindowRect(wmHelper)
|
||||
uiDevice.click(windowRect.centerX(), windowRect.centerY())
|
||||
// search and interact with the dismiss button
|
||||
val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss")
|
||||
uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT)
|
||||
val dismissPipObject = uiDevice.findObject(dismissSelector)
|
||||
?: error("PIP window dismiss button not found")
|
||||
val dismissButtonBounds = dismissPipObject.visibleBounds
|
||||
uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY())
|
||||
}
|
||||
open fun closePipWindow(wmHelper: WindowManagerStateHelper) {
|
||||
val windowRect = getWindowRect(wmHelper)
|
||||
uiDevice.click(windowRect.centerX(), windowRect.centerY())
|
||||
// search and interact with the dismiss button
|
||||
val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss")
|
||||
uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT)
|
||||
val dismissPipObject = uiDevice.findObject(dismissSelector)
|
||||
?: error("PIP window dismiss button not found")
|
||||
val dismissButtonBounds = dismissPipObject.visibleBounds
|
||||
uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY())
|
||||
|
||||
// Wait for animation to complete.
|
||||
wmHelper.StateSyncBuilder()
|
||||
@@ -213,7 +181,6 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val FOCUS_ATTEMPTS = 20
|
||||
private const val ENTER_PIP_BUTTON_ID = "enter_pip"
|
||||
private const val WITH_CUSTOM_ACTIONS_BUTTON_ID = "with_custom_actions"
|
||||
private const val MEDIA_SESSION_START_RADIO_BUTTON_ID = "media_session_start"
|
||||
@@ -25,10 +25,9 @@ import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
|
||||
class SeamlessRotationAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.SEAMLESS_ACTIVITY_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.SeamlessRotation.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
ActivityOptions.SeamlessRotation.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy =
|
||||
LauncherStrategyFactory.getInstance(instr).launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
|
||||
|
||||
@@ -25,10 +25,9 @@ import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
|
||||
class ShowWhenLockedAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.SHOW_WHEN_LOCKED_ACTIVITY_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.ShowWhenLockedActivity.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.SHOW_WHEN_LOCKED_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
ActivityOptions.ShowWhenLockedActivity.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy =
|
||||
LauncherStrategyFactory.getInstance(instr).launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
|
||||
|
||||
@@ -25,10 +25,9 @@ import com.android.server.wm.traces.parser.toFlickerComponent
|
||||
|
||||
class SimpleAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.SIMPLE_ACTIVITY_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.SimpleActivity.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
ActivityOptions.SimpleActivity.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy =
|
||||
LauncherStrategyFactory.getInstance(instr).launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
|
||||
|
||||
@@ -29,16 +29,15 @@ import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelpe
|
||||
|
||||
class TwoActivitiesAppHelper @JvmOverloads constructor(
|
||||
instr: Instrumentation,
|
||||
launcherName: String = ActivityOptions.BUTTON_ACTIVITY_LAUNCHER_NAME,
|
||||
launcherName: String = ActivityOptions.LaunchNewActivity.LABEL,
|
||||
component: ComponentNameMatcher =
|
||||
ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
|
||||
.getInstance(instr)
|
||||
.launcherStrategy
|
||||
ActivityOptions.LaunchNewActivity.COMPONENT.toFlickerComponent(),
|
||||
launcherStrategy: ILauncherStrategy =
|
||||
LauncherStrategyFactory.getInstance(instr).launcherStrategy
|
||||
) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
|
||||
|
||||
private val secondActivityComponent =
|
||||
ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent()
|
||||
ActivityOptions.SimpleActivity.COMPONENT.toFlickerComponent()
|
||||
|
||||
fun openSecondActivity(device: UiDevice, wmHelper: WindowManagerStateHelper) {
|
||||
val launchActivityButton = By.res(getPackage(), LAUNCH_SECOND_ACTIVITY)
|
||||
@@ -46,7 +45,7 @@ class TwoActivitiesAppHelper @JvmOverloads constructor(
|
||||
|
||||
requireNotNull(button) {
|
||||
"Button not found, this usually happens when the device " +
|
||||
"was left in an unknown state (e.g. in split screen)"
|
||||
"was left in an unknown state (e.g. in split screen)"
|
||||
}
|
||||
button.click()
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ public class ActivityOptions {
|
||||
FLICKER_APP_PACKAGE + ".LaunchNewActivity");
|
||||
}
|
||||
|
||||
public static class PipActivity {
|
||||
public static class Pip {
|
||||
// Test App > Pip Activity
|
||||
public static final String LABEL = "PipActivity";
|
||||
public static final String MENU_ACTION_NO_OP = "No-Op";
|
||||
@@ -163,7 +163,7 @@ public class ActivityOptions {
|
||||
FLICKER_APP_PACKAGE + ".PipActivity");
|
||||
}
|
||||
|
||||
public static class SplitScreenActivity {
|
||||
public static class SplitScreen {
|
||||
public static class Primary {
|
||||
public static final String LABEL = "SplitScreenPrimaryActivity";
|
||||
public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
|
||||
|
||||
Reference in New Issue
Block a user