Merge "[OneSearch] Add onesearch plugin api to trigger image from URL." into sc-v2-dev
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 6af0d60..88c98c0 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -193,6 +193,8 @@
     <string name="action_split">Split</string>
     <!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
     <string name="toast_split_select_app">Tap another app to use splitscreen</string>
+    <!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
+    <string name="toast_split_app_unsupported">App does not support split-screen.</string>
     <!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
     <string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string>
 
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
index 080633a..56945ba 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
@@ -16,33 +16,25 @@
 package com.android.launcher3.hybridhotseat;
 
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
+import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
+import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction;
+import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;
 
 import android.app.prediction.AppTarget;
 import android.app.prediction.AppTargetEvent;
-import android.app.prediction.AppTargetId;
-import android.content.ComponentName;
 import android.content.Context;
 import android.os.Bundle;
 
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.shortcuts.ShortcutKey;
 
 import java.util.ArrayList;
-import java.util.Locale;
 
 /**
  * Model helper for app predictions in workspace
  */
 public class HotseatPredictionModel {
-    private static final String APP_LOCATION_HOTSEAT = "hotseat";
-    private static final String APP_LOCATION_WORKSPACE = "workspace";
-
     private static final String BUNDLE_KEY_PIN_EVENTS = "pin_events";
     private static final String BUNDLE_KEY_CURRENT_ITEMS = "current_items";
 
@@ -54,15 +46,15 @@
         ArrayList<AppTargetEvent> events = new ArrayList<>();
         ArrayList<ItemInfo> workspaceItems = dataModel.getAllWorkspaceItems();
         for (ItemInfo item : workspaceItems) {
-            AppTarget target = getAppTargetFromInfo(context, item);
-            if (target != null && !isTrackedForPrediction(item)) continue;
-            events.add(wrapAppTargetWithLocation(target, AppTargetEvent.ACTION_PIN, item));
+            AppTarget target = getAppTargetFromItemInfo(context, item);
+            if (target != null && !isTrackedForHotseatPrediction(item)) continue;
+            events.add(wrapAppTargetWithItemLocation(target, AppTargetEvent.ACTION_PIN, item));
         }
         ArrayList<AppTarget> currentTargets = new ArrayList<>();
         FixedContainerItems hotseatItems = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION);
         if (hotseatItems != null) {
             for (ItemInfo itemInfo : hotseatItems.items) {
-                AppTarget target = getAppTargetFromInfo(context, itemInfo);
+                AppTarget target = getAppTargetFromItemInfo(context, itemInfo);
                 if (target != null) currentTargets.add(target);
             }
         }
@@ -70,56 +62,4 @@
         bundle.putParcelableArrayList(BUNDLE_KEY_CURRENT_ITEMS, currentTargets);
         return bundle;
     }
-
-    /**
-     * Creates and returns for {@link AppTarget} object given an {@link ItemInfo}. Returns null
-     * if item is not supported prediction
-     */
-    public static AppTarget getAppTargetFromInfo(Context context, ItemInfo info) {
-        if (info == null) return null;
-        if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
-                && info instanceof LauncherAppWidgetInfo
-                && ((LauncherAppWidgetInfo) info).providerName != null) {
-            ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
-            return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
-                    cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
-        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
-                && info.getTargetComponent() != null) {
-            ComponentName cn = info.getTargetComponent();
-            return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
-                    cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
-        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
-                && info instanceof WorkspaceItemInfo) {
-            ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
-            //TODO: switch to using full shortcut info
-            return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
-                    shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
-        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
-            return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
-                    context.getPackageName(), info.user).build();
-        }
-        return null;
-    }
-
-    /**
-     * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item
-     * location using {@link ItemInfo}
-     */
-    public static AppTargetEvent wrapAppTargetWithLocation(
-            AppTarget target, int action, ItemInfo info) {
-        String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]",
-                info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
-                        ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE,
-                info.screenId, info.cellX, info.cellY, info.spanX, info.spanY);
-        return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build();
-    }
-
-    /**
-     * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors
-     */
-    public static boolean isTrackedForPrediction(ItemInfo info) {
-        return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || (
-                info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP
-                        && info.screenId == Workspace.FIRST_SCREEN_ID);
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index b665db6..1305bbc 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -22,6 +22,7 @@
 
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED;
@@ -35,6 +36,8 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
+import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction;
+import static com.android.launcher3.model.PredictionHelper.isTrackedForWidgetPrediction;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
 import android.annotation.TargetApi;
@@ -62,7 +65,6 @@
 import com.android.launcher3.logger.LauncherAtom.HotseatContainer;
 import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer;
 import com.android.launcher3.logging.StatsLogManager.EventEnum;
-import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer;
@@ -141,6 +143,9 @@
             if (isTrackedForHotseatPrediction(mLastDragItem)) {
                 sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION);
             }
+            if (isTrackedForWidgetPrediction(atomInfo)) {
+                sendEvent(atomInfo, ACTION_PIN, CONTAINER_WIDGETS_PREDICTION);
+            }
             mLastDragItem = null;
         } else if (event == LAUNCHER_ITEM_DROP_FOLDER_CREATED) {
             if (isTrackedForHotseatPrediction(atomInfo)) {
@@ -158,12 +163,15 @@
             if (mLastDragItem != null && isTrackedForHotseatPrediction(mLastDragItem)) {
                 sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION);
             }
+            if (mLastDragItem != null && isTrackedForWidgetPrediction(mLastDragItem)) {
+                sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_WIDGETS_PREDICTION);
+            }
         } else if (event == LAUNCHER_HOTSEAT_PREDICTION_PINNED) {
             if (isTrackedForHotseatPrediction(atomInfo)) {
                 sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION);
             }
         } else if (event == LAUNCHER_ONRESUME) {
-            AppTarget target = new AppTarget.Builder(new AppTargetId("id:launcher"),
+            AppTarget target = new AppTarget.Builder(new AppTargetId("launcher:launcher"),
                     mContext.getPackageName(), Process.myUserHandle())
                     .build();
             sendEvent(target, atomInfo, ACTION_LAUNCH, CONTAINER_PREDICTION);
@@ -302,19 +310,4 @@
         return TextUtils.isEmpty(componentNameString)
                 ? null : ComponentName.unflattenFromString(componentNameString);
     }
-
-    /**
-     * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors
-     */
-    private static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) {
-        ContainerInfo ci = info.getContainerInfo();
-        switch (ci.getContainerCase()) {
-            case HOTSEAT:
-                return true;
-            case WORKSPACE:
-                return ci.getWorkspace().getPageIndex() == 0;
-            default:
-                return false;
-        }
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/model/PredictionHelper.java b/quickstep/src/com/android/launcher3/model/PredictionHelper.java
new file mode 100644
index 0000000..738dd83
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/model/PredictionHelper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+package com.android.launcher3.model;
+
+import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.WORKSPACE;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
+import android.content.ComponentName;
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.shortcuts.ShortcutKey;
+
+import java.util.Locale;
+
+/** Helper class with methods for converting launcher items to form usable by predictors */
+public final class PredictionHelper {
+    private static final String APP_LOCATION_HOTSEAT = "hotseat";
+    private static final String APP_LOCATION_WORKSPACE = "workspace";
+
+    /**
+     * Creates and returns an {@link AppTarget} object for an {@link ItemInfo}. Returns null
+     * if item type is not supported in predictions
+     */
+    @Nullable
+    public static AppTarget getAppTargetFromItemInfo(Context context, ItemInfo info) {
+        if (info == null) return null;
+        if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+                && info instanceof LauncherAppWidgetInfo
+                && ((LauncherAppWidgetInfo) info).providerName != null) {
+            ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
+            return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
+                    cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
+        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+                && info.getTargetComponent() != null) {
+            ComponentName cn = info.getTargetComponent();
+            return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
+                    cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
+        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+                && info instanceof WorkspaceItemInfo) {
+            ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
+            //TODO: switch to using full shortcut info
+            return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
+                    shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
+        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+            return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
+                    context.getPackageName(), info.user).build();
+        }
+        return null;
+    }
+
+    /**
+     * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item
+     * location using {@link ItemInfo}
+     */
+    public static AppTargetEvent wrapAppTargetWithItemLocation(
+            AppTarget target, int action, ItemInfo info) {
+        String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]",
+                info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
+                        ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE,
+                info.screenId, info.cellX, info.cellY, info.spanX, info.spanY);
+        return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build();
+    }
+
+    /**
+     * Helper method to determine if {@link ItemInfo} should be tracked and reported to hotseat
+     * predictors
+     */
+    public static boolean isTrackedForHotseatPrediction(ItemInfo info) {
+        return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || (
+                info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP
+                        && info.screenId == Workspace.FIRST_SCREEN_ID);
+    }
+
+    /**
+     * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported to
+     * hotseat predictors
+     */
+    public static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) {
+        LauncherAtom.ContainerInfo ci = info.getContainerInfo();
+        switch (ci.getContainerCase()) {
+            case HOTSEAT:
+                return true;
+            case WORKSPACE:
+                return ci.getWorkspace().getPageIndex() == 0;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Helper method to determine if {@link ItemInfo} should be tracked and reported to widget
+     * predictors
+     */
+    public static boolean isTrackedForWidgetPrediction(ItemInfo info) {
+        return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+                && info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP;
+    }
+
+    /**
+     * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported
+     * to widget predictors
+     */
+    public static boolean isTrackedForWidgetPrediction(LauncherAtom.ItemInfo info) {
+        return info.getItemCase() == LauncherAtom.ItemInfo.ItemCase.WIDGET
+                && info.getContainerInfo().getContainerCase() == WORKSPACE;
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 55a140d..7794d27 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -25,8 +25,12 @@
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
 import static com.android.launcher3.Utilities.getDevicePrefs;
 import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle;
+import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
+import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import static java.util.stream.Collectors.toCollection;
+
 import android.app.StatsManager;
 import android.app.prediction.AppPredictionContext;
 import android.app.prediction.AppPredictionManager;
@@ -39,6 +43,7 @@
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
 import android.content.pm.ShortcutInfo;
+import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.StatsEvent;
@@ -62,6 +67,7 @@
 import com.android.quickstep.logging.StatsLogCompatManager;
 import com.android.systemui.shared.system.SysUiStatsLog;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -75,6 +81,7 @@
 
     public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
     private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS";
+    private static final String BUNDLE_KEY_ADDED_APP_WIDGETS = "added_app_widgets";
     private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20;
 
     private static final boolean IS_DEBUG = false;
@@ -272,6 +279,7 @@
         registerWidgetsPredictor(apm.createAppPredictionSession(
                 new AppPredictionContext.Builder(context)
                         .setUiSurface("widgets")
+                        .setExtras(getBundleForWidgetsOnWorkspace(context, mDataModel))
                         .setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION)
                         .build()));
     }
@@ -306,12 +314,41 @@
     }
 
     private void onAppTargetEvent(AppTargetEvent event, int client) {
-        PredictorState state = client == CONTAINER_PREDICTION ? mAllAppsState : mHotseatState;
+        PredictorState state;
+        switch(client) {
+            case CONTAINER_PREDICTION:
+                state = mAllAppsState;
+                break;
+            case CONTAINER_WIDGETS_PREDICTION:
+                state = mWidgetsRecommendationState;
+                break;
+            case CONTAINER_HOTSEAT_PREDICTION:
+            default:
+                state = mHotseatState;
+                break;
+        }
         if (state.predictor != null) {
             state.predictor.notifyAppTargetEvent(event);
         }
     }
 
+    private Bundle getBundleForWidgetsOnWorkspace(Context context, BgDataModel dataModel) {
+        Bundle bundle = new Bundle();
+        ArrayList<AppTargetEvent> widgetEvents =
+                dataModel.getAllWorkspaceItems().stream()
+                        .filter(PredictionHelper::isTrackedForWidgetPrediction)
+                        .map(item -> {
+                            AppTarget target = getAppTargetFromItemInfo(context, item);
+                            if (target == null) return null;
+                            return wrapAppTargetWithItemLocation(
+                                    target, AppTargetEvent.ACTION_PIN, item);
+                        })
+                        .filter(Objects::nonNull)
+                        .collect(toCollection(ArrayList::new));
+        bundle.putParcelableArrayList(BUNDLE_KEY_ADDED_APP_WIDGETS, widgetEvents);
+        return bundle;
+    }
+
     static class PredictorState {
 
         public final FixedContainerItems items;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 8ae661f..172b396 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -70,7 +70,6 @@
 import com.android.launcher3.views.ActivityContext;
 import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.SysUINavigationMode.Mode;
-import com.android.quickstep.SystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -158,7 +157,8 @@
                 new TaskbarKeyguardController(this),
                 new StashedHandleViewController(this, stashedHandleView),
                 new TaskbarStashController(this),
-                new TaskbarEduController(this));
+                new TaskbarEduController(this),
+                new TaskbarAutohideSuspendController(this));
     }
 
     public void init(TaskbarSharedState sharedState) {
@@ -375,7 +375,8 @@
      * Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
      */
     public void setTaskbarWindowFullscreen(boolean fullscreen) {
-        SystemUiProxy.INSTANCE.getNoCreate().notifyTaskbarAutohideSuspend(fullscreen);
+        mControllers.taskbarAutohideSuspendController.updateFlag(
+                TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen);
         mIsFullscreen = fullscreen;
         setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
new file mode 100644
index 0000000..e42f83d
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+package com.android.launcher3.taskbar;
+
+import androidx.annotation.IntDef;
+
+import com.android.quickstep.SystemUiProxy;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Normally Taskbar will auto-hide when entering immersive (fullscreen) apps. This controller allows
+ * us to suspend that behavior in certain cases (e.g. opening a Folder or dragging an icon).
+ */
+public class TaskbarAutohideSuspendController {
+
+    public static final int FLAG_AUTOHIDE_SUSPEND_FULLSCREEN = 1 << 0;
+    public static final int FLAG_AUTOHIDE_SUSPEND_DRAGGING = 1 << 1;
+    @IntDef(flag = true, value = {
+            FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
+            FLAG_AUTOHIDE_SUSPEND_DRAGGING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AutohideSuspendFlag {}
+
+    private final SystemUiProxy mSystemUiProxy;
+
+    private @AutohideSuspendFlag int mAutohideSuspendFlags = 0;
+
+    public TaskbarAutohideSuspendController(TaskbarActivityContext activity) {
+        mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
+    }
+
+    public void onDestroy() {
+        mSystemUiProxy.notifyTaskbarAutohideSuspend(false);
+    }
+
+    /**
+     * Adds or removes the given flag, then notifies system UI proxy whether to suspend auto-hide.
+     */
+    public void updateFlag(@AutohideSuspendFlag int flag, boolean enabled) {
+        if (enabled) {
+            mAutohideSuspendFlags |= flag;
+        } else {
+            mAutohideSuspendFlags &= ~flag;
+        }
+        mSystemUiProxy.notifyTaskbarAutohideSuspend(mAutohideSuspendFlags != 0);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 8684c29..7b0053e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -37,6 +37,7 @@
     public final StashedHandleViewController stashedHandleViewController;
     public final TaskbarStashController taskbarStashController;
     public final TaskbarEduController taskbarEduController;
+    public final TaskbarAutohideSuspendController taskbarAutohideSuspendController;
 
     /** Do not store this controller, as it may change at runtime. */
     @NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT;
@@ -53,7 +54,8 @@
             TaskbarKeyguardController taskbarKeyguardController,
             StashedHandleViewController stashedHandleViewController,
             TaskbarStashController taskbarStashController,
-            TaskbarEduController taskbarEduController) {
+            TaskbarEduController taskbarEduController,
+            TaskbarAutohideSuspendController taskbarAutoHideSuspendController) {
         this.taskbarActivityContext = taskbarActivityContext;
         this.taskbarDragController = taskbarDragController;
         this.navButtonController = navButtonController;
@@ -67,6 +69,7 @@
         this.stashedHandleViewController = stashedHandleViewController;
         this.taskbarStashController = taskbarStashController;
         this.taskbarEduController = taskbarEduController;
+        this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController;
     }
 
     /**
@@ -75,6 +78,7 @@
      * in constructors for now, as some controllers may still be waiting for init().
      */
     public void init(TaskbarSharedState sharedState) {
+        taskbarDragController.init(this);
         navbarButtonsViewController.init(this, sharedState);
         if (taskbarActivityContext.isThreeButtonNav()) {
             rotationButtonController.init();
@@ -101,5 +105,6 @@
         taskbarUnfoldAnimationController.onDestroy();
         taskbarViewController.onDestroy();
         stashedHandleViewController.onDestroy();
+        taskbarAutohideSuspendController.onDestroy();
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 1afbd17..3bcacb6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -15,9 +15,6 @@
  */
 package com.android.launcher3.taskbar;
 
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
-
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Intent;
@@ -49,7 +46,6 @@
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.graphics.DragPreviewProvider;
-import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -65,6 +61,9 @@
     private final int mDragIconSize;
     private final int[] mTempXY = new int[2];
 
+    // Initialized in init.
+    TaskbarControllers mControllers;
+
     // Where the initial touch was relative to the dragged icon.
     private int mRegistrationX;
     private int mRegistrationY;
@@ -77,6 +76,10 @@
         mDragIconSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_drag_icon_size);
     }
 
+    public void init(TaskbarControllers controllers) {
+        mControllers = controllers;
+    }
+
     /**
      * Attempts to start a system drag and drop operation for the given View, using its tag to
      * generate the ClipDescription and Intent.
@@ -90,19 +93,17 @@
         BubbleTextView btv = (BubbleTextView) view;
 
         mActivity.setTaskbarWindowFullscreen(true);
-        view.post(() -> {
+        btv.post(() -> {
             startInternalDrag(btv);
-            btv.setVisibility(INVISIBLE);
+            btv.getIcon().setIsDisabled(true);
+            mControllers.taskbarAutohideSuspendController.updateFlag(
+                    TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, true);
         });
         return true;
     }
 
     private void startInternalDrag(BubbleTextView btv) {
-        float iconScale = 1f;
-        Drawable icon = btv.getIcon();
-        if (icon instanceof FastBitmapDrawable) {
-            iconScale = ((FastBitmapDrawable) icon).getAnimatedScale();
-        }
+        float iconScale = btv.getIcon().getAnimatedScale();
 
         // Clear the pressed state if necessary
         btv.clearFocus();
@@ -239,16 +240,17 @@
                 shadowSize.set(mDragIconSize, mDragIconSize);
                 // The registration point was taken before the icon scaled to mDragIconSize, so
                 // offset the registration to where the touch is on the new size.
-                int offset = (mDragIconSize - btv.getIconSize()) / 2;
-                shadowTouchPoint.set(mRegistrationX + offset, mRegistrationY + offset);
+                int offsetX = (mDragIconSize - mDragObject.dragView.getDragRegionWidth()) / 2;
+                int offsetY = (mDragIconSize - mDragObject.dragView.getDragRegionHeight()) / 2;
+                shadowTouchPoint.set(mRegistrationX + offsetX, mRegistrationY + offsetY);
             }
 
             @Override
             public void onDrawShadow(Canvas canvas) {
                 canvas.save();
-                float scale = (float) mDragIconSize / btv.getIconSize();
+                float scale = mDragObject.dragView.getScaleX();
                 canvas.scale(scale, scale);
-                btv.getIcon().draw(canvas);
+                mDragObject.dragView.draw(canvas);
                 canvas.restore();
             }
         };
@@ -330,7 +332,9 @@
 
     private void maybeOnDragEnd() {
         if (!isDragging()) {
-            ((View) mDragObject.originalView).setVisibility(VISIBLE);
+            ((BubbleTextView) mDragObject.originalView).getIcon().setIsDisabled(false);
+            mControllers.taskbarAutohideSuspendController.updateFlag(
+                    TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, false);
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index e2441ed..73d1424 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -59,7 +59,6 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 import android.view.Surface;
 
@@ -581,8 +580,7 @@
             final Info displayInfo = mDisplayController.getInfo();
             return (mRotationTouchHelper.touchInOneHandedModeRegion(ev)
                 && displayInfo.rotation != Surface.ROTATION_90
-                && displayInfo.rotation != Surface.ROTATION_270
-                && displayInfo.densityDpi < DisplayMetrics.DENSITY_600);
+                && displayInfo.rotation != Surface.ROTATION_270);
         }
         return false;
     }
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index a59b0d7..81e18f6 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -274,7 +274,6 @@
                 mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle);
         subtitle.setText(subtitleResId);
         if (isGestureSuccessful) {
-            hideCloseButton();
             if (mTutorialFragment.isAtFinalStep()) {
                 showActionButton();
             }
@@ -402,6 +401,7 @@
     void transitToController() {
         hideFeedback();
         hideActionButton();
+        updateCloseButton();
         updateSubtext();
         updateDrawables();
         updateLayout();
@@ -412,26 +412,21 @@
         }
     }
 
-    void hideCloseButton() {
-        mCloseButton.setVisibility(GONE);
-    }
-
-    void showCloseButton() {
-        mCloseButton.setVisibility(View.VISIBLE);
+    void updateCloseButton() {
         mCloseButton.setTextAppearance(Utilities.isDarkTheme(mContext)
                 ? R.style.TextAppearance_GestureTutorial_Feedback_Subtext
                 : R.style.TextAppearance_GestureTutorial_Feedback_Subtext_Dark);
     }
 
     void hideActionButton() {
-        showCloseButton();
+        mCloseButton.setVisibility(View.VISIBLE);
         // Invisible to maintain the layout.
         mActionButton.setVisibility(View.INVISIBLE);
         mActionButton.setOnClickListener(null);
     }
 
     void showActionButton() {
-        hideCloseButton();
+        mCloseButton.setVisibility(GONE);
         mActionButton.setVisibility(View.VISIBLE);
         mActionButton.setOnClickListener(this::onActionButtonClicked);
     }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5a455c1..687a13a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -599,6 +599,8 @@
     private SplitConfigurationOptions.StagedSplitBounds mSplitBoundsConfig;
     private final Toast mSplitToast = Toast.makeText(getContext(),
             R.string.toast_split_select_app, Toast.LENGTH_SHORT);
+    private final Toast mSplitUnsupportedToast = Toast.makeText(getContext(),
+            R.string.toast_split_app_unsupported, Toast.LENGTH_SHORT);
 
     /**
      * Keeps track of the index of the TaskView that split screen was initialized with so we know
@@ -3878,6 +3880,11 @@
 
     public void confirmSplitSelect(TaskView taskView) {
         mSplitToast.cancel();
+        if (!taskView.getTask().isDockable) {
+            // Task not split screen supported
+            mSplitUnsupportedToast.show();
+            return;
+        }
         RectF secondTaskStartingBounds = new RectF();
         Rect secondTaskEndingBounds = new Rect();
         // TODO(194414938) starting bounds seem slightly off, investigate
@@ -3920,6 +3927,7 @@
         int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
         PendingAnimation pendingAnim = new PendingAnimation(duration);
         mSplitToast.cancel();
+        mSplitUnsupportedToast.cancel();
         if (!animate) {
             resetFromSplitSelectionState();
             return pendingAnim;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 03ab737..5c73fbb 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -210,7 +210,7 @@
 
     @Override
     public void onScrollChanged() {
-        RecentsView rv = mTaskView.getRecentsView();
+        RecentsView rv = mActivity.getOverviewPanel();
         setPosition(mTaskView.getX() - rv.getScrollX(), mTaskView.getY() - rv.getScrollY(),
                 rv.getOverScrollShift());
     }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 710afe0..4895b10 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -43,7 +43,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -289,7 +288,6 @@
 
     @Test
     @PortraitLandscape
-    @Ignore("b/203781041")
     public void testOverviewForTablet() throws Exception {
         if (!mLauncher.isTablet()) {
             return;
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index eb42a65..9fb14f6 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -275,8 +275,12 @@
     @Override
     protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
-        if (TestProtocol.sDebugTracing && visibility == VISIBLE) {
-            Log.d(TestProtocol.NO_DROP_TARGET, "9");
+        if (TestProtocol.sDebugTracing) {
+            if (visibility == VISIBLE) {
+                Log.d(TestProtocol.NO_DROP_TARGET, "9");
+            } else {
+                Log.d(TestProtocol.NO_DROP_TARGET, "Hiding drop target", new Exception());
+            }
         }
     }
 }
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 33ab0d2..9774c46 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -40,6 +40,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.core.content.ContextCompat;
 
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
@@ -220,6 +221,11 @@
             Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
             return null;
         } else {
+            AbstractFloatingView floatingView = AbstractFloatingView.getTopOpenViewWithType(
+                    launcher, TYPE_WIDGETS_FULL_SHEET);
+            if (floatingView != null) {
+                return (WidgetsFullSheet) floatingView;
+            }
             return WidgetsFullSheet.show(launcher, true /* animated */);
         }
     }
@@ -279,7 +285,7 @@
         public final OnLongClickListener clickListener;
 
         public OptionItem(Context context, int labelRes, int iconRes, EventEnum eventId,
-                          OnLongClickListener clickListener) {
+                OnLongClickListener clickListener) {
             this.labelRes = labelRes;
             this.label = context.getText(labelRes);
             this.icon = ContextCompat.getDrawable(context, iconRes);
@@ -288,7 +294,7 @@
         }
 
         public OptionItem(CharSequence label, Drawable icon, EventEnum eventId,
-                          OnLongClickListener clickListener) {
+                OnLongClickListener clickListener) {
             this.labelRes = 0;
             this.label = label;
             this.icon = icon;
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 0e3b501..d5479fb 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -54,18 +54,14 @@
     }
 
     private void flingForwardImpl() {
-        flingForwardImpl(0);
-    }
-
-    private void flingForwardImpl(int rightMargin) {
         try (LauncherInstrumentation.Closable c =
                      mLauncher.addContextLayer("want to fling forward in overview")) {
             LauncherInstrumentation.log("Overview.flingForward before fling");
             final UiObject2 overview = verifyActiveContainer();
             final int leftMargin =
                     mLauncher.getTargetInsets().left + mLauncher.getEdgeSensitivityWidth();
-            mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, rightMargin, 0),
-                    20, false);
+            mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, 0, 0), 20,
+                    false);
             try (LauncherInstrumentation.Closable c2 =
                          mLauncher.addContextLayer("flung forwards")) {
                 verifyActiveContainer();
@@ -131,7 +127,7 @@
 
             OverviewTask task = getCurrentTask();
             mLauncher.assertNotNull("current task is null", task);
-            flingForwardImpl(task.getTaskCenterX());
+            mLauncher.scrollLeftByDistance(verifyActiveContainer(), task.getVisibleWidth());
 
             try (LauncherInstrumentation.Closable c2 =
                          mLauncher.addContextLayer("scrolled task off screen")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 9ee0e25..7ffdf4c 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1190,10 +1190,19 @@
         return getVisibleBounds(container).bottom - bottomGestureStartOnScreen;
     }
 
+    int getRightGestureMarginInContainer(UiObject2 container) {
+        final int rightGestureStartOnScreen = getRightGestureStartOnScreen();
+        return getVisibleBounds(container).right - rightGestureStartOnScreen;
+    }
+
     int getBottomGestureStartOnScreen() {
         return getRealDisplaySize().y - getBottomGestureSize();
     }
 
+    int getRightGestureStartOnScreen() {
+        return getRealDisplaySize().x - getWindowInsets().right;
+    }
+
     void clickLauncherObject(UiObject2 object) {
         waitForObjectEnabled(object, "clickLauncherObject");
         expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_TOUCH_DOWN);
@@ -1235,6 +1244,21 @@
                 true);
     }
 
+    void scrollLeftByDistance(UiObject2 container, int distance) {
+        final Rect containerRect = getVisibleBounds(container);
+        final int rightGestureMarginInContainer = getRightGestureMarginInContainer(container);
+        scroll(
+                container,
+                Direction.LEFT,
+                new Rect(
+                        0,
+                        containerRect.width() - distance - rightGestureMarginInContainer,
+                        0,
+                        rightGestureMarginInContainer),
+                10,
+                true);
+    }
+
     void scroll(
             UiObject2 container, Direction direction, Rect margins, int steps, boolean slowDown) {
         final Rect rect = getVisibleBounds(container);
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 15bddd7..a860e7d 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -53,6 +53,10 @@
         return mTask.getVisibleBounds().height();
     }
 
+    int getVisibleWidth() {
+        return mTask.getVisibleBounds().width();
+    }
+
     int getTaskCenterX() {
         return mTask.getVisibleCenter().x;
     }