1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm.flicker.helpers 18 19 import android.app.Instrumentation 20 import android.graphics.Rect 21 import android.graphics.Region 22 import android.tools.device.apphelpers.StandardAppHelper 23 import android.tools.helpers.FIND_TIMEOUT 24 import android.tools.helpers.GestureHelper 25 import android.tools.helpers.SYSTEMUI_PACKAGE 26 import android.tools.traces.component.ComponentNameMatcher 27 import android.tools.traces.parsers.WindowManagerStateHelper 28 import android.tools.traces.parsers.toFlickerComponent 29 import androidx.test.uiautomator.By 30 import androidx.test.uiautomator.Until 31 import com.android.server.wm.flicker.testapp.ActivityOptions 32 33 class LetterboxAppHelper 34 @JvmOverloads 35 constructor( 36 instr: Instrumentation, 37 launcherName: String = ActivityOptions.NonResizeableFixedAspectRatioPortraitActivity.LABEL, 38 component: ComponentNameMatcher = 39 ActivityOptions.NonResizeableFixedAspectRatioPortraitActivity.COMPONENT.toFlickerComponent() 40 ) : StandardAppHelper(instr, launcherName, component) { 41 42 private val gestureHelper: GestureHelper = 43 GestureHelper(instrumentation) 44 clickRestartnull45 fun clickRestart(wmHelper: WindowManagerStateHelper) { 46 val restartButton = 47 uiDevice.wait( 48 Until.findObject(By.res(SYSTEMUI_PACKAGE, "size_compat_restart_button")), 49 FIND_TIMEOUT 50 ) 51 restartButton?.run { restartButton.click() } ?: error("Restart button not found") 52 53 // size compat mode restart confirmation dialog button 54 val restartDialogButton = 55 uiDevice.wait( 56 Until.findObject( 57 By.res(SYSTEMUI_PACKAGE, "letterbox_restart_dialog_restart_button") 58 ), 59 FIND_TIMEOUT 60 ) 61 restartDialogButton?.run { restartDialogButton.click() } 62 ?: error("Restart dialog button not found") 63 wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() 64 } 65 repositionHorizontallynull66 fun repositionHorizontally(displayBounds: Rect, right: Boolean) { 67 val x = if (right) displayBounds.right - BOUNDS_OFFSET else BOUNDS_OFFSET 68 reposition(x.toFloat(), displayBounds.centerY().toFloat()) 69 } 70 repositionVerticallynull71 fun repositionVertically(displayBounds: Rect, bottom: Boolean) { 72 val y = if (bottom) displayBounds.bottom - BOUNDS_OFFSET else BOUNDS_OFFSET 73 reposition(displayBounds.centerX().toFloat(), y.toFloat()) 74 } 75 repositionnull76 private fun reposition(x: Float, y: Float) { 77 val coords = GestureHelper.Tuple(x, y) 78 require(gestureHelper.tap(coords, 2)) { "Failed to reposition letterbox app" } 79 } 80 waitForAppToMoveHorizontallyTonull81 fun waitForAppToMoveHorizontallyTo( 82 wmHelper: WindowManagerStateHelper, 83 displayBounds: Rect, 84 right: Boolean 85 ) { 86 wmHelper 87 .StateSyncBuilder() 88 .add("letterboxAppRepositioned") { 89 val letterboxAppWindow = getWindowRegion(wmHelper) 90 val appRegionBounds = letterboxAppWindow.bounds 91 val appWidth = appRegionBounds.width() 92 return@add if (right) 93 appRegionBounds.left == displayBounds.right - appWidth && 94 appRegionBounds.right == displayBounds.right 95 else 96 appRegionBounds.left == displayBounds.left && 97 appRegionBounds.right == displayBounds.left + appWidth 98 } 99 .waitForAndVerify() 100 } 101 waitForAppToMoveVerticallyTonull102 fun waitForAppToMoveVerticallyTo( 103 wmHelper: WindowManagerStateHelper, 104 displayBounds: Rect, 105 navBarHeight: Int, 106 bottom: Boolean 107 ) { 108 wmHelper 109 .StateSyncBuilder() 110 .add("letterboxAppRepositioned") { 111 val letterboxAppWindow = getWindowRegion(wmHelper) 112 val appRegionBounds = letterboxAppWindow.bounds 113 val appHeight = appRegionBounds.height() 114 return@add if (bottom) 115 appRegionBounds.bottom == displayBounds.bottom && 116 appRegionBounds.top == (displayBounds.bottom - appHeight + navBarHeight) 117 else 118 appRegionBounds.top == displayBounds.top && 119 appRegionBounds.bottom == displayBounds.top + appHeight 120 } 121 .waitForAndVerify() 122 } 123 getWindowRegionnull124 private fun getWindowRegion(wmHelper: WindowManagerStateHelper): Region { 125 val windowRegion = wmHelper.getWindowRegion(this) 126 require(!windowRegion.isEmpty) { 127 "Unable to find letterbox app window in the current state" 128 } 129 return windowRegion 130 } 131 132 companion object { 133 private const val BOUNDS_OFFSET: Int = 50 134 } 135 } 136