Add All Apps entry button to Taskbar.

- Opens All Apps when clicked
- Fades button in/out when transitioning b/w Hotseat & Taskbar

Bug: 205803230
Test: manual
      ensures alpha gets reset properly
      clicking button opens all apps
Change-Id: I1b96bae734aa9fd9308931d6312e3d65559d4284
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java
index 0b53cc2..62125fe 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAllAppsViewController.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.taskbar;
 
-import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
 
@@ -41,9 +40,6 @@
 
         mAppsView.setOnIconLongClickListener(
                 controllers.taskbarDragController::startDragOnLongClick);
-
-        // TODO(b/205803230): Remove once entry point button is implemented.
-        mContext.getDragLayer().findViewById(R.id.taskbar_view).setOnClickListener(v -> show());
     }
 
     /** Binds the current {@link AppInfo} instances to the {@link TaskbarAllAppsContainerView}. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index c8d9fca..fddd1ed 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -22,6 +22,7 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
 import androidx.annotation.LayoutRes;
@@ -31,6 +32,7 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
@@ -38,6 +40,7 @@
 import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.AllAppsButton;
 
 /**
  * Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
@@ -64,6 +67,9 @@
     // Only non-null when the corresponding Folder is open.
     private @Nullable FolderIcon mLeaveBehindFolderIcon;
 
+    // Only non-null when device supports having an All Apps button.
+    private @Nullable AllAppsButton mAllAppsButton;
+
     public TaskbarView(@NonNull Context context) {
         this(context, null);
     }
@@ -94,6 +100,13 @@
 
         // Needed to draw folder leave-behind when opening one.
         setWillNotDraw(false);
+
+        if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
+            mAllAppsButton = new AllAppsButton(context);
+            mAllAppsButton.setLayoutParams(
+                    new ViewGroup.LayoutParams(mIconTouchSize, mIconTouchSize));
+            mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+        }
     }
 
     protected void init(TaskbarViewController.TaskbarViewCallbacks callbacks) {
@@ -102,6 +115,10 @@
         mIconLongClickListener = mControllerCallbacks.getIconOnLongClickListener();
 
         setOnLongClickListener(mControllerCallbacks.getBackgroundOnLongClickListener());
+
+        if (mAllAppsButton != null) {
+            mAllAppsButton.setOnClickListener(mControllerCallbacks.getAllAppsButtonClickListener());
+        }
     }
 
     private void removeAndRecycle(View view) {
@@ -121,6 +138,10 @@
         int nextViewIndex = 0;
         int numViewsAnimated = 0;
 
+        if (mAllAppsButton != null) {
+            removeView(mAllAppsButton);
+        }
+
         for (int i = 0; i < hotseatItemInfos.length; i++) {
             ItemInfo hotseatItemInfo = hotseatItemInfos[i];
             if (hotseatItemInfo == null) {
@@ -191,6 +212,10 @@
         while (nextViewIndex < getChildCount()) {
             removeAndRecycle(getChildAt(nextViewIndex));
         }
+
+        if (mAllAppsButton != null) {
+            addView(mAllAppsButton);
+        }
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 0508994..778040d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -22,6 +22,7 @@
 
 import android.graphics.Rect;
 import android.util.FloatProperty;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewTreeObserver;
@@ -33,6 +34,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
@@ -45,6 +47,9 @@
  * Handles properties/data collection, then passes the results to TaskbarView to render.
  */
 public class TaskbarViewController implements TaskbarControllers.LoggableTaskbarController {
+
+    private static final String TAG = TaskbarViewController.class.getSimpleName();
+
     private static final Runnable NO_OP = () -> { };
 
     public static final int ALPHA_INDEX_HOME = 0;
@@ -225,14 +230,29 @@
         int count = mTaskbarView.getChildCount();
         for (int i = 0; i < count; i++) {
             View child = mTaskbarView.getChildAt(i);
-            ItemInfo info = (ItemInfo) child.getTag();
-            setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR);
+
+            int positionInHotseat = -1;
+            if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() && i == count - 1) {
+                // Note that there is no All Apps button in the hotseat, this position is only used
+                // as its convenient for animation purposes.
+                positionInHotseat = mActivity.getDeviceProfile().inv.numShownHotseatIcons;
+
+                setter.setViewAlpha(child, 0, LINEAR);
+            } else if (child.getTag() instanceof ItemInfo) {
+                positionInHotseat = ((ItemInfo) child.getTag()).screenId;
+            } else {
+                Log.w(TAG, "Unsupported view found in createIconAlignmentController, v=" + child);
+                continue;
+            }
+
+            float hotseatIconCenter = hotseatPadding.left
+                    + (hotseatCellSize + borderSpacing) * positionInHotseat
+                    + hotseatCellSize / 2;
 
             float childCenter = (child.getLeft() + child.getRight()) / 2;
-            float hotseatIconCenter = hotseatPadding.left
-                    + (hotseatCellSize + borderSpacing) * info.screenId
-                    + hotseatCellSize / 2;
             setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR);
+
+            setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR);
         }
 
         AnimatorPlaybackController controller = setter.createPlaybackController();
@@ -279,6 +299,10 @@
             return mActivity.getItemOnClickListener();
         }
 
+        public View.OnClickListener getAllAppsButtonClickListener() {
+            return v -> mControllers.taskbarAllAppsViewController.show();
+        }
+
         public View.OnLongClickListener getIconOnLongClickListener() {
             return mControllers.taskbarDragController::startDragOnLongClick;
         }
diff --git a/res/drawable/ic_all_apps_button.xml b/res/drawable/ic_all_apps_button.xml
new file mode 100644
index 0000000..52b919b
--- /dev/null
+++ b/res/drawable/ic_all_apps_button.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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="80dp"
+    android:height="80dp"
+    android:viewportWidth="80"
+    android:viewportHeight="80">
+  <path
+      android:pathData="M40,0.5L40,0.5c21.8,0 39.5,17.7 39.5,39.5l0,0c0,21.8 -17.7,39.5 -39.5,39.5l0,0C18.2,79.5 0.5,61.8 0.5,40l0,0C0.5,18.2 18.2,0.5 40,0.5z"
+      android:fillColor="#F7F9FA"/>
+  <path
+      android:pathData="M26.8,32.1m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0"
+      android:fillColor="#00677E"/>
+  <path
+      android:pathData="M26.8,47.9m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0"
+      android:fillColor="#5F757E"/>
+  <path
+      android:pathData="M40,32.1m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0"
+      android:fillColor="#5F757E"/>
+  <path
+      android:pathData="M40,47.9m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0"
+      android:fillColor="#6C6F93"/>
+  <path
+      android:pathData="M53.2,32.1m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0"
+      android:fillColor="#005A6E"/>
+  <path
+      android:pathData="M53.2,47.9m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0"
+      android:fillColor="#5F757E"/>
+</vector>
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 0b168a5..a381787 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -135,7 +135,7 @@
     /**
      * Number of icons inside the hotseat area.
      */
-    protected int numShownHotseatIcons;
+    public int numShownHotseatIcons;
 
     /**
      * Number of icons inside the hotseat area that is stored in the database. This is greater than
diff --git a/src/com/android/launcher3/views/AllAppsButton.java b/src/com/android/launcher3/views/AllAppsButton.java
new file mode 100644
index 0000000..f502d46
--- /dev/null
+++ b/src/com/android/launcher3/views/AllAppsButton.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 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.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.util.AttributeSet;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+import com.android.launcher3.icons.FastBitmapDrawable;
+
+/**
+ * Button in Taskbar that opens All Apps.
+ */
+public class AllAppsButton extends BubbleTextView {
+
+    public AllAppsButton(Context context) {
+        this(context, null);
+    }
+
+    public AllAppsButton(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AllAppsButton(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        Bitmap bitmap = LauncherAppState.getInstance(context).getIconCache().getIconFactory()
+                .createScaledBitmapWithShadow(context.getDrawable(R.drawable.ic_all_apps_button));
+        setIcon(new FastBitmapDrawable(bitmap));
+    }
+}