• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.android.launcher3.ui;
17 
18 import static androidx.test.InstrumentationRegistry.getInstrumentation;
19 import static androidx.test.InstrumentationRegistry.getTargetContext;
20 
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.graphics.Point;
27 import android.os.Process;
28 import android.os.SystemClock;
29 import android.util.Log;
30 import android.view.KeyEvent;
31 import android.view.MotionEvent;
32 import android.view.View;
33 import android.view.ViewGroup;
34 
35 import androidx.test.uiautomator.By;
36 import androidx.test.uiautomator.BySelector;
37 import androidx.test.uiautomator.UiDevice;
38 import androidx.test.uiautomator.UiObject2;
39 import androidx.test.uiautomator.Until;
40 
41 import com.android.launcher3.LauncherAppWidgetProviderInfo;
42 import com.android.launcher3.R;
43 import com.android.launcher3.compat.AppWidgetManagerCompat;
44 import com.android.launcher3.testcomponent.AppWidgetNoConfig;
45 import com.android.launcher3.testcomponent.AppWidgetWithConfig;
46 
47 import java.util.concurrent.Callable;
48 import java.util.function.Function;
49 
50 public class TestViewHelpers {
51     private static final String TAG = "TestViewHelpers";
52 
getDevice()53     private static UiDevice getDevice() {
54         return UiDevice.getInstance(getInstrumentation());
55     }
56 
findViewById(int id)57     public static UiObject2 findViewById(int id) {
58         return getDevice().wait(Until.findObject(getSelectorForId(id)),
59                 AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT);
60     }
61 
getSelectorForId(int id)62     public static BySelector getSelectorForId(int id) {
63         final Context targetContext = getTargetContext();
64         String name = targetContext.getResources().getResourceEntryName(id);
65         return By.res(targetContext.getPackageName(), name);
66     }
67 
68     /**
69      * Finds a widget provider which can fit on the home screen.
70      *
71      * @param test               test suite.
72      * @param hasConfigureScreen if true, a provider with a config screen is returned.
73      */
findWidgetProvider(AbstractLauncherUiTest test, final boolean hasConfigureScreen)74     public static LauncherAppWidgetProviderInfo findWidgetProvider(AbstractLauncherUiTest test,
75             final boolean hasConfigureScreen) {
76         LauncherAppWidgetProviderInfo info =
77                 test.getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
78                     @Override
79                     public LauncherAppWidgetProviderInfo call() throws Exception {
80                         ComponentName cn = new ComponentName(getInstrumentation().getContext(),
81                                 hasConfigureScreen ? AppWidgetWithConfig.class
82                                         : AppWidgetNoConfig.class);
83                         Log.d(TAG, "findWidgetProvider componentName=" + cn.flattenToString());
84                         return AppWidgetManagerCompat.getInstance(getTargetContext())
85                                 .findProvider(cn, Process.myUserHandle());
86                     }
87                 });
88         if (info == null) {
89             throw new IllegalArgumentException("No valid widget provider");
90         }
91         return info;
92     }
93 
94     /**
95      * Drags an icon to the center of homescreen.
96      *
97      * @param icon object that is either app icon or shortcut icon
98      */
dragToWorkspace(UiObject2 icon, boolean expectedToShowShortcuts)99     public static void dragToWorkspace(UiObject2 icon, boolean expectedToShowShortcuts) {
100         Point center = icon.getVisibleCenter();
101 
102         // Action Down
103         final long downTime = SystemClock.uptimeMillis();
104         sendPointer(downTime, MotionEvent.ACTION_DOWN, center);
105 
106         UiObject2 dragLayer = findViewById(R.id.drag_layer);
107 
108         if (expectedToShowShortcuts) {
109             // Make sure shortcuts show up, and then move a bit to hide them.
110             assertNotNull(findViewById(R.id.deep_shortcuts_container));
111 
112             Point moveLocation = new Point(center);
113             int distanceToMove =
114                     getTargetContext().getResources().getDimensionPixelSize(
115                             R.dimen.deep_shortcuts_start_drag_threshold) + 50;
116             if (moveLocation.y - distanceToMove >= dragLayer.getVisibleBounds().top) {
117                 moveLocation.y -= distanceToMove;
118             } else {
119                 moveLocation.y += distanceToMove;
120             }
121             movePointer(downTime, center, moveLocation);
122 
123             assertNull(findViewById(R.id.deep_shortcuts_container));
124         }
125 
126         // Wait until Remove/Delete target is visible
127         assertNotNull(findViewById(R.id.delete_target_text));
128 
129         Point moveLocation = dragLayer.getVisibleCenter();
130 
131         // Move to center
132         movePointer(downTime, center, moveLocation);
133         sendPointer(downTime, MotionEvent.ACTION_UP, moveLocation);
134 
135         // Wait until remove target is gone.
136         getDevice().wait(Until.gone(getSelectorForId(R.id.delete_target_text)),
137                 AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT);
138     }
139 
movePointer(long downTime, Point from, Point to)140     private static void movePointer(long downTime, Point from, Point to) {
141         while (!from.equals(to)) {
142             try {
143                 Thread.sleep(20);
144             } catch (InterruptedException e) {
145                 e.printStackTrace();
146             }
147             from.x = getNextMoveValue(to.x, from.x);
148             from.y = getNextMoveValue(to.y, from.y);
149             sendPointer(downTime, MotionEvent.ACTION_MOVE, from);
150         }
151     }
152 
getNextMoveValue(int targetValue, int oldValue)153     private static int getNextMoveValue(int targetValue, int oldValue) {
154         if (targetValue - oldValue > 10) {
155             return oldValue + 10;
156         } else if (targetValue - oldValue < -10) {
157             return oldValue - 10;
158         } else {
159             return targetValue;
160         }
161     }
162 
sendPointer(long downTime, int action, Point point)163     public static void sendPointer(long downTime, int action, Point point) {
164         MotionEvent event = MotionEvent.obtain(downTime,
165                 SystemClock.uptimeMillis(), action, point.x, point.y, 0);
166         getInstrumentation().sendPointerSync(event);
167         event.recycle();
168     }
169 
170     /**
171      * Opens widget tray and returns the recycler view.
172      */
openWidgetsTray()173     public static UiObject2 openWidgetsTray() {
174         final UiDevice device = getDevice();
175         device.pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
176         device.waitForIdle();
177         return findViewById(R.id.widgets_list_view);
178     }
179 
findChildView(ViewGroup parent, Function<View, Boolean> condition)180     public static View findChildView(ViewGroup parent, Function<View, Boolean> condition) {
181         for (int i = 0; i < parent.getChildCount(); ++i) {
182             final View child = parent.getChildAt(i);
183             if (condition.apply(child)) return child;
184         }
185         return null;
186     }
187 }
188