• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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