1 /* 2 * Copyright (C) 2022 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.launcher3.tapl; 18 19 import static com.android.launcher3.tapl.LauncherInstrumentation.DEFAULT_POLL_INTERVAL; 20 import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID; 21 import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS; 22 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT; 23 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING; 24 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT; 25 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING; 26 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_SHELL_DRAG_READY; 27 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT; 28 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_SCALE; 29 30 import android.graphics.Point; 31 import android.graphics.Rect; 32 import android.os.SystemClock; 33 import android.view.InputDevice; 34 import android.view.MotionEvent; 35 import android.view.ViewConfiguration; 36 37 import androidx.test.uiautomator.By; 38 import androidx.test.uiautomator.Condition; 39 import androidx.test.uiautomator.UiDevice; 40 41 import com.android.launcher3.testing.shared.ResourceUtils; 42 import com.android.launcher3.testing.shared.TestProtocol; 43 44 /** 45 * Background state operations specific to when an app has been launched. 46 */ 47 public final class LaunchedAppState extends Background { 48 49 // More drag steps than Launchables to give the window manager time to register the drag. 50 private static final int DEFAULT_DRAG_STEPS = 35; 51 52 // UNSTASHED_TASKBAR_HANDLE_HINT_SCALE value from TaskbarStashController. 53 private static final float UNSTASHED_TASKBAR_HANDLE_HINT_SCALE = 1.1f; 54 55 private static final int STASHED_TASKBAR_BOTTOM_EDGE_DP = 1; 56 57 private final Condition<UiDevice, Boolean> mStashedTaskbarHintScaleCondition = 58 device -> mLauncher.getTestInfo(REQUEST_STASHED_TASKBAR_SCALE).getFloat( 59 TestProtocol.TEST_INFO_RESPONSE_FIELD) - UNSTASHED_TASKBAR_HANDLE_HINT_SCALE 60 < 0.00001f; 61 62 private final Condition<UiDevice, Boolean> mStashedTaskbarDefaultScaleCondition = 63 device -> mLauncher.getTestInfo(REQUEST_STASHED_TASKBAR_SCALE).getFloat( 64 TestProtocol.TEST_INFO_RESPONSE_FIELD) - 1f < 0.00001f; 65 66 LaunchedAppState(LauncherInstrumentation launcher) { 67 super(launcher); 68 } 69 70 @Override 71 protected LauncherInstrumentation.ContainerType getContainerType() { 72 return LauncherInstrumentation.ContainerType.LAUNCHED_APP; 73 } 74 75 /** 76 * Returns the taskbar. 77 * 78 * The taskbar must already be visible when calling this method. 79 */ 80 public Taskbar getTaskbar() { 81 try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 82 "want to get the taskbar")) { 83 mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID); 84 85 return new Taskbar(mLauncher); 86 } 87 } 88 89 /** 90 * Waits for the taskbar to be hidden, or fails. 91 */ 92 public void assertTaskbarHidden() { 93 try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 94 "waiting for taskbar to be hidden")) { 95 mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); 96 } 97 } 98 99 /** 100 * Waits for the taskbar to be visible, or fails. 101 */ 102 public void assertTaskbarVisible() { 103 try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 104 "waiting for taskbar to be visible")) { 105 mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID); 106 } 107 } 108 109 /** 110 * Returns the Taskbar in a visible state. 111 * 112 * The taskbar must already be hidden when calling this method. 113 */ 114 public Taskbar showTaskbar() { 115 mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING); 116 mLauncher.getTestInfo(REQUEST_ENABLE_BLOCK_TIMEOUT); 117 118 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 119 LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( 120 "want to show the taskbar")) { 121 mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); 122 123 final long downTime = SystemClock.uptimeMillis(); 124 final int unstashTargetY = mLauncher.getRealDisplaySize().y 125 - (mLauncher.getTestInfo(REQUEST_STASHED_TASKBAR_HEIGHT) 126 .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD) / 2); 127 final Point unstashTarget = new Point( 128 mLauncher.getRealDisplaySize().x / 2, unstashTargetY); 129 130 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, unstashTarget, 131 LauncherInstrumentation.GestureScope.EXPECT_PILFER); 132 LauncherInstrumentation.log("showTaskbar: sent down"); 133 134 try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) { 135 mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID); 136 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, unstashTarget, 137 LauncherInstrumentation.GestureScope.EXPECT_PILFER); 138 139 return new Taskbar(mLauncher); 140 } 141 } finally { 142 mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING); 143 mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT); 144 } 145 } 146 147 static void dragToSplitscreen( 148 LauncherInstrumentation launcher, 149 Launchable launchable, 150 String expectedNewPackageName, 151 String expectedExistingPackageName) { 152 try (LauncherInstrumentation.Closable c1 = launcher.addContextLayer( 153 "want to drag taskbar item to splitscreen")) { 154 final Point displaySize = launcher.getRealDisplaySize(); 155 // Drag to the center of the top-left quadrant of the screen, this point will work in 156 // both portrait and landscape. 157 final Point endPoint = new Point(displaySize.x / 4, displaySize.y / 4); 158 final long downTime = SystemClock.uptimeMillis(); 159 // Use mObject before starting drag since the system drag and drop moves the original 160 // view. 161 Point itemVisibleCenter = launchable.mObject.getVisibleCenter(); 162 Rect itemVisibleBounds = launcher.getVisibleBounds(launchable.mObject); 163 String itemLabel = launchable.mObject.getText(); 164 165 Point dragStart = launchable.startDrag( 166 downTime, 167 launchable::addExpectedEventsForLongClick, 168 /* runToSpringLoadedState= */ false); 169 170 try (LauncherInstrumentation.Closable c2 = launcher.addContextLayer( 171 "started item drag")) { 172 launcher.assertTrue("Shell drag not marked as ready", launcher.waitAndGet(() -> { 173 LauncherInstrumentation.log("Checking shell drag ready"); 174 return launcher.getTestInfo(REQUEST_SHELL_DRAG_READY) 175 .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, false); 176 }, WAIT_TIME_MS, DEFAULT_POLL_INTERVAL)); 177 launcher.movePointer( dragStart, endPoint, DEFAULT_DRAG_STEPS, true, downTime, SystemClock.uptimeMillis(), false, LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER)178 launcher.movePointer( 179 dragStart, 180 endPoint, 181 DEFAULT_DRAG_STEPS, 182 /* isDecelerating= */ true, 183 downTime, 184 SystemClock.uptimeMillis(), 185 /* slowDown= */ false, 186 LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER); 187 try(LauncherInstrumentation.Closable c3 = launcher.addContextLayer( "moved pointer to drop point"))188 try (LauncherInstrumentation.Closable c3 = launcher.addContextLayer( 189 "moved pointer to drop point")) { 190 LauncherInstrumentation.log("SplitscreenDragSource.dragToSplitscreen: " 191 + "before drop " + itemVisibleCenter + " in " + itemVisibleBounds); 192 launcher.sendPointer( 193 downTime, 194 SystemClock.uptimeMillis(), 195 MotionEvent.ACTION_UP, 196 endPoint, 197 LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER); 198 LauncherInstrumentation.log("SplitscreenDragSource.dragToSplitscreen: " 199 + "after drop"); 200 201 try (LauncherInstrumentation.Closable c4 = launcher.addContextLayer( 202 "dropped item")) { 203 launchable.assertAppLaunched(By.pkg(expectedNewPackageName)); 204 launchable.assertAppLaunched(By.pkg(expectedExistingPackageName)); 205 } 206 } 207 } 208 } 209 } 210 211 /** 212 * Emulate the cursor hovering the screen edge to unstash the taskbar. 213 * 214 * <p>This unstashing occurs when not actively hovering the taskbar. 215 */ 216 public Taskbar hoverScreenBottomEdgeToUnstashTaskbar() { 217 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 218 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 219 "cursor hover entering screen edge to unstash taskbar")) { 220 mLauncher.getDevice().wait(mStashedTaskbarDefaultScaleCondition, 221 ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT); 222 223 long downTime = SystemClock.uptimeMillis(); 224 int leftEdge = 10; 225 Point taskbarUnstashArea = new Point(leftEdge, mLauncher.getRealDisplaySize().y - 1); 226 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 227 new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null, 228 InputDevice.SOURCE_MOUSE); 229 230 mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID); 231 232 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT, 233 new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null, 234 InputDevice.SOURCE_MOUSE); 235 236 return new Taskbar(mLauncher); 237 } 238 } 239 240 /** 241 * Emulate the cursor hovering the taskbar to get unstash hint, then hovering below to unstash. 242 */ 243 public Taskbar hoverBelowHintedTaskbarToUnstash() { 244 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 245 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 246 "cursor hover entering stashed taskbar")) { 247 long downTime = SystemClock.uptimeMillis(); 248 Point stashedTaskbarHintArea = new Point(mLauncher.getRealDisplaySize().x / 2, 249 mLauncher.getRealDisplaySize().y - 1); 250 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 251 new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null, 252 InputDevice.SOURCE_MOUSE); 253 254 mLauncher.getDevice().wait(mStashedTaskbarHintScaleCondition, 255 LauncherInstrumentation.WAIT_TIME_MS); 256 257 try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( 258 "cursor hover enter below taskbar to unstash")) { 259 downTime = SystemClock.uptimeMillis(); 260 Point taskbarUnstashArea = new Point(mLauncher.getRealDisplaySize().x / 2, 261 mLauncher.getRealDisplaySize().y - 1); 262 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT, 263 new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null, 264 InputDevice.SOURCE_MOUSE); 265 266 mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID); 267 return new Taskbar(mLauncher); 268 } 269 } 270 } 271 272 /** 273 * Emulate the cursor entering and exiting a hover over the taskbar. 274 */ 275 public void hoverToShowTaskbarUnstashHint() { 276 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 277 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 278 "cursor hover entering stashed taskbar")) { 279 long downTime = SystemClock.uptimeMillis(); 280 Point stashedTaskbarHintArea = new Point(mLauncher.getRealDisplaySize().x / 2, 281 mLauncher.getRealDisplaySize().y - 1); 282 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 283 new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null); 284 285 mLauncher.getDevice().wait(mStashedTaskbarHintScaleCondition, 286 LauncherInstrumentation.WAIT_TIME_MS); 287 288 try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( 289 "cursor hover exiting stashed taskbar")) { 290 Point outsideStashedTaskbarHintArea = new Point( 291 mLauncher.getRealDisplaySize().x / 2, 292 mLauncher.getRealDisplaySize().y - 500); 293 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT, 294 new Point(outsideStashedTaskbarHintArea.x, outsideStashedTaskbarHintArea.y), 295 null); 296 297 mLauncher.getDevice().wait(mStashedTaskbarDefaultScaleCondition, 298 LauncherInstrumentation.WAIT_TIME_MS); 299 } 300 } 301 } 302 303 /** 304 * Emulate the cursor clicking the stashed taskbar to go home. 305 */ 306 public Workspace clickStashedTaskbarToGoHome() { 307 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); 308 LauncherInstrumentation.Closable c = mLauncher.addContextLayer( 309 "cursor hover entering stashed taskbar")) { 310 long downTime = SystemClock.uptimeMillis(); 311 int stashedTaskbarBottomEdge = ResourceUtils.pxFromDp(STASHED_TASKBAR_BOTTOM_EDGE_DP, 312 mLauncher.getResources().getDisplayMetrics()); 313 Point stashedTaskbarHintArea = new Point(mLauncher.getRealDisplaySize().x / 2, 314 mLauncher.getRealDisplaySize().y - stashedTaskbarBottomEdge - 1); 315 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 316 new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null, 317 InputDevice.SOURCE_MOUSE); 318 319 mLauncher.getDevice().wait(mStashedTaskbarHintScaleCondition, 320 LauncherInstrumentation.WAIT_TIME_MS); 321 322 try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( 323 "cursor clicking stashed taskbar to go home")) { 324 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT, 325 new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), 326 null, InputDevice.SOURCE_MOUSE); 327 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, 328 new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), 329 LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER, 330 InputDevice.SOURCE_MOUSE); 331 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_BUTTON_PRESS, 332 new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), 333 null, InputDevice.SOURCE_MOUSE); 334 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_BUTTON_RELEASE, 335 new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), 336 null, InputDevice.SOURCE_MOUSE); 337 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, 338 new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), 339 LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER, 340 InputDevice.SOURCE_MOUSE); 341 342 return mLauncher.getWorkspace(); 343 } 344 } 345 } 346 } 347