Loading tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +12 −0 Original line number Diff line number Diff line Loading @@ -423,6 +423,18 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL); } @Test @PortraitLandscape public void testDeleteFromWorkspace() throws Exception { // test delete both built-in apps and user-installed app from workspace for (String appName : new String[] {"Gmail", "Play Store", APP_NAME}) { final AppIcon appIcon = createShortcutIfNotExist(appName); Workspace workspace = mLauncher.getWorkspace().deleteAppIcon(appIcon); assertNull(appName + " app was found after being deleted from workspace", workspace.tryGetWorkspaceAppIcon(appName)); } } public static String getAppPackageName() { return getInstrumentation().getContext().getPackageName(); } Loading tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +47 −12 Original line number Diff line number Diff line Loading @@ -1399,14 +1399,15 @@ public final class LauncherInstrumentation { final Point start = new Point(startX, startY); final Point end = new Point(endX, endY); sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope); final long endTime = movePointer(start, end, steps, downTime, slowDown, gestureScope); final long endTime = movePointer( start, end, steps, false, downTime, slowDown, gestureScope); sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope); } long movePointer(Point start, Point end, int steps, long downTime, boolean slowDown, GestureScope gestureScope) { long endTime = movePointer( downTime, downTime, steps * GESTURE_STEP_MS, start, end, gestureScope); long movePointer(Point start, Point end, int steps, boolean isDecelerating, long downTime, boolean slowDown, GestureScope gestureScope) { long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, isDecelerating, start, end, gestureScope); if (slowDown) { endTime = movePointer(downTime, endTime + GESTURE_STEP_MS, 5 * GESTURE_STEP_MS, end, end, gestureScope); Loading Loading @@ -1485,21 +1486,55 @@ public final class LauncherInstrumentation { public long movePointer(long downTime, long startTime, long duration, Point from, Point to, GestureScope gestureScope) { return movePointer( downTime, startTime, duration, false, from, to, gestureScope); } public long movePointer(long downTime, long startTime, long duration, boolean isDecelerating, Point from, Point to, GestureScope gestureScope) { log("movePointer: " + from + " to " + to); final Point point = new Point(); long steps = duration / GESTURE_STEP_MS; long currentTime = startTime; if (isDecelerating) { // formula: V = V0 - D*T, assuming V = 0 when T = duration // vx0: initial speed at the x-dimension, set as twice the avg speed // dx: the constant deceleration at the x-dimension double vx0 = 2 * (to.x - from.x) / duration; double dx = vx0 / duration; // vy0: initial speed at the y-dimension, set as twice the avg speed // dy: the constant deceleration at the y-dimension double vy0 = 2 * (to.y - from.y) / duration; double dy = vy0 / duration; for (long i = 0; i < steps; ++i) { sleep(GESTURE_STEP_MS); currentTime += GESTURE_STEP_MS; // formula: P = P0 + V0*T - (D*T^2/2) final double t = (i + 1) * GESTURE_STEP_MS; point.x = from.x + (int) (vx0 * t - 0.5 * dx * t * t); point.y = from.y + (int) (vy0 * t - 0.5 * dy * t * t); sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point, gestureScope); } } else { for (long i = 0; i < steps; ++i) { sleep(GESTURE_STEP_MS); currentTime += GESTURE_STEP_MS; final float progress = (currentTime - startTime) / (float) duration; final float progress = (currentTime - startTime) / (float) duration; point.x = from.x + (int) (progress * (to.x - from.x)); point.y = from.y + (int) (progress * (to.y - from.y)); sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point, gestureScope); } } return currentTime; } Loading tests/tapl/com/android/launcher3/tapl/Workspace.java +46 −9 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ import java.util.stream.Collectors; */ public final class Workspace extends Home { private static final int FLING_STEPS = 10; private static final int DEFAULT_DRAG_STEPS = 10; private static final String DROP_BAR_RES_ID = "drop_target_bar"; private static final String DELETE_TARGET_TEXT_ID = "delete_target_text"; static final Pattern EVENT_CTRL_W_DOWN = Pattern.compile( "Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_W" Loading Loading @@ -211,6 +214,40 @@ public final class Workspace extends Home { TestProtocol.TEST_INFO_RESPONSE_FIELD); } /* * Get the center point of the delete icon in the drop target bar. */ private Point getDeleteDropPoint() { return mLauncher.waitForObjectInContainer( mLauncher.waitForLauncherObject(DROP_BAR_RES_ID), DELETE_TARGET_TEXT_ID).getVisibleCenter(); } /** * Delete the appIcon from the workspace. * * @param appIcon to be deleted. * @return validated workspace after the existing appIcon being deleted. */ public Workspace deleteAppIcon(AppIcon appIcon) { try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "removing app icon from workspace")) { dragIconToWorkspace( mLauncher, appIcon, () -> getDeleteDropPoint(), true, /* decelerating */ appIcon.getLongPressIndicator(), () -> mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), null); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( "dragged the app to the drop bar")) { return new Workspace(mLauncher); } } } /** * Finds folder icons in the current workspace. * Loading Loading @@ -241,8 +278,8 @@ public final class Workspace extends Home { expectLongClickEvents.run(); launcher.waitForLauncherObject(longPressIndicator); LauncherInstrumentation.log("dragIconToSpringLoaded: indicator"); launcher.movePointer(iconCenter, dragStartCenter, 10, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); launcher.movePointer(iconCenter, dragStartCenter, DEFAULT_DRAG_STEPS, false, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); }, SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start"); return dragStartCenter; } Loading Loading @@ -270,7 +307,7 @@ public final class Workspace extends Home { expectDropEvents = () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START); } dragIconToWorkspace(launcher, launchable, () -> dest, longPressIndicator, dragIconToWorkspace(launcher, launchable, () -> dest, false, longPressIndicator, expectLongClickEvents, expectDropEvents); } Loading @@ -280,13 +317,13 @@ public final class Workspace extends Home { */ static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> destSupplier, String longPressIndicator) { dragIconToWorkspace(launcher, launchable, destSupplier, longPressIndicator, dragIconToWorkspace(launcher, launchable, destSupplier, false, longPressIndicator, () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), null); } static void dragIconToWorkspace( LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> dest, String longPressIndicator, Runnable expectLongClickEvents, boolean isDecelerating, String longPressIndicator, Runnable expectLongClickEvents, @Nullable Runnable expectDropEvents) { try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer( "want to drag icon to workspace")) { Loading @@ -301,8 +338,8 @@ public final class Workspace extends Home { while (targetDest.x > displayX || targetDest.x < 0) { int edgeX = targetDest.x > 0 ? displayX : 0; Point screenEdge = new Point(edgeX, targetDest.y); launcher.movePointer(dragStart, screenEdge, 10, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); launcher.movePointer(dragStart, screenEdge, DEFAULT_DRAG_STEPS, isDecelerating, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); launcher.waitForIdle(); // Wait for the page change to happen targetDest.x += displayX * (targetDest.x > 0 ? -1 : 1); dragStart = screenEdge; Loading @@ -310,8 +347,8 @@ public final class Workspace extends Home { // targetDest.x is now between 0 and displayX so we found the target page, // we just have to put move the icon to the destination and drop it launcher.movePointer(dragStart, targetDest, 10, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents); } } Loading Loading
tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +12 −0 Original line number Diff line number Diff line Loading @@ -423,6 +423,18 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL); } @Test @PortraitLandscape public void testDeleteFromWorkspace() throws Exception { // test delete both built-in apps and user-installed app from workspace for (String appName : new String[] {"Gmail", "Play Store", APP_NAME}) { final AppIcon appIcon = createShortcutIfNotExist(appName); Workspace workspace = mLauncher.getWorkspace().deleteAppIcon(appIcon); assertNull(appName + " app was found after being deleted from workspace", workspace.tryGetWorkspaceAppIcon(appName)); } } public static String getAppPackageName() { return getInstrumentation().getContext().getPackageName(); } Loading
tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +47 −12 Original line number Diff line number Diff line Loading @@ -1399,14 +1399,15 @@ public final class LauncherInstrumentation { final Point start = new Point(startX, startY); final Point end = new Point(endX, endY); sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope); final long endTime = movePointer(start, end, steps, downTime, slowDown, gestureScope); final long endTime = movePointer( start, end, steps, false, downTime, slowDown, gestureScope); sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope); } long movePointer(Point start, Point end, int steps, long downTime, boolean slowDown, GestureScope gestureScope) { long endTime = movePointer( downTime, downTime, steps * GESTURE_STEP_MS, start, end, gestureScope); long movePointer(Point start, Point end, int steps, boolean isDecelerating, long downTime, boolean slowDown, GestureScope gestureScope) { long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS, isDecelerating, start, end, gestureScope); if (slowDown) { endTime = movePointer(downTime, endTime + GESTURE_STEP_MS, 5 * GESTURE_STEP_MS, end, end, gestureScope); Loading Loading @@ -1485,21 +1486,55 @@ public final class LauncherInstrumentation { public long movePointer(long downTime, long startTime, long duration, Point from, Point to, GestureScope gestureScope) { return movePointer( downTime, startTime, duration, false, from, to, gestureScope); } public long movePointer(long downTime, long startTime, long duration, boolean isDecelerating, Point from, Point to, GestureScope gestureScope) { log("movePointer: " + from + " to " + to); final Point point = new Point(); long steps = duration / GESTURE_STEP_MS; long currentTime = startTime; if (isDecelerating) { // formula: V = V0 - D*T, assuming V = 0 when T = duration // vx0: initial speed at the x-dimension, set as twice the avg speed // dx: the constant deceleration at the x-dimension double vx0 = 2 * (to.x - from.x) / duration; double dx = vx0 / duration; // vy0: initial speed at the y-dimension, set as twice the avg speed // dy: the constant deceleration at the y-dimension double vy0 = 2 * (to.y - from.y) / duration; double dy = vy0 / duration; for (long i = 0; i < steps; ++i) { sleep(GESTURE_STEP_MS); currentTime += GESTURE_STEP_MS; // formula: P = P0 + V0*T - (D*T^2/2) final double t = (i + 1) * GESTURE_STEP_MS; point.x = from.x + (int) (vx0 * t - 0.5 * dx * t * t); point.y = from.y + (int) (vy0 * t - 0.5 * dy * t * t); sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point, gestureScope); } } else { for (long i = 0; i < steps; ++i) { sleep(GESTURE_STEP_MS); currentTime += GESTURE_STEP_MS; final float progress = (currentTime - startTime) / (float) duration; final float progress = (currentTime - startTime) / (float) duration; point.x = from.x + (int) (progress * (to.x - from.x)); point.y = from.y + (int) (progress * (to.y - from.y)); sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point, gestureScope); } } return currentTime; } Loading
tests/tapl/com/android/launcher3/tapl/Workspace.java +46 −9 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ import java.util.stream.Collectors; */ public final class Workspace extends Home { private static final int FLING_STEPS = 10; private static final int DEFAULT_DRAG_STEPS = 10; private static final String DROP_BAR_RES_ID = "drop_target_bar"; private static final String DELETE_TARGET_TEXT_ID = "delete_target_text"; static final Pattern EVENT_CTRL_W_DOWN = Pattern.compile( "Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_W" Loading Loading @@ -211,6 +214,40 @@ public final class Workspace extends Home { TestProtocol.TEST_INFO_RESPONSE_FIELD); } /* * Get the center point of the delete icon in the drop target bar. */ private Point getDeleteDropPoint() { return mLauncher.waitForObjectInContainer( mLauncher.waitForLauncherObject(DROP_BAR_RES_ID), DELETE_TARGET_TEXT_ID).getVisibleCenter(); } /** * Delete the appIcon from the workspace. * * @param appIcon to be deleted. * @return validated workspace after the existing appIcon being deleted. */ public Workspace deleteAppIcon(AppIcon appIcon) { try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "removing app icon from workspace")) { dragIconToWorkspace( mLauncher, appIcon, () -> getDeleteDropPoint(), true, /* decelerating */ appIcon.getLongPressIndicator(), () -> mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), null); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( "dragged the app to the drop bar")) { return new Workspace(mLauncher); } } } /** * Finds folder icons in the current workspace. * Loading Loading @@ -241,8 +278,8 @@ public final class Workspace extends Home { expectLongClickEvents.run(); launcher.waitForLauncherObject(longPressIndicator); LauncherInstrumentation.log("dragIconToSpringLoaded: indicator"); launcher.movePointer(iconCenter, dragStartCenter, 10, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); launcher.movePointer(iconCenter, dragStartCenter, DEFAULT_DRAG_STEPS, false, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); }, SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start"); return dragStartCenter; } Loading Loading @@ -270,7 +307,7 @@ public final class Workspace extends Home { expectDropEvents = () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START); } dragIconToWorkspace(launcher, launchable, () -> dest, longPressIndicator, dragIconToWorkspace(launcher, launchable, () -> dest, false, longPressIndicator, expectLongClickEvents, expectDropEvents); } Loading @@ -280,13 +317,13 @@ public final class Workspace extends Home { */ static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> destSupplier, String longPressIndicator) { dragIconToWorkspace(launcher, launchable, destSupplier, longPressIndicator, dragIconToWorkspace(launcher, launchable, destSupplier, false, longPressIndicator, () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), null); } static void dragIconToWorkspace( LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> dest, String longPressIndicator, Runnable expectLongClickEvents, boolean isDecelerating, String longPressIndicator, Runnable expectLongClickEvents, @Nullable Runnable expectDropEvents) { try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer( "want to drag icon to workspace")) { Loading @@ -301,8 +338,8 @@ public final class Workspace extends Home { while (targetDest.x > displayX || targetDest.x < 0) { int edgeX = targetDest.x > 0 ? displayX : 0; Point screenEdge = new Point(edgeX, targetDest.y); launcher.movePointer(dragStart, screenEdge, 10, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); launcher.movePointer(dragStart, screenEdge, DEFAULT_DRAG_STEPS, isDecelerating, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); launcher.waitForIdle(); // Wait for the page change to happen targetDest.x += displayX * (targetDest.x > 0 ? -1 : 1); dragStart = screenEdge; Loading @@ -310,8 +347,8 @@ public final class Workspace extends Home { // targetDest.x is now between 0 and displayX so we found the target page, // we just have to put move the icon to the destination and drop it launcher.movePointer(dragStart, targetDest, 10, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating, downTime, true, LauncherInstrumentation.GestureScope.INSIDE); dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents); } } Loading