Implement splitting from Taskbar long-press
Implements the ability to split the screen by long-pressing a Taskbar icon.
Bug: 217964720
Test: Manual
Change-Id: I5d324d8ca912c10cc3c3de21cae98fad546b85ac
diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
index 3bc6576..cc0072e 100644
--- a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
+++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java
@@ -40,16 +40,12 @@
class SplitSelectSystemShortcut extends SystemShortcut<BaseQuickstepLauncher> {
- private final BaseQuickstepLauncher mLauncher;
- private final ItemInfo mItemInfo;
private final SplitPositionOption mPosition;
public SplitSelectSystemShortcut(BaseQuickstepLauncher launcher, ItemInfo itemInfo,
SplitPositionOption position) {
super(position.iconResId, position.textResId, launcher, itemInfo);
- mLauncher = launcher;
- mItemInfo = itemInfo;
mPosition = position;
}
@@ -71,7 +67,7 @@
return;
}
- RecentsView recentsView = mLauncher.getOverviewPanel();
+ RecentsView recentsView = mTarget.getOverviewPanel();
recentsView.initiateSplitSelect(
new SplitSelectSource(view, new BitmapDrawable(bitmap), intent, mPosition));
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index f9c8062..1ccad78 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -15,14 +15,19 @@
*/
package com.android.launcher3.taskbar;
+import android.content.Intent;
+import android.content.pm.LauncherApps;
import android.graphics.Point;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -38,7 +43,9 @@
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.SystemUiProxy;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -151,7 +158,7 @@
mPopupDataProvider.getShortcutCountForItem(item),
mPopupDataProvider.getNotificationKeysForItem(item),
// TODO (b/198438631): add support for INSTALL shortcut factory
- Stream.of(APP_INFO)
+ getSystemShortcuts()
.map(s -> s.getShortcut(context, item))
.filter(Objects::nonNull)
.collect(Collectors.toList()));
@@ -167,6 +174,18 @@
return container;
}
+ // Create a Stream of all applicable system shortcuts
+ // TODO(b/227800345): Add "Split bottom" option when tablet is in portrait mode.
+ private Stream<SystemShortcut.Factory> getSystemShortcuts() {
+ // concat a Stream of split options with a Stream of APP_INFO
+ return Stream.concat(
+ Utilities.getSplitPositionOptions(mContext.getDeviceProfile())
+ .stream()
+ .map(this::createSplitShortcutFactory),
+ Stream.of(APP_INFO)
+ );
+ }
+
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarPopupController:");
@@ -213,4 +232,56 @@
return false;
}
}
+
+ /**
+ * Creates a factory function representing a single "split position" menu item ("Split left,"
+ * "Split right," or "Split top").
+ * @param position A SplitPositionOption representing whether we are splitting top, left, or
+ * right.
+ * @return A factory function to be used in populating the long-press menu.
+ */
+ private SystemShortcut.Factory<BaseTaskbarContext> createSplitShortcutFactory(
+ SplitPositionOption position) {
+ return (context, itemInfo) -> new TaskbarSplitShortcut(context, itemInfo, position);
+ }
+
+ /**
+ * A single menu item ("Split left," "Split right," or "Split top") that executes a split
+ * from the taskbar, as if the user performed a drag and drop split.
+ * Includes an onClick method that initiates the actual split.
+ */
+ private static class TaskbarSplitShortcut extends SystemShortcut<BaseTaskbarContext> {
+ private final SplitPositionOption mPosition;
+
+ TaskbarSplitShortcut(BaseTaskbarContext context, ItemInfo itemInfo,
+ SplitPositionOption position) {
+ super(position.iconResId, position.textResId, context, itemInfo);
+ mPosition = position;
+ }
+
+ @Override
+ public void onClick(View view) {
+ AbstractFloatingView.closeAllOpenViews(mTarget);
+
+ if (mItemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) mItemInfo;
+ SystemUiProxy.INSTANCE.get(mTarget).startShortcut(
+ workspaceItemInfo.getIntent().getPackage(),
+ workspaceItemInfo.getDeepShortcutId(),
+ mPosition.stagePosition,
+ null,
+ workspaceItemInfo.user);
+ } else {
+ SystemUiProxy.INSTANCE.get(mTarget).startIntent(
+ mTarget.getSystemService(LauncherApps.class).getMainActivityLaunchIntent(
+ mItemInfo.getIntent().getComponent(),
+ null,
+ mItemInfo.user),
+ new Intent(),
+ mPosition.stagePosition,
+ null);
+ }
+ }
+ }
}
+
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 9bc3d15..655ab5a 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -18,6 +18,9 @@
import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ICON_BADGED;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
import android.annotation.TargetApi;
import android.app.ActivityManager;
@@ -86,12 +89,14 @@
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@@ -867,4 +872,39 @@
v.getLocationOnScreen(pos);
return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
}
+
+ /**
+ * Returns a list of screen-splitting options depending on the device orientation (split top for
+ * portrait, split left for landscape, split left and right for landscape tablets, etc.)
+ */
+ public static List<SplitPositionOption> getSplitPositionOptions(
+ DeviceProfile dp) {
+ List<SplitPositionOption> options = new ArrayList<>();
+ // Add both left and right options if we're in tablet mode
+ if (dp.isTablet && dp.isLandscape) {
+ options.add(new SplitPositionOption(
+ R.drawable.ic_split_left, R.string.split_screen_position_left,
+ STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
+ options.add(new SplitPositionOption(
+ R.drawable.ic_split_right, R.string.split_screen_position_right,
+ STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
+ } else {
+ if (dp.isSeascape()) {
+ // Add left/right options
+ options.add(new SplitPositionOption(
+ R.drawable.ic_split_right, R.string.split_screen_position_right,
+ STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
+ } else if (dp.isLandscape) {
+ options.add(new SplitPositionOption(
+ R.drawable.ic_split_left, R.string.split_screen_position_left,
+ STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
+ } else {
+ // Only add top option
+ options.add(new SplitPositionOption(
+ R.drawable.ic_split_top, R.string.split_screen_position_top,
+ STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
+ }
+ }
+ return options;
+ }
}
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index d88656c..73c6115 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -29,7 +29,6 @@
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
import android.content.res.Resources;
import android.graphics.Matrix;
@@ -48,7 +47,6 @@
import android.widget.LinearLayout;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
@@ -56,7 +54,6 @@
import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.launcher3.views.BaseDragLayer;
-import java.util.ArrayList;
import java.util.List;
public class PortraitPagedViewHandler implements PagedOrientationHandler {
@@ -406,33 +403,7 @@
@Override
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
- List<SplitPositionOption> options = new ArrayList<>(1);
- // Add both left and right options if we're in tablet mode
- if (dp.isTablet && dp.isLandscape) {
- options.add(new SplitPositionOption(
- R.drawable.ic_split_left, R.string.split_screen_position_left,
- STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
- options.add(new SplitPositionOption(
- R.drawable.ic_split_right, R.string.split_screen_position_right,
- STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
- } else {
- if (dp.isSeascape()) {
- // Add left/right options
- options.add(new SplitPositionOption(
- R.drawable.ic_split_right, R.string.split_screen_position_right,
- STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
- } else if (dp.isLandscape) {
- options.add(new SplitPositionOption(
- R.drawable.ic_split_left, R.string.split_screen_position_left,
- STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
- } else {
- // Only add top option
- options.add(new SplitPositionOption(
- R.drawable.ic_split_top, R.string.split_screen_position_top,
- STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
- }
- }
- return options;
+ return Utilities.getSplitPositionOptions(dp);
}
@Override