1 /* <lambda>null2 * 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.wm.shell.flicker.service.splitscreen.scenarios 18 19 import android.app.Instrumentation 20 import android.graphics.Point 21 import android.tools.NavBar 22 import android.tools.Rotation 23 import android.tools.helpers.WindowUtils 24 import android.tools.traces.parsers.WindowManagerStateHelper 25 import androidx.test.platform.app.InstrumentationRegistry 26 import androidx.test.uiautomator.UiDevice 27 import com.android.launcher3.tapl.LauncherInstrumentation 28 import com.android.wm.shell.flicker.service.common.Utils 29 import com.android.wm.shell.flicker.utils.SplitScreenUtils 30 import org.junit.After 31 import org.junit.Before 32 import org.junit.Ignore 33 import org.junit.Rule 34 import org.junit.Test 35 36 @Ignore("Base Test Class") 37 abstract class SwitchAppByDoubleTapDivider 38 @JvmOverloads 39 constructor(val rotation: Rotation = Rotation.ROTATION_0) { 40 private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() 41 private val tapl = LauncherInstrumentation() 42 private val wmHelper = WindowManagerStateHelper(instrumentation) 43 private val device = UiDevice.getInstance(instrumentation) 44 private val primaryApp = SplitScreenUtils.getPrimary(instrumentation) 45 private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation) 46 47 @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) 48 49 @Before 50 fun setup() { 51 tapl.workspace.switchToOverview().dismissAllTasks() 52 53 tapl.setEnableRotation(true) 54 tapl.setExpectedRotation(rotation.value) 55 56 SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp, rotation) 57 } 58 59 @Test 60 open fun switchAppByDoubleTapDivider() { 61 SplitScreenUtils.doubleTapDividerToSwitch(device) 62 wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() 63 64 waitForLayersToSwitch(wmHelper) 65 waitForWindowsToSwitch(wmHelper) 66 } 67 68 @After 69 fun teardown() { 70 primaryApp.exit(wmHelper) 71 secondaryApp.exit(wmHelper) 72 } 73 74 private fun waitForWindowsToSwitch(wmHelper: WindowManagerStateHelper) { 75 wmHelper 76 .StateSyncBuilder() 77 .add("appWindowsSwitched") { 78 val primaryAppWindow = 79 it.wmState.visibleWindows.firstOrNull { window -> 80 primaryApp.windowMatchesAnyOf(window) 81 } 82 ?: return@add false 83 val secondaryAppWindow = 84 it.wmState.visibleWindows.firstOrNull { window -> 85 secondaryApp.windowMatchesAnyOf(window) 86 } 87 ?: return@add false 88 89 if (isLandscape(rotation)) { 90 return@add if (isTablet()) { 91 secondaryAppWindow.frame.right <= primaryAppWindow.frame.left 92 } else { 93 primaryAppWindow.frame.right <= secondaryAppWindow.frame.left 94 } 95 } else { 96 return@add if (isTablet()) { 97 primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top 98 } else { 99 primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top 100 } 101 } 102 } 103 .waitForAndVerify() 104 } 105 106 private fun waitForLayersToSwitch(wmHelper: WindowManagerStateHelper) { 107 wmHelper 108 .StateSyncBuilder() 109 .add("appLayersSwitched") { 110 val primaryAppLayer = 111 it.layerState.visibleLayers.firstOrNull { window -> 112 primaryApp.layerMatchesAnyOf(window) 113 } 114 ?: return@add false 115 val secondaryAppLayer = 116 it.layerState.visibleLayers.firstOrNull { window -> 117 secondaryApp.layerMatchesAnyOf(window) 118 } 119 ?: return@add false 120 121 val primaryVisibleRegion = primaryAppLayer.visibleRegion?.bounds ?: return@add false 122 val secondaryVisibleRegion = 123 secondaryAppLayer.visibleRegion?.bounds ?: return@add false 124 125 if (isLandscape(rotation)) { 126 return@add if (isTablet()) { 127 secondaryVisibleRegion.right <= primaryVisibleRegion.left 128 } else { 129 primaryVisibleRegion.right <= secondaryVisibleRegion.left 130 } 131 } else { 132 return@add if (isTablet()) { 133 primaryVisibleRegion.bottom <= secondaryVisibleRegion.top 134 } else { 135 primaryVisibleRegion.bottom <= secondaryVisibleRegion.top 136 } 137 } 138 } 139 .waitForAndVerify() 140 } 141 142 private fun isLandscape(rotation: Rotation): Boolean { 143 val displayBounds = WindowUtils.getDisplayBounds(rotation) 144 return displayBounds.width() > displayBounds.height() 145 } 146 147 private fun isTablet(): Boolean { 148 val sizeDp: Point = device.displaySizeDp 149 val LARGE_SCREEN_DP_THRESHOLD = 600 150 return sizeDp.x >= LARGE_SCREEN_DP_THRESHOLD && sizeDp.y >= LARGE_SCREEN_DP_THRESHOLD 151 } 152 } 153