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