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.SYSTEMUI_PACKAGE 25 import android.tools.traces.component.ComponentNameMatcher 26 import android.tools.traces.parsers.WindowManagerStateHelper 27 import android.tools.traces.parsers.toFlickerComponent 28 import androidx.test.uiautomator.By 29 import androidx.test.uiautomator.Until 30 import com.android.server.wm.flicker.testapp.ActivityOptions 31 32 class LetterboxAppHelper 33 @JvmOverloads 34 constructor( 35 instr: Instrumentation, 36 launcherName: String = ActivityOptions.NonResizeablePortraitActivity.LABEL, 37 component: ComponentNameMatcher = 38 ActivityOptions.NonResizeablePortraitActivity.COMPONENT.toFlickerComponent() 39 ) : StandardAppHelper(instr, launcherName, component) { 40 41 private val gestureHelper: GestureHelper = GestureHelper(instrumentation) 42 clickRestartnull43 fun clickRestart(wmHelper: WindowManagerStateHelper) { 44 val restartButton = 45 uiDevice.wait( 46 Until.findObject(By.res(SYSTEMUI_PACKAGE, "size_compat_restart_button")), 47 FIND_TIMEOUT 48 ) 49 restartButton?.run { restartButton.click() } ?: error("Restart button not found") 50 51 // size compat mode restart confirmation dialog button 52 val restartDialogButton = 53 uiDevice.wait( 54 Until.findObject( 55 By.res(SYSTEMUI_PACKAGE, "letterbox_restart_dialog_restart_button") 56 ), 57 FIND_TIMEOUT 58 ) 59 restartDialogButton?.run { restartDialogButton.click() } 60 ?: error("Restart dialog button not found") 61 wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() 62 } 63 repositionHorizontallynull64 fun repositionHorizontally(displayBounds: Rect, right: Boolean) { 65 val x = if (right) displayBounds.right - BOUNDS_OFFSET else BOUNDS_OFFSET 66 reposition(x.toFloat(), displayBounds.centerY().toFloat()) 67 } 68 repositionVerticallynull69 fun repositionVertically(displayBounds: Rect, bottom: Boolean) { 70 val y = if (bottom) displayBounds.bottom - BOUNDS_OFFSET else BOUNDS_OFFSET 71 reposition(displayBounds.centerX().toFloat(), y.toFloat()) 72 } 73 repositionnull74 private fun reposition(x: Float, y: Float) { 75 val coords = GestureHelper.Tuple(x, y) 76 require(gestureHelper.tap(coords, 2)) { "Failed to reposition letterbox app" } 77 } 78 waitForAppToMoveHorizontallyTonull79 fun waitForAppToMoveHorizontallyTo( 80 wmHelper: WindowManagerStateHelper, 81 displayBounds: Rect, 82 right: Boolean 83 ) { 84 wmHelper 85 .StateSyncBuilder() 86 .add("letterboxAppRepositioned") { 87 val letterboxAppWindow = getWindowRegion(wmHelper) 88 val appRegionBounds = letterboxAppWindow.bounds 89 val appWidth = appRegionBounds.width() 90 return@add if (right) 91 appRegionBounds.left == displayBounds.right - appWidth && 92 appRegionBounds.right == displayBounds.right 93 else 94 appRegionBounds.left == displayBounds.left && 95 appRegionBounds.right == displayBounds.left + appWidth 96 } 97 .waitForAndVerify() 98 } 99 waitForAppToMoveVerticallyTonull100 fun waitForAppToMoveVerticallyTo( 101 wmHelper: WindowManagerStateHelper, 102 displayBounds: Rect, 103 navBarHeight: Int, 104 bottom: Boolean 105 ) { 106 wmHelper 107 .StateSyncBuilder() 108 .add("letterboxAppRepositioned") { 109 val letterboxAppWindow = getWindowRegion(wmHelper) 110 val appRegionBounds = letterboxAppWindow.bounds 111 val appHeight = appRegionBounds.height() 112 return@add if (bottom) 113 appRegionBounds.bottom == displayBounds.bottom && 114 appRegionBounds.top == (displayBounds.bottom - appHeight + navBarHeight) 115 else 116 appRegionBounds.top == displayBounds.top && 117 appRegionBounds.bottom == displayBounds.top + appHeight 118 } 119 .waitForAndVerify() 120 } 121 getWindowRegionnull122 private fun getWindowRegion(wmHelper: WindowManagerStateHelper): Region { 123 val windowRegion = wmHelper.getWindowRegion(this) 124 require(!windowRegion.isEmpty) { 125 "Unable to find letterbox app window in the current state" 126 } 127 return windowRegion 128 } 129 130 companion object { 131 private const val BOUNDS_OFFSET: Int = 100 132 } 133 } 134