diff --git a/go/quickstep/src/com/android/launcher3/AppSharing.java b/go/quickstep/src/com/android/launcher3/AppSharing.java index 7c66f6e105..c252fba728 100644 --- a/go/quickstep/src/com/android/launcher3/AppSharing.java +++ b/go/quickstep/src/com/android/launcher3/AppSharing.java @@ -22,6 +22,9 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Process; +import android.os.UserHandle; +import android.os.UserManager; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -98,14 +101,19 @@ public final class AppSharing { * The Share App system shortcut, used to initiate p2p sharing of a given app */ public final class Share extends SystemShortcut { - private PopupDataProvider mPopupDataProvider; + private final PopupDataProvider mPopupDataProvider; + private final boolean mSharingEnabledForUser; public Share(Launcher target, ItemInfo itemInfo) { super(R.drawable.ic_share, R.string.app_share_drop_target_label, target, itemInfo); mPopupDataProvider = target.getPopupDataProvider(); - if (ENABLE_SHAREABILITY_CHECK) { - mShareabilityMgr = AppShareabilityManager.INSTANCE.get(target); + mSharingEnabledForUser = bluetoothSharingEnabled(target); + if (!mSharingEnabledForUser) { + setEnabled(false); + } else if (ENABLE_SHAREABILITY_CHECK) { + mShareabilityMgr = + AppShareabilityManager.INSTANCE.get(target.getApplicationContext()); checkShareability(/* requestUpdateIfUnknown */ true); } } @@ -144,7 +152,12 @@ public final class AppSharing { sendIntent.setType(APP_MIME_TYPE); sendIntent.setComponent(ComponentName.unflattenFromString(mSharingComponent)); - mTarget.startActivitySafely(view, sendIntent, mItemInfo); + UserHandle user = mItemInfo.user; + if (user != null && !user.equals(Process.myUserHandle())) { + mTarget.startActivityAsUser(sendIntent, user); + } else { + mTarget.startActivitySafely(view, sendIntent, mItemInfo); + } AbstractFloatingView.closeAllOpenViews(mTarget); } @@ -170,8 +183,15 @@ public final class AppSharing { } } + private boolean bluetoothSharingEnabled(Context context) { + return !context.getSystemService(UserManager.class) + .hasUserRestriction(UserManager.DISALLOW_BLUETOOTH_SHARING, mItemInfo.user); + } + private void showCannotShareToast(Context context) { - CharSequence text = context.getText(R.string.toast_p2p_app_not_shareable); + CharSequence text = (mSharingEnabledForUser) + ? context.getText(R.string.toast_p2p_app_not_shareable) + : context.getText(R.string.blocked_by_policy); int duration = Toast.LENGTH_SHORT; Toast.makeText(context, text, duration).show(); } diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java index cf80c35972..0d0f700b39 100644 --- a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java +++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java @@ -47,7 +47,7 @@ import java.util.function.Consumer; * Each app's status is retrieved from the Play Store's API. Statuses are cached in order * to limit extraneous calls to that API (which can be time-consuming). */ -public final class AppShareabilityManager { +public class AppShareabilityManager { @Retention(SOURCE) @IntDef({ ShareabilityStatus.UNKNOWN, diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java index 02468497bb..276e1c2a6f 100644 --- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java @@ -23,6 +23,7 @@ import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBN import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED; import android.annotation.SuppressLint; +import android.app.ActivityManager; import android.content.Context; import android.graphics.Insets; import android.graphics.Matrix; @@ -54,6 +55,7 @@ import com.android.quickstep.views.TaskView; import com.android.quickstep.views.TaskView.TaskIdAttributeContainer; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.system.ActivityManagerWrapper; import java.util.ArrayList; import java.util.List; @@ -115,8 +117,9 @@ public class TaskOverlayFactory implements ResourceBasedOverride { * Does NOT add split options in the following scenarios: * * The taskView to add split options is already showing split screen tasks * * There aren't at least 2 tasks in overview to show split options for + * * Device is in "Lock task mode" * * The taskView to show split options for is the focused task AND we haven't started - * scrolling in overview (if we haven't scrolled, there's a split overview action so + * scrolling in overview (if we haven't scrolled, there's a split overview action button so * we don't need this menu option) */ private static void addSplitOptions(List outShortcuts, @@ -130,7 +133,11 @@ public class TaskOverlayFactory implements ResourceBasedOverride { boolean isFocusedTask = deviceProfile.overviewShowAsGrid && taskView.isFocusedTask(); boolean isTaskInExpectedScrollPosition = recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView)); - if (taskViewHasMultipleTasks || notEnoughTasksToSplit || + ActivityManager activityManager = + (ActivityManager) taskView.getContext().getSystemService(Context.ACTIVITY_SERVICE); + boolean isLockTaskMode = activityManager.isInLockTaskMode(); + + if (taskViewHasMultipleTasks || notEnoughTasksToSplit || isLockTaskMode || (isFocusedTask && isTaskInExpectedScrollPosition)) { return; } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 1d8a45983b..3e0eb9127b 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -470,7 +470,9 @@ public class TaskView extends FrameLayout implements Reusable { stubInfo.user = componentKey.user; stubInfo.intent = new Intent().setComponent(componentKey.componentName); stubInfo.title = task.title; - stubInfo.screenId = getRecentsView().indexOfChild(this); + if (getRecentsView() != null) { + stubInfo.screenId = getRecentsView().indexOfChild(this); + } return stubInfo; } diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 5a46e1280e..6db0af3799 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -133,6 +133,8 @@ + + diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml index d2d8fc3c10..dd201e556f 100644 --- a/res/xml/device_profiles.xml +++ b/res/xml/device_profiles.xml @@ -140,6 +140,7 @@ launcher:name="6_by_5" launcher:numRows="5" launcher:numColumns="6" + launcher:numSearchContainerColumns="3" launcher:numFolderRows="3" launcher:numFolderColumns="3" launcher:numHotseatIcons="6" diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 2a29f3bde7..ab8e5e73f0 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -1061,8 +1061,10 @@ public class DeviceProfile { writer.println(prefix + "\tisScalableGrid:" + isScalableGrid); - writer.println(prefix + "\tinv.numColumns: " + inv.numColumns); writer.println(prefix + "\tinv.numRows: " + inv.numRows); + writer.println(prefix + "\tinv.numColumns: " + inv.numColumns); + writer.println(prefix + "\tinv.numSearchContainerColumns: " + + inv.numSearchContainerColumns); writer.println(prefix + "\tminCellSize: " + inv.minCellSize[mTypeIndex] + "dp"); diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 2d0d640772..94325d0216 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -105,6 +105,7 @@ public class InvariantDeviceProfile { */ public int numRows; public int numColumns; + public int numSearchContainerColumns; /** * Number of icons per row and column in the folder. @@ -304,6 +305,7 @@ public class InvariantDeviceProfile { GridOption closestProfile = displayOption.grid; numRows = closestProfile.numRows; numColumns = closestProfile.numColumns; + numSearchContainerColumns = closestProfile.numSearchContainerColumns; dbFile = closestProfile.dbFile; defaultLayoutId = closestProfile.defaultLayoutId; demoModeLayoutId = closestProfile.demoModeLayoutId; @@ -401,8 +403,8 @@ public class InvariantDeviceProfile { private Object[] toModelState() { return new Object[]{ - numColumns, numRows, numDatabaseHotseatIcons, iconBitmapSize, fillResIconDpi, - numDatabaseAllAppsColumns, dbFile}; + numColumns, numRows, numSearchContainerColumns, numDatabaseHotseatIcons, + iconBitmapSize, fillResIconDpi, numDatabaseAllAppsColumns, dbFile}; } private void onConfigChanged(Context context) { @@ -679,6 +681,7 @@ public class InvariantDeviceProfile { public final String name; public final int numRows; public final int numColumns; + public final int numSearchContainerColumns; public final boolean isEnabled; private final int numFolderRows; @@ -705,6 +708,8 @@ public class InvariantDeviceProfile { name = a.getString(R.styleable.GridDisplayOption_name); numRows = a.getInt(R.styleable.GridDisplayOption_numRows, 0); numColumns = a.getInt(R.styleable.GridDisplayOption_numColumns, 0); + numSearchContainerColumns = a.getInt( + R.styleable.GridDisplayOption_numSearchContainerColumns, numColumns); dbFile = a.getString(R.styleable.GridDisplayOption_dbFile); defaultLayoutId = a.getResourceId(deviceType == TYPE_MULTI_DISPLAY && a.hasValue( diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 281dfea492..65006ff87f 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -585,8 +585,8 @@ public class Workspace extends PagedView int cellVSpan = FeatureFlags.EXPANDED_SMARTSPACE.get() ? EXPANDED_SMARTSPACE_HEIGHT : DEFAULT_SMARTSPACE_HEIGHT; - CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), - cellVSpan); + int cellHSpan = mLauncher.getDeviceProfile().inv.numSearchContainerColumns; + CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, cellHSpan, cellVSpan); lp.canReorder = false; if (!firstPage.addViewToCellLayout(mQsb, 0, R.id.search_container_workspace, lp, true)) { Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout"); diff --git a/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java index b048cd4d43..122a130f7b 100644 --- a/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java +++ b/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java @@ -19,6 +19,7 @@ package com.android.launcher3.ui.workspace; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; @@ -47,20 +48,12 @@ import java.util.stream.Collectors; @RunWith(AndroidJUnit4.class) public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { - Workspace mWorkspace; - @Before public void setUp() throws Exception { super.setUp(); TaplTestsLauncher3.initialize(this); - mWorkspace = mLauncher.getWorkspace(); - } - @Test - public void testDragIconToRightPanel() { - if (!mLauncher.isTwoPanels()) { - return; - } + assumeTrue(mLauncher.isTwoPanels()); // Pre verifying the screens executeOnLauncher(launcher -> { @@ -68,8 +61,15 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { assertItemsOnPage(launcher, 0, "Play Store", "Maps"); assertPageEmpty(launcher, 1); }); + } - mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Chrome"), 1); + @Test + // TODO(b/197631877) Enable in portrait. + // @PortraitLandscape + public void testDragIconToRightPanel() { + Workspace workspace = mLauncher.getWorkspace(); + + workspace.dragIcon(workspace.getHotseatAppIcon("Chrome"), 1); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1); @@ -79,19 +79,67 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { } @Test - public void testDragIconToPage2() { - if (!mLauncher.isTwoPanels()) { - return; - } + // TODO(b/197631877) Enable in portrait. + // @PortraitLandscape + public void testSinglePageDragIconWhenMultiplePageScrollingIsPossible() { + Workspace workspace = mLauncher.getWorkspace(); + + workspace.dragIcon(workspace.getHotseatAppIcon("Chrome"), 2); + + workspace.flingBackward(); + + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), 3); - // Pre verifying the screens executeOnLauncher(launcher -> { - assertPagesExist(launcher, 0, 1); - assertItemsOnPage(launcher, 0, "Play Store", "Maps"); + assertPagesExist(launcher, 0, 1, 2, 3); + assertItemsOnPage(launcher, 0, "Play Store"); assertPageEmpty(launcher, 1); + assertItemsOnPage(launcher, 2, "Chrome"); + assertItemsOnPage(launcher, 3, "Maps"); }); - mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), 2); + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), 3); + + executeOnLauncher(launcher -> { + assertPagesExist(launcher, 0, 1, 2, 3, 4, 5); + assertItemsOnPage(launcher, 0, "Play Store"); + assertPageEmpty(launcher, 1); + assertItemsOnPage(launcher, 2, "Chrome"); + assertPageEmpty(launcher, 3); + assertPageEmpty(launcher, 4); + assertItemsOnPage(launcher, 5, "Maps"); + }); + + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), -1); + + executeOnLauncher(launcher -> { + assertPagesExist(launcher, 0, 1, 2, 3); + assertItemsOnPage(launcher, 0, "Play Store"); + assertPageEmpty(launcher, 1); + assertItemsOnPage(launcher, 2, "Chrome"); + assertItemsOnPage(launcher, 3, "Maps"); + }); + + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), -1); + + workspace.flingForward(); + + workspace.dragIcon(workspace.getWorkspaceAppIcon("Chrome"), -2); + + executeOnLauncher(launcher -> { + assertPagesExist(launcher, 0, 1); + assertItemsOnPage(launcher, 0, "Chrome", "Play Store"); + assertItemsOnPage(launcher, 1, "Maps"); + }); + } + + @Test + // TODO(b/197631877) Enable in portrait. + // @PortraitLandscape + public void testDragIconToPage2() { + Workspace workspace = mLauncher.getWorkspace(); + + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), 2); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1, 2, 3); @@ -103,19 +151,12 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { } @Test + // TODO(b/197631877) Enable in portrait. + // @PortraitLandscape public void testDragIconToPage3() { - if (!mLauncher.isTwoPanels()) { - return; - } + Workspace workspace = mLauncher.getWorkspace(); - // Pre verifying the screens - executeOnLauncher(launcher -> { - assertPagesExist(launcher, 0, 1); - assertItemsOnPage(launcher, 0, "Play Store", "Maps"); - assertPageEmpty(launcher, 1); - }); - - mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Phone"), 3); + workspace.dragIcon(workspace.getHotseatAppIcon("Phone"), 3); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1, 2, 3); @@ -126,22 +167,61 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { }); } - @Test - public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() { - if (!mLauncher.isTwoPanels()) { - return; - } + // TODO(b/197631877) Enable in portrait. + // @PortraitLandscape + public void testMultiplePageDragIcon() { + Workspace workspace = mLauncher.getWorkspace(); + + workspace.dragIcon(workspace.getHotseatAppIcon("Messages"), 2); + + workspace.flingBackward(); + + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), 5); - // Pre verifying the screens executeOnLauncher(launcher -> { - assertPagesExist(launcher, 0, 1); - assertItemsOnPage(launcher, 0, "Play Store", "Maps"); + assertPagesExist(launcher, 0, 1, 2, 3, 4, 5); + assertItemsOnPage(launcher, 0, "Play Store"); assertPageEmpty(launcher, 1); + assertItemsOnPage(launcher, 2, "Messages"); + assertPageEmpty(launcher, 3); + assertPageEmpty(launcher, 4); + assertItemsOnPage(launcher, 5, "Maps"); }); - mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), 3); - mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Chrome"), 0); + workspace.flingBackward(); + + workspace.dragIcon(workspace.getWorkspaceAppIcon("Messages"), 4); + + executeOnLauncher(launcher -> { + assertPagesExist(launcher, 0, 1, 4, 5, 6, 7); + assertItemsOnPage(launcher, 0, "Play Store"); + assertPageEmpty(launcher, 1); + assertPageEmpty(launcher, 4); + assertItemsOnPage(launcher, 5, "Maps"); + assertItemsOnPage(launcher, 6, "Messages"); + assertPageEmpty(launcher, 7); + }); + + workspace.dragIcon(workspace.getWorkspaceAppIcon("Messages"), -3); + + executeOnLauncher(launcher -> { + assertPagesExist(launcher, 0, 1, 4, 5); + assertItemsOnPage(launcher, 0, "Play Store"); + assertItemsOnPage(launcher, 1, "Messages"); + assertPageEmpty(launcher, 4); + assertItemsOnPage(launcher, 5, "Maps"); + }); + } + + @Test + // TODO(b/197631877) Enable in portrait. + // @PortraitLandscape + public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() { + Workspace workspace = mLauncher.getWorkspace(); + + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), 3); + workspace.dragIcon(workspace.getHotseatAppIcon("Chrome"), 0); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1, 2, 3); @@ -151,7 +231,7 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { assertItemsOnPage(launcher, 3, "Maps"); }); - mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), -1); + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), -1); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1, 2, 3); @@ -163,8 +243,8 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { // Move Chrome to the right panel as well, to make sure pages are not deleted whichever // page is the empty one - mWorkspace.flingForward(); - mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Chrome"), 1); + workspace.flingForward(); + workspace.dragIcon(workspace.getWorkspaceAppIcon("Chrome"), 1); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1, 2, 3); @@ -175,22 +255,14 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { }); } - @Test + // TODO(b/197631877) Enable in portrait. + // @PortraitLandscape public void testEmptyPagesGetRemovedIfBothPagesAreEmpty() { - if (!mLauncher.isTwoPanels()) { - return; - } + Workspace workspace = mLauncher.getWorkspace(); - // Pre verifying the screens - executeOnLauncher(launcher -> { - assertPagesExist(launcher, 0, 1); - assertItemsOnPage(launcher, 0, "Play Store", "Maps"); - assertPageEmpty(launcher, 1); - }); - - mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Play Store"), 2); - mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Camera"), 1); + workspace.dragIcon(workspace.getWorkspaceAppIcon("Play Store"), 2); + workspace.dragIcon(workspace.getHotseatAppIcon("Camera"), 1); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1, 2, 3); @@ -200,9 +272,9 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { assertItemsOnPage(launcher, 3, "Camera"); }); - mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Camera"), -1); - mWorkspace.flingForward(); - mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Play Store"), -2); + workspace.dragIcon(workspace.getWorkspaceAppIcon("Camera"), -1); + workspace.flingForward(); + workspace.dragIcon(workspace.getWorkspaceAppIcon("Play Store"), -2); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1); @@ -212,20 +284,13 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { } @Test + // TODO(b/197631877) Enable in portrait. + // @PortraitLandscape public void testMiddleEmptyPagesGetRemoved() { - if (!mLauncher.isTwoPanels()) { - return; - } + Workspace workspace = mLauncher.getWorkspace(); - // Pre verifying the screens - executeOnLauncher(launcher -> { - assertPagesExist(launcher, 0, 1); - assertItemsOnPage(launcher, 0, "Play Store", "Maps"); - assertPageEmpty(launcher, 1); - }); - - mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), 2); - mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Messages"), 3); + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), 2); + workspace.dragIcon(workspace.getHotseatAppIcon("Messages"), 3); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1, 2, 3, 4, 5); @@ -237,8 +302,8 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { assertItemsOnPage(launcher, 5, "Messages"); }); - mWorkspace.flingBackward(); - mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), 2); + workspace.flingBackward(); + workspace.dragIcon(workspace.getWorkspaceAppIcon("Maps"), 2); executeOnLauncher(launcher -> { assertPagesExist(launcher, 0, 1, 4, 5); diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index 3f0d7fdc00..e457354289 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -16,6 +16,8 @@ package com.android.launcher3.tapl; +import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED; + import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL; import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL; import static com.android.launcher3.testing.TestProtocol.SPRING_LOADED_STATE_ORDINAL; @@ -165,15 +167,22 @@ public final class Workspace extends Home { } /** - * Drags an icon to the (currentPage + pageDelta) page if the page already exists. - * If the target page doesn't exist, the icon will be put onto an existing page that is the - * closest to the target page. + * Drags an icon to the (currentPage + pageDelta) page. + * If the target page doesn't exist yet, a new page will be created. + * In case the target page can't be created (e.g. existing pages are 0, 1, current: 0, + * pageDelta: 3, the latest page that can be created is 2) the icon will be dragged onto the + * page that can be created and is closest to the target page. * * @param appIcon - icon to drag. * @param pageDelta - how many pages should the icon be dragged from the current page. - * It can be a negative value. + * It can be a negative value. currentPage + pageDelta should be greater + * than or equal to 0. */ public void dragIcon(AppIcon appIcon, int pageDelta) { + if (mHotseat.getVisibleBounds().height() > mHotseat.getVisibleBounds().width()) { + throw new UnsupportedOperationException( + "dragIcon does NOT support dragging when the hotseat is on the side."); + } try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) { final UiObject2 workspace = verifyActiveContainer(); try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( @@ -338,9 +347,11 @@ 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, DEFAULT_DRAG_STEPS, isDecelerating, - downTime, true, LauncherInstrumentation.GestureScope.INSIDE); - launcher.waitForIdle(); // Wait for the page change to happen + Point finalDragStart = dragStart; + executeAndWaitForPageScroll(launcher, + () -> launcher.movePointer(finalDragStart, screenEdge, DEFAULT_DRAG_STEPS, + isDecelerating, downTime, true, + LauncherInstrumentation.GestureScope.INSIDE)); targetDest.x += displayX * (targetDest.x > 0 ? -1 : 1); dragStart = screenEdge; } @@ -353,6 +364,13 @@ public final class Workspace extends Home { } } + private static void executeAndWaitForPageScroll(LauncherInstrumentation launcher, + Runnable command) { + launcher.executeAndWaitForEvent(command, + event -> event.getEventType() == TYPE_VIEW_SCROLLED, + () -> "Page scroll didn't happen", "Scrolling page"); + } + /** * Flings to get to screens on the right. Waits for scrolling and a possible overscroll * recoil to complete.