1 /* 2 * Copyright (C) 2018 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.testing.shared.TestProtocol.SPRING_LOADED_STATE_ORDINAL; 20 21 import android.graphics.Point; 22 import android.view.MotionEvent; 23 24 import androidx.test.uiautomator.By; 25 import androidx.test.uiautomator.BySelector; 26 import androidx.test.uiautomator.UiObject2; 27 import androidx.test.uiautomator.Until; 28 29 import com.android.launcher3.testing.shared.TestProtocol; 30 31 /** 32 * Ancestor for AppIcon and AppMenuItem. 33 */ 34 public abstract class Launchable { 35 36 protected static final int DEFAULT_DRAG_STEPS = 10; 37 38 protected final LauncherInstrumentation mLauncher; 39 40 protected final UiObject2 mObject; 41 Launchable(LauncherInstrumentation launcher, UiObject2 object)42 Launchable(LauncherInstrumentation launcher, UiObject2 object) { 43 mObject = object; 44 mLauncher = launcher; 45 } 46 getObject()47 UiObject2 getObject() { 48 return mObject; 49 } 50 51 /** 52 * Clicks the object to launch its app. 53 */ launch(String expectedPackageName)54 public LaunchedAppState launch(String expectedPackageName) { 55 try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) { 56 return launch(By.pkg(expectedPackageName)); 57 } 58 } 59 expectActivityStartEvents()60 protected abstract void expectActivityStartEvents(); 61 launchableType()62 protected abstract String launchableType(); 63 launch(BySelector selector)64 private LaunchedAppState launch(BySelector selector) { 65 try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( 66 "want to launch an app from " + launchableType())) { 67 LauncherInstrumentation.log("Launchable.launch before click " 68 + mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject)); 69 70 mLauncher.clickLauncherObject(mObject); 71 72 try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("clicked")) { 73 expectActivityStartEvents(); 74 return assertAppLaunched(selector); 75 } 76 } 77 } 78 79 /** 80 * Clicks a launcher object to initiate splitscreen, where the selected app will be one of two 81 * apps running on the screen. Should be called when Launcher is in a "split staging" state 82 * and is waiting for the user's selection of a second app. Expects a SPLIT_START_EVENT to be 83 * fired when the click is executed. 84 */ launchIntoSplitScreen()85 public LaunchedAppState launchIntoSplitScreen() { 86 try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( 87 "want to launch split tasks from " + launchableType())) { 88 LauncherInstrumentation.log("Launchable.launch before click " 89 + mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject)); 90 91 mLauncher.clickLauncherObject(mObject); 92 93 try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("clicked")) { 94 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, OverviewTask.SPLIT_START_EVENT); 95 return new LaunchedAppState(mLauncher); 96 } 97 } 98 } 99 assertAppLaunched(BySelector selector)100 protected LaunchedAppState assertAppLaunched(BySelector selector) { 101 mLauncher.assertTrue( 102 "App didn't start: (" + selector + ")", 103 mLauncher.getDevice().wait(Until.hasObject(selector), 104 LauncherInstrumentation.WAIT_TIME_MS)); 105 return new LaunchedAppState(mLauncher); 106 } 107 startDrag(long downTime, Runnable expectLongClickEvents, boolean runToSpringLoadedState)108 Point startDrag(long downTime, Runnable expectLongClickEvents, boolean runToSpringLoadedState) { 109 final Point iconCenter = getObject().getVisibleCenter(); 110 final Point dragStartCenter = new Point(iconCenter.x, 111 iconCenter.y - getStartDragThreshold()); 112 113 if (runToSpringLoadedState) { 114 mLauncher.runToState(() -> movePointerForStartDrag( 115 downTime, 116 iconCenter, 117 dragStartCenter, 118 expectLongClickEvents), 119 SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start"); 120 } else { 121 movePointerForStartDrag( 122 downTime, 123 iconCenter, 124 dragStartCenter, 125 expectLongClickEvents); 126 } 127 128 return dragStartCenter; 129 } 130 131 /** 132 * Waits for a confirmation that a long press has successfully been triggered. 133 * 134 * This method waits for a view to either appear or disappear to confirm that the long press 135 * has been triggered and fails if no confirmation is received before the default timeout. 136 */ waitForLongPressConfirmation()137 protected abstract void waitForLongPressConfirmation(); 138 139 /** 140 * Drags this Launchable a short distance before starting a full drag. 141 * 142 * This is necessary for shortcuts, which require being dragged beyond a threshold to close 143 * their container and start drag callbacks. 144 */ movePointerForStartDrag( long downTime, Point iconCenter, Point dragStartCenter, Runnable expectLongClickEvents)145 private void movePointerForStartDrag( 146 long downTime, 147 Point iconCenter, 148 Point dragStartCenter, 149 Runnable expectLongClickEvents) { 150 mLauncher.sendPointer( 151 downTime, 152 downTime, 153 MotionEvent.ACTION_DOWN, 154 iconCenter, 155 LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER); 156 LauncherInstrumentation.log("movePointerForStartDrag: sent down"); 157 expectLongClickEvents.run(); 158 waitForLongPressConfirmation(); 159 LauncherInstrumentation.log("movePointerForStartDrag: indicator"); 160 mLauncher.movePointer( 161 iconCenter, 162 dragStartCenter, 163 DEFAULT_DRAG_STEPS, 164 /* isDecelerating= */ false, 165 downTime, 166 downTime, 167 /* slowDown= */ true, 168 LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER); 169 } 170 getStartDragThreshold()171 private int getStartDragThreshold() { 172 return mLauncher.getTestInfo(TestProtocol.REQUEST_START_DRAG_THRESHOLD).getInt( 173 TestProtocol.TEST_INFO_RESPONSE_FIELD); 174 } 175 addExpectedEventsForLongClick()176 protected abstract void addExpectedEventsForLongClick(); 177 } 178