Update task menu

- Remove widgets option
- Add Split screen
- Add Pin
- Tap as well as long press icon to show menu

Bug: 72320614
Bug: 70294936
Change-Id: I231160286426ac3d2a23524b2f4a0170f963190e
diff --git a/quickstep/res/drawable/ic_pin.xml b/quickstep/res/drawable/ic_pin.xml
new file mode 100644
index 0000000..8c799e3
--- /dev/null
+++ b/quickstep/res/drawable/ic_pin.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="#FFffffff"
+        android:pathData="M16,12L16,4l1,0L17,2L7,2l0,2l1,0l0,8l-2,2l0,2l5.2,0l0,6l1.6,0l0,-6L18,16l0,-2L16,12z"/>
+</vector>
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_split_screen.xml b/quickstep/res/drawable/ic_split_screen.xml
new file mode 100644
index 0000000..77bd333
--- /dev/null
+++ b/quickstep/res/drawable/ic_split_screen.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="88.0dp"
+        android:height="88.0dp"
+        android:viewportWidth="88.0"
+        android:viewportHeight="88.0" >
+
+    <path
+        android:pathData="M 32,11
+           C 32,11 68,11 68,11
+             76.74,11.06 76.98,12.76 77,21
+             77.01,25.97 78.50,38.23 73.85,40.98
+             71.80,42.19 68.35,42 66,42
+             66,42 22,42 22,42
+             18.82,41.99 14.87,42.38 12.60,39.69
+             10.71,37.44 11.01,33.77 11,31
+             10.99,25.54 9.53,16.08 13.31,12.02
+             18.07,10.21 26.66,11 32,11 Z
+           M 32,46
+           C 32,46 68,46 68,46
+             76.74,46.06 76.98,47.76 77,56
+             77.01,60.97 78.50,73.23 73.85,75.98
+             71.80,77.19 68.35,77 66,77
+             66,77 22,77 22,77
+             18.82,76.99 14.87,77.38 12.60,74.69
+             10.71,72.44 11.01,68.77 11,66
+             10.99,60.54 9.53,51.08 13.31,47.02
+             18.07,45.21 26.66,46 32,46 Z"
+        android:fillColor="@android:color/white" />
+</vector>
\ No newline at end of file
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index ef61226..c2d6604 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -20,4 +20,10 @@
 
     <!-- Application name -->
     <string name="derived_app_name" translatable="false">Quickstep</string>
+
+    <!-- Options for recent tasks -->
+    <!-- Title for an option to enter split screen mode for a given app -->
+    <string name="recent_task_option_split_screen">Split screen</string>
+    <!-- Title for an option to keep an app pinned to the screen until it is unpinned -->
+    <string name="recent_task_option_pin">Pin</string>
 </resources>
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 22658b2..d10c5a6 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -24,6 +24,7 @@
 
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.R;
+import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions;
 import com.android.systemui.shared.recents.model.RecentsTaskLoader;
@@ -66,6 +67,7 @@
     private RecentsTaskLoadPlan mLastLoadPlan;
     private int mLastLoadPlanId;
     private int mTaskChangeId;
+    private ISystemUiProxy mSystemUiProxy;
 
     private RecentsModel(Context context) {
         mContext = context;
@@ -137,4 +139,12 @@
     public RecentsTaskLoadPlan getLastLoadPlan() {
         return mLastLoadPlan;
     }
+
+    public void setSystemUiProxy(ISystemUiProxy systemUiProxy) {
+        mSystemUiProxy = systemUiProxy;
+    }
+
+    public ISystemUiProxy getSystemUiProxy() {
+        return mSystemUiProxy;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskMenuView.java b/quickstep/src/com/android/quickstep/TaskMenuView.java
index 196a227..52b2400 100644
--- a/quickstep/src/com/android/quickstep/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/TaskMenuView.java
@@ -40,7 +40,6 @@
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.shortcuts.DeepShortcutView;
-import com.android.systemui.shared.recents.model.Task;
 
 /**
  * Contains options for a recent task when long-pressing its icon.
@@ -51,9 +50,10 @@
 
     /** Note that these will be shown in order from top to bottom, if available for the task. */
     private static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] {
-            new TaskSystemShortcut.Widgets(),
             new TaskSystemShortcut.AppInfo(),
-            new TaskSystemShortcut.Install()
+            new TaskSystemShortcut.SplitScreen(),
+            new TaskSystemShortcut.Pin(),
+            new TaskSystemShortcut.Install(),
     };
 
     private static final long OPEN_CLOSE_DURATION = 220;
@@ -62,7 +62,6 @@
     private TextView mTaskIconAndName;
     private AnimatorSet mOpenCloseAnimator;
     private TaskView mTaskView;
-    private View mWidgetsOptionView;
 
     public TaskMenuView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -133,21 +132,21 @@
         }
         mLauncher.getDragLayer().addView(this);
         mTaskView = taskView;
-        addMenuOptions(mTaskView.getTask());
+        addMenuOptions(mTaskView);
         orientAroundTaskView(mTaskView);
         post(this::animateOpen);
         return true;
     }
 
-    private void addMenuOptions(Task task) {
-        Drawable icon = task.icon.getConstantState().newDrawable();
+    private void addMenuOptions(TaskView taskView) {
+        Drawable icon = taskView.getTask().icon.getConstantState().newDrawable();
         int iconSize = getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
         icon.setBounds(0, 0, iconSize, iconSize);
         mTaskIconAndName.setCompoundDrawables(null, icon, null, null);
-        mTaskIconAndName.setText(TaskUtils.getTitle(mLauncher, task));
+        mTaskIconAndName.setText(TaskUtils.getTitle(mLauncher, taskView.getTask()));
 
         for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
-            OnClickListener onClickListener = menuOption.getOnClickListener(mLauncher, task);
+            OnClickListener onClickListener = menuOption.getOnClickListener(mLauncher, taskView);
             if (onClickListener != null) {
                 addMenuOption(menuOption, onClickListener);
             }
@@ -161,10 +160,6 @@
         menuOptionView.getBubbleText().setText(menuOption.labelResId);
         menuOptionView.setOnClickListener(onClickListener);
         addView(menuOptionView);
-
-        if (menuOption instanceof TaskSystemShortcut.Widgets) {
-            mWidgetsOptionView = menuOptionView;
-        }
     }
 
     private void orientAroundTaskView(TaskView taskView) {
@@ -231,19 +226,4 @@
             }
         };
     }
-
-    @Override
-    protected void onWidgetsBound() {
-        TaskSystemShortcut widgetsOption = new TaskSystemShortcut.Widgets();
-        View.OnClickListener onClickListener = widgetsOption.getOnClickListener(
-                mLauncher, mTaskView.getTask());
-
-        if (onClickListener != null && mWidgetsOptionView == null) {
-            // We didn't have any widgets cached but now there are some, so add the option.
-            addMenuOption(widgetsOption, onClickListener);
-        } else if (onClickListener == null && mWidgetsOptionView != null) {
-            // No widgets exist, but we previously added the option so remove it.
-            removeView(mWidgetsOptionView);
-        }
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
index 1ba7ce4..9200eeb 100644
--- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
@@ -16,23 +16,37 @@
 
 package com.android.quickstep;
 
+import android.app.ActivityOptions;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
 import android.view.View;
 
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.util.InstantAppResolver;
+import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
+
+import java.util.function.Consumer;
 
 /**
  * Represents a system shortcut that can be shown for a recent task.
  */
 public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut {
 
+    private static final String TAG = "TaskSystemShortcut";
+
     protected T mSystemShortcut;
 
     protected TaskSystemShortcut(T systemShortcut) {
@@ -40,12 +54,18 @@
         mSystemShortcut = systemShortcut;
     }
 
+    protected TaskSystemShortcut(int iconResId, int labelResId) {
+        super(iconResId, labelResId);
+    }
+
     @Override
     public View.OnClickListener getOnClickListener(Launcher launcher, ItemInfo itemInfo) {
         return null;
     }
 
-    public View.OnClickListener getOnClickListener(final Launcher launcher, final Task task) {
+    public View.OnClickListener getOnClickListener(final Launcher launcher, final TaskView view) {
+        Task task = view.getTask();
+
         ShortcutInfo dummyInfo = new ShortcutInfo();
         dummyInfo.intent = new Intent();
         ComponentName component = task.getTopComponent();
@@ -61,19 +81,83 @@
         return mSystemShortcut.getOnClickListener(launcher, dummyInfo);
     }
 
-
-    public static class Widgets extends TaskSystemShortcut<SystemShortcut.Widgets> {
-        public Widgets() {
-            super(new SystemShortcut.Widgets());
-        }
-    }
-
     public static class AppInfo extends TaskSystemShortcut<SystemShortcut.AppInfo> {
         public AppInfo() {
             super(new SystemShortcut.AppInfo());
         }
     }
 
+    public static class SplitScreen extends TaskSystemShortcut {
+
+        private Handler mHandler;
+
+        public SplitScreen() {
+            super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen);
+            mHandler = new Handler(Looper.getMainLooper());
+        }
+
+        @Override
+        public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) {
+            if (launcher.getDeviceProfile().inMultiWindowMode()) {
+                return null;
+            }
+            return (v -> {
+                Task task  = taskView.getTask();
+                final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(true);
+                final Consumer<Boolean> resultCallback = success -> {
+                    if (success) {
+                        launcher.<RecentsView>getOverviewPanel().removeView(taskView);
+                    }
+                };
+                ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(
+                        task.key, options, resultCallback, mHandler);
+
+                // TODO improve transition; see:
+                // DockedFirstAnimationFrameEvent
+                // RecentsTransitionHelper#composeDockAnimationSpec
+                // WindowManagerWrapper#overridePendingAppTransitionMultiThumbFuture
+            });
+        }
+    }
+
+    public static class Pin extends TaskSystemShortcut {
+
+        // Same as Settings.System.LOCK_TO_APP_ENABLED, which is hidden.
+        // TODO use call from shared lib instead
+        private static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
+
+        private Handler mHandler;
+
+        public Pin() {
+            super(R.drawable.ic_pin, R.string.recent_task_option_pin);
+            mHandler = new Handler(Looper.getMainLooper());
+        }
+
+        @Override
+        public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) {
+            ISystemUiProxy sysUiProxy = RecentsModel.getInstance(launcher).getSystemUiProxy();
+            if (sysUiProxy == null) {
+                return null;
+            }
+            if (Settings.System.getInt(launcher.getContentResolver(),
+                    LOCK_TO_APP_ENABLED, 0) == 0) {
+                return null;
+            }
+            return view -> {
+                Consumer<Boolean> resultCallback = success -> {
+                    if (success) {
+                        try {
+                            sysUiProxy.startScreenPinning(taskView.getTask().key.id);
+                        } catch (RemoteException e) {
+                            Log.w(TAG, "Failed to start screen pinning: ", e);
+                        }
+                    }
+                };
+                taskView.launchTask(true, resultCallback, mHandler);
+            };
+        }
+    }
+
     public static class Install extends TaskSystemShortcut<SystemShortcut.Install> {
         public Install() {
             super(new SystemShortcut.Install());
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index 46fcc72..6a70e2d 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -26,6 +26,7 @@
 import android.content.res.Resources;
 import android.graphics.Outline;
 import android.graphics.Rect;
+import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.Property;
 import android.view.View;
@@ -36,7 +37,6 @@
 import com.android.launcher3.R;
 import com.android.quickstep.RecentsView.PageCallbacks;
 import com.android.quickstep.RecentsView.ScrollState;
-import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -47,6 +47,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * A task in the Recents view.
@@ -127,6 +128,11 @@
     }
 
     public void launchTask(boolean animate) {
+        launchTask(animate, null, null);
+    }
+
+    public void launchTask(boolean animate, Consumer<Boolean> resultCallback,
+            Handler resultCallbackHandler) {
         if (mTask != null) {
             final ActivityOptions opts;
             if (animate) {
@@ -154,7 +160,7 @@
                 opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0);
             }
             ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
-                    opts, null, null);
+                    opts, resultCallback, resultCallbackHandler);
         }
     }
 
@@ -162,6 +168,7 @@
     public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
         mSnapshotView.setThumbnail(task, thumbnailData);
         mIconView.setImageDrawable(task.icon);
+        mIconView.setOnClickListener(icon -> TaskMenuView.showForTask(this));
         mIconView.setOnLongClickListener(icon -> TaskMenuView.showForTask(this));
     }
 
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 0490832..67146ff 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -110,6 +110,7 @@
         @Override
         public void onBind(ISystemUiProxy iSystemUiProxy) {
             mISystemUiProxy = iSystemUiProxy;
+            mRecentsModel.setSystemUiProxy(mISystemUiProxy);
         }
 
         @Override