Overview actions - adds feature flag and base class for Overview Actions.

Adds ENABLE_OVERVIEW_ACTIONS feature flag and base factory. Requires an
implementation in overlay to show any actions.

Test: run locally with flag on and off.
Bug: 145628186

Change-Id: I1c36330464cc01e1e987ebfea1a9f451067598a5
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
index ed5dba1..bd37e56 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -44,6 +44,7 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.quickstep.SysUINavigationMode;
@@ -140,6 +141,10 @@
         if (launcher.getDeviceProfile().isVerticalBarLayout()) {
             return VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON;
         } else {
+            if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
+                return VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON;
+            }
+
             boolean hasAllAppsHeaderExtra = launcher.getAppsView() != null
                     && launcher.getAppsView().getFloatingHeaderView().hasVisibleContent();
             return HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON |
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewActionsFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewActionsFactory.java
new file mode 100644
index 0000000..6d17b27
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewActionsFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.quickstep;
+
+import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ResourceBasedOverride;
+
+/**
+ * Overview actions are shown in overview underneath the task snapshot. This factory class is
+ * overrideable in an overlay. The {@link OverviewActions} class provides the view that should be
+ * shown in the Overview.
+ */
+public class OverviewActionsFactory implements ResourceBasedOverride {
+
+    public static final MainThreadInitializedObject<OverviewActionsFactory> INSTANCE =
+            forOverride(OverviewActionsFactory.class, R.string.overview_actions_factory_class);
+
+    /** Create a new Overview Actions for interacting between the actions and overview. */
+    public OverviewActions createOverviewActions() {
+        return new OverviewActions();
+    }
+
+    /** Overlay overrideable, base class does nothing. */
+    public static class OverviewActions {
+        /** Get the view to show in the overview. */
+        public View getView() {
+            return null;
+        }
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index b602cea..a8d88b9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -111,6 +111,7 @@
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.ViewUtils;
 import com.android.quickstep.util.AppWindowAnimationHelper;
+import com.android.quickstep.util.LayoutUtils;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -344,8 +345,7 @@
         setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
         mTaskTopMargin = getResources()
                 .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
-        mTaskBottomMargin = getResources().getDimensionPixelSize(
-                R.dimen.task_thumbnail_bottom_margin);
+        mTaskBottomMargin = LayoutUtils.thumbnailBottomMargin(getResources());
         mSquaredTouchSlop = squaredTouchSlop(context);
 
         mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 0bfde64..94cec72 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -47,11 +47,14 @@
 import android.widget.FrameLayout;
 import android.widget.Toast;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -59,11 +62,13 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.util.PendingAnimation;
 import com.android.launcher3.util.ViewPool.Reusable;
+import com.android.quickstep.OverviewActionsFactory;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TaskIconCache;
 import com.android.quickstep.TaskOverlayFactory;
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
+import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.TaskCornerRadius;
 import com.android.quickstep.views.RecentsView.PageCallbacks;
 import com.android.quickstep.views.RecentsView.ScrollState;
@@ -159,6 +164,9 @@
     private final float mWindowCornerRadius;
     private final BaseDraggingActivity mActivity;
 
+    private OverviewActionsFactory.OverviewActions mOverviewActions;
+    @Nullable private View mActionsView;
+
     private ObjectAnimator mIconAndDimAnimator;
     private float mIconScaleAnimStartProgress = 0;
     private float mFocusTransitionProgress = 1;
@@ -214,6 +222,7 @@
         mCurrentFullscreenParams = new FullscreenDrawParams(mCornerRadius);
         mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
 
+        mOverviewActions = OverviewActionsFactory.INSTANCE.get(context).createOverviewActions();
         mOutlineProvider = new TaskOutlineProvider(getResources(), mCurrentFullscreenParams);
         setOutlineProvider(mOutlineProvider);
     }
@@ -223,6 +232,21 @@
         super.onFinishInflate();
         mSnapshotView = findViewById(R.id.snapshot);
         mIconView = findViewById(R.id.icon);
+
+        TaskView.LayoutParams thumbnailParams = (LayoutParams) mSnapshotView.getLayoutParams();
+        thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(getResources());
+        mSnapshotView.setLayoutParams(thumbnailParams);
+
+
+        if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
+            mActionsView = mOverviewActions.getView();
+            if (mActionsView != null) {
+                TaskView.LayoutParams params = new TaskView.LayoutParams(LayoutParams.MATCH_PARENT,
+                        getResources().getDimensionPixelSize(R.dimen.overview_actions_height),
+                        Gravity.BOTTOM);
+                addView(mActionsView, params);
+            }
+        }
     }
 
     public TaskMenuView getMenuView() {
@@ -422,6 +446,10 @@
         mIconView.setScaleX(scale);
         mIconView.setScaleY(scale);
 
+        if (mActionsView != null) {
+            mActionsView.setAlpha(scale);
+        }
+
         mFooterVerticalOffset = 1.0f - scale;
         for (FooterWrapper footer : mFooters) {
             if (footer != null) {
@@ -626,7 +654,7 @@
 
         TaskOutlineProvider(Resources res, FullscreenDrawParams fullscreenParams) {
             mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
-            mMarginBottom = res.getDimensionPixelSize(R.dimen.task_thumbnail_bottom_margin);
+            mMarginBottom = LayoutUtils.thumbnailBottomMargin(res);
             mFullscreenParams = fullscreenParams;
         }
 
@@ -783,6 +811,7 @@
 
     /**
      * Hides the icon and shows insets when this TaskView is about to be shown fullscreen.
+     *
      * @param progress: 0 = show icon and no insets; 1 = don't show icon and show full insets.
      */
     public void setFullscreenProgress(float progress) {
@@ -793,6 +822,9 @@
         mFullscreenProgress = progress;
         boolean isFullscreen = mFullscreenProgress > 0;
         mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
+        if (mActionsView != null) {
+            mActionsView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
+        }
         setClipChildren(!isFullscreen);
         setClipToPadding(!isFullscreen);
 
@@ -873,4 +905,5 @@
             mScale = scale;
         }
     }
+
 }
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 7a36416..60cfa0c 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -25,8 +25,7 @@
         android:id="@+id/snapshot"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_marginTop="@dimen/task_thumbnail_top_margin"
-        android:layout_marginBottom="@dimen/task_thumbnail_bottom_margin"/>
+        android:layout_marginTop="@dimen/task_thumbnail_top_margin"/>
 
     <com.android.quickstep.views.IconView
         android:id="@+id/icon"
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 327bb14..24ab487 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -15,6 +15,8 @@
 -->
 <resources>
     <string name="task_overlay_factory_class" translatable="false"></string>
+    <!-- Class name for factory object that creates the overview actions UI when enabled. -->
+    <string name="overview_actions_factory_class" translatable="false" />
 
     <!-- Activity which blocks home gesture -->
     <string name="gesture_blocking_activity" translatable="false"></string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 82833ea..9ff1350 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -18,12 +18,13 @@
 
     <dimen name="task_thumbnail_top_margin">24dp</dimen>
     <dimen name="task_thumbnail_half_top_margin">12dp</dimen>
-    <!-- Can be overridden in overlays. -->
-    <dimen name="task_thumbnail_bottom_margin">0dp</dimen>
     <dimen name="task_thumbnail_icon_size">48dp</dimen>
     <!-- For screens without rounded corners -->
     <dimen name="task_corner_radius_small">2dp</dimen>
 
+    <!-- Overrideable in overlay that provides the Overview Actions. -->
+    <dimen name="overview_actions_height">0dp</dimen>
+
     <dimen name="recents_page_spacing">10dp</dimen>
     <dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
     <dimen name="overview_peek_distance">96dp</dimen>
@@ -58,6 +59,7 @@
     <dimen name="task_card_menu_shadow_height">3dp</dimen>
     <dimen name="task_card_menu_horizontal_padding">0dp</dimen>
     <dimen name="portrait_task_card_horz_space">136dp</dimen>
+    <dimen name="portrait_task_card_horz_space_big_overview">24dp</dimen>
     <dimen name="landscape_task_card_horz_space">200dp</dimen>
     <dimen name="multi_window_task_card_horz_space">100dp</dimen>
     <!-- Copied from framework resource:
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index c47bb4a..d49ff89 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -26,6 +26,7 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.quickstep.SysUINavigationMode;
 
 import java.lang.annotation.Retention;
@@ -57,9 +58,16 @@
         } else {
             Resources res = context.getResources();
 
-            extraSpace = getDefaultSwipeHeight(context, dp) + dp.verticalDragHandleSizePx
-                    + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size)
-                    + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
+            if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
+                //TODO: this needs to account for the swipe gesture height and accessibility
+                // UI when shown.
+                extraSpace = 0;
+            } else {
+                extraSpace = getDefaultSwipeHeight(context, dp) + dp.verticalDragHandleSizePx
+                        + res.getDimensionPixelSize(
+                                R.dimen.dynamic_grid_hotseat_extra_vertical_size)
+                        + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
+            }
         }
         calculateTaskSize(context, dp, extraSpace, MULTI_WINDOW_STRATEGY_HALF_SCREEN, outRect);
     }
@@ -99,13 +107,20 @@
         } else {
             taskWidth = dp.availableWidthPx;
             taskHeight = dp.availableHeightPx;
-            paddingHorz = res.getDimension(dp.isVerticalBarLayout()
-                    ? R.dimen.landscape_task_card_horz_space
-                    : R.dimen.portrait_task_card_horz_space);
+
+            final int paddingResId;
+            if (dp.isVerticalBarLayout()) {
+                paddingResId = R.dimen.landscape_task_card_horz_space;
+            } else if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
+                paddingResId = R.dimen.portrait_task_card_horz_space_big_overview;
+            } else {
+                paddingResId = R.dimen.portrait_task_card_horz_space;
+            }
+            paddingHorz = res.getDimension(paddingResId);
         }
 
-        float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
-        float bottomMargin = res.getDimension(R.dimen.task_thumbnail_bottom_margin);
+        float topIconMargin =   res.getDimension(R.dimen.task_thumbnail_top_margin);
+        float bottomMargin = thumbnailBottomMargin(res);
         float paddingVert = res.getDimension(R.dimen.task_card_vert_space);
 
         // Note this should be same as dp.availableWidthPx and dp.availableHeightPx unless
@@ -136,4 +151,16 @@
                 R.dimen.task_card_vert_space);
         return shelfHeight + spaceBetweenShelfAndRecents;
     }
+
+    /**
+     * Get the margin that the task thumbnail view should use.
+     * @return the margin in pixels.
+     */
+    public static int thumbnailBottomMargin(Resources resources) {
+        if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
+            return resources.getDimensionPixelSize(R.dimen.overview_actions_height);
+        } else {
+            return 0;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 1ae30b7..80c7056 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -130,6 +130,9 @@
             "ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", false,
             "Show launcher preview in grid picker");
 
+    public static final TogglableFlag ENABLE_OVERVIEW_ACTIONS = new TogglableFlag(
+            "ENABLE_OVERVIEW_ACTIONS", false, "Show app actions in Overview");
+
     public static void initialize(Context context) {
         // Avoid the disk read for user builds
         if (Utilities.IS_DEBUG_DEVICE) {