Merge "Update TaskIcon UI." into sc-dev
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 36b51cd..feeee50 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1071,9 +1071,7 @@
                     && runningTaskTarget != null
                     && runningTaskTarget.pictureInPictureParams != null
                     && TaskInfoCompat.isAutoEnterPipEnabled(
-                            runningTaskTarget.pictureInPictureParams)
-                    && TaskInfoCompat.getPipSourceRectHint(
-                            runningTaskTarget.pictureInPictureParams) != null;
+                            runningTaskTarget.pictureInPictureParams);
             if (mIsSwipingPipToHome) {
                 mSwipePipToHomeAnimator = getSwipePipToHomeAnimator(
                         homeAnimFactory, runningTaskTarget, start);
@@ -1176,8 +1174,10 @@
             swipePipToHomeAnimator.setFromRotation(mTaskViewSimulator, windowRotation);
         }
         swipePipToHomeAnimator.addListener(new AnimatorListenerAdapter() {
+            private boolean mHasAnimationEnded;
             @Override
             public void onAnimationStart(Animator animation) {
+                if (mHasAnimationEnded) return;
                 // Ensure Launcher ends in NORMAL state, we intentionally skip other callbacks
                 // since they are not relevant in this swipe-pip-to-home case.
                 homeAnimFactory.createActivityAnimationToHome().dispatchOnStart();
@@ -1185,6 +1185,8 @@
 
             @Override
             public void onAnimationEnd(Animator animation) {
+                if (mHasAnimationEnded) return;
+                mHasAnimationEnded = true;
                 if (mRecentsAnimationController == null) {
                     // If the recents animation is interrupted, we still end the running
                     // animation (not canceled) so this is still called. In that case, we can
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 93ebd5a..844d6f5 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -222,6 +222,12 @@
         }
 
         /**
+         * Sets full screen progress to the task overlay.
+         */
+        public void setFullscreenProgress(float progress) {
+        }
+
+        /**
          * Gets the system shortcut for the screenshot that will be added to the task menu.
          */
         public SystemShortcut getScreenshotShortcut(BaseDraggingActivity activity,
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index d22496d..aafb1af 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER;
+import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_SNAPSHOT;
 import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__ALLAPPS;
 import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__BACKGROUND;
@@ -38,6 +39,8 @@
 import com.android.launcher3.logger.LauncherAtom.FolderIcon;
 import com.android.launcher3.logger.LauncherAtom.FromState;
 import com.android.launcher3.logger.LauncherAtom.ToState;
+import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer;
+import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.AllAppsList;
@@ -301,6 +304,14 @@
                 return info.getContainerInfo().getPredictedHotseatContainer().getCardinality();
             case SEARCH_RESULT_CONTAINER:
                 return info.getContainerInfo().getSearchResultContainer().getQueryLength();
+            case EXTENDED_CONTAINERS:
+                ExtendedContainers extendedCont = info.getContainerInfo().getExtendedContainers();
+                if (extendedCont.getContainerCase() == DEVICE_SEARCH_RESULT_CONTAINER) {
+                    DeviceSearchResultContainer deviceSearchResultCont = extendedCont
+                            .getDeviceSearchResultContainer();
+                    return deviceSearchResultCont.hasQueryLength() ? deviceSearchResultCont
+                            .getQueryLength() : -1;
+                }
             default:
                 return info.getFolderIcon().getCardinality();
         }
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 378f25b..0ce5072 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -31,6 +31,7 @@
 import android.view.View;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.systemui.shared.pip.PipSurfaceTransactionHelper;
@@ -60,7 +61,7 @@
     /** for calculating the transform in {@link #onAnimationUpdate(ValueAnimator)} */
     private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
     private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect());
-    private final Rect mSourceHintRectInsets = new Rect();
+    private final Rect mSourceHintRectInsets;
     private final Rect mSourceInsets = new Rect();
 
     /** for rotation via {@link #setFromRotation(TaskViewSimulator, int)} */
@@ -89,7 +90,7 @@
     public SwipePipToHomeAnimator(int taskId,
             @NonNull ComponentName componentName,
             @NonNull SurfaceControl leash,
-            @NonNull Rect sourceRectHint,
+            @Nullable Rect sourceRectHint,
             @NonNull Rect appBounds,
             @NonNull Rect startBounds,
             @NonNull Rect destinationBounds,
@@ -104,10 +105,14 @@
         mDestinationBoundsAnimation.set(mDestinationBounds);
         mSurfaceTransactionHelper = new PipSurfaceTransactionHelper();
 
-        mSourceHintRectInsets.set(sourceRectHint.left - appBounds.left,
-                sourceRectHint.top - appBounds.top,
-                appBounds.right - sourceRectHint.right,
-                appBounds.bottom - sourceRectHint.bottom);
+        if (sourceRectHint == null) {
+            mSourceHintRectInsets = null;
+        } else {
+            mSourceHintRectInsets = new Rect(sourceRectHint.left - appBounds.left,
+                    sourceRectHint.top - appBounds.top,
+                    appBounds.right - sourceRectHint.right,
+                    appBounds.bottom - sourceRectHint.bottom);
+        }
 
         addListener(new AnimationSuccessListener() {
             @Override
@@ -168,34 +173,44 @@
         final float fraction = animator.getAnimatedFraction();
         final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds,
                 mDestinationBoundsAnimation);
-        final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets,
-                mSourceHintRectInsets);
         final SurfaceControl.Transaction tx =
                 PipSurfaceTransactionHelper.newSurfaceControlTransaction();
-        if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
-            final float degree, positionX, positionY;
-            if (mFromRotation == Surface.ROTATION_90) {
-                degree = -90 * fraction;
-                positionX = fraction * (mDestinationBoundsTransformed.left - mAppBounds.left)
-                        + mAppBounds.left;
-                positionY = fraction * (mDestinationBoundsTransformed.bottom - mAppBounds.top)
-                        + mAppBounds.top;
-            } else {
-                degree = 90 * fraction;
-                positionX = fraction * (mDestinationBoundsTransformed.right - mAppBounds.left)
-                        + mAppBounds.left;
-                positionY = fraction * (mDestinationBoundsTransformed.top - mAppBounds.top)
-                        + mAppBounds.top;
-            }
-            mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets,
-                    degree, positionX, positionY);
+        if (mSourceHintRectInsets == null) {
+            // no source rect hint been set, directly scale the window down
+            onAnimationScale(fraction, tx, bounds);
         } else {
-            mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets);
+            // scale and crop according to the source rect hint
+            onAnimationScaleAndCrop(fraction, tx, bounds);
         }
         mSurfaceTransactionHelper.resetCornerRadius(tx, mLeash);
         tx.apply();
     }
 
+    /** scale the window directly with no source rect hint being set */
+    private void onAnimationScale(float fraction, SurfaceControl.Transaction tx, Rect bounds) {
+        if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
+            final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
+            mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds,
+                    rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
+        } else {
+            mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds);
+        }
+    }
+
+    /** scale and crop the window with source rect hint */
+    private void onAnimationScaleAndCrop(float fraction, SurfaceControl.Transaction tx,
+            Rect bounds) {
+        final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets,
+                mSourceHintRectInsets);
+        if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
+            final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
+            mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets,
+                    rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
+        } else {
+            mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets);
+        }
+    }
+
     public int getTaskId() {
         return mTaskId;
     }
@@ -217,4 +232,34 @@
         tx.apply();
         mHasAnimationEnded = true;
     }
+
+    private RotatedPosition getRotatedPosition(float fraction) {
+        final float degree, positionX, positionY;
+        if (mFromRotation == Surface.ROTATION_90) {
+            degree = -90 * fraction;
+            positionX = fraction * (mDestinationBoundsTransformed.left - mAppBounds.left)
+                    + mAppBounds.left;
+            positionY = fraction * (mDestinationBoundsTransformed.bottom - mAppBounds.top)
+                    + mAppBounds.top;
+        } else {
+            degree = 90 * fraction;
+            positionX = fraction * (mDestinationBoundsTransformed.right - mAppBounds.left)
+                    + mAppBounds.left;
+            positionY = fraction * (mDestinationBoundsTransformed.top - mAppBounds.top)
+                    + mAppBounds.top;
+        }
+        return new RotatedPosition(degree, positionX, positionY);
+    }
+
+    private static class RotatedPosition {
+        private final float degree;
+        private final float positionX;
+        private final float positionY;
+
+        private RotatedPosition(float degree, float positionX, float positionY) {
+            this.degree = degree;
+            this.positionX = positionX;
+            this.positionY = positionY;
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 20d9fa4..8a8b021 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -1085,6 +1085,7 @@
         progress = Utilities.boundToRange(progress, 0, 1);
         mFullscreenProgress = progress;
         mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
+        getThumbnail().getTaskOverlay().setFullscreenProgress(progress);
 
         updateTaskScaling();
 
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 8a45c81..4b95372 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1706,10 +1706,9 @@
         if (dropOverView instanceof FolderIcon) {
             FolderIcon fi = (FolderIcon) dropOverView;
             if (fi.acceptDrop(d.dragInfo)) {
-                mStatsLogManager.logger().withItemInfo(d.dragInfo).withInstanceId(d.logInstanceId)
-                        .log(LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED);
+                mStatsLogManager.logger().withItemInfo(fi.mInfo).withInstanceId(d.logInstanceId)
+                        .log(LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED_ON_FOLDER_ICON);
                 fi.onDrop(d, false /* itemReturnedOnFailedDrop */);
-
                 // if the drag started here, we need to remove it from the workspace
                 if (!external) {
                     getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 20f7c23..505e6d8 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -213,10 +213,14 @@
         if (insets == null) return;
 
         if (insets.isVisible(WindowInsets.Type.ime())) {
-            getWindowInsetsController().hide(WindowInsets.Type.ime());
+            hideIme();
         }
     }
 
+    protected void hideIme() {
+        getWindowInsetsController().hide(WindowInsets.Type.ime());
+    }
+
     /**
      * Returns whether the view itself will handle the touch event or not.
      */
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index a6bc6cf..bb1a4c0 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -15,6 +15,10 @@
  */
 package com.android.launcher3.allapps;
 
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SWITCHED_TO_MAIN_TAB;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SWITCHED_TO_WORK_TAB;
+
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
@@ -86,6 +90,14 @@
     public void onTabChanged(int pos) {
         super.onTabChanged(pos);
         if (mUsingTabs) {
+
+            // Log tab switches only when the launcher is in AllApps state
+            if (mLauncher.getStateManager().getCurrentStableState() == LauncherState.ALL_APPS) {
+                mLauncher.getLiveSearchManager().allAppsLogger()
+                        .log(pos == AdapterHolder.WORK ? LAUNCHER_ALLAPPS_SWITCHED_TO_WORK_TAB
+                                : LAUNCHER_ALLAPPS_SWITCHED_TO_MAIN_TAB);
+            }
+
             if (pos == AdapterHolder.WORK) {
                 WorkEduView.showWorkEduIfNeeded(mLauncher);
             } else {
@@ -93,4 +105,10 @@
             }
         }
     }
+
+    @Override
+    protected void hideIme() {
+        super.hideIme();
+        mLauncher.getLiveSearchManager().allAppsLogger().log(LAUNCHER_ALLAPPS_KEYBOARD_CLOSED);
+    }
 }
diff --git a/src/com/android/launcher3/allapps/search/LiveSearchManager.java b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
index 608affe..d51c786 100644
--- a/src/com/android/launcher3/allapps/search/LiveSearchManager.java
+++ b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
@@ -153,15 +153,15 @@
             clearWidgetHost();
         }
 
-        StatsLogger logger = mLauncher.getStatsLogManager().logger();
         if (finalState.equals(ALL_APPS)) {
+            // creates new instance ID since new all apps session is started.
             mLogInstanceId = new InstanceIdSequence().newInstanceId();
-            logger.withInstanceId(mLogInstanceId).log(LAUNCHER_ALLAPPS_ENTRY);
+            allAppsLogger().log(LAUNCHER_ALLAPPS_ENTRY);
         } else if (mPrevLauncherState.equals(ALL_APPS)
                 // Check if mLogInstanceId is not null; to avoid NPE when LAUNCHER_ALLAPPS_EXIT is
                 // triggered multiple times
                 && mLogInstanceId != null) {
-            logger.withInstanceId(mLogInstanceId).log(LAUNCHER_ALLAPPS_EXIT);
+            allAppsLogger().log(LAUNCHER_ALLAPPS_EXIT);
             mLogInstanceId = null;
         }
     }
@@ -316,4 +316,15 @@
         @Override
         public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { }
     }
+
+    /**
+     * Returns new instance of {@link StatsLogger} pre-populated with details required to log
+     * AllApps specific user events.
+     */
+    public StatsLogger allAppsLogger() {
+        return getLogInstanceId()
+                .map(instanceId -> mLauncher.getStatsLogManager().logger()
+                        .withInstanceId(instanceId))
+                .orElse(mLauncher.getStatsLogManager().logger());
+    }
 }
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 1cfe6ac..93df599 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -40,12 +40,14 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.accessibility.DragViewStateAnnouncer;
+import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.TouchController;
 
 import java.util.ArrayList;
+import java.util.Optional;
 
 /**
  * Class for initiating a drag within a view or across multiple views.
@@ -230,6 +232,11 @@
         }
     }
 
+    public Optional<InstanceId> getLogInstanceId() {
+        return Optional.ofNullable(mDragObject)
+                .map(dragObject -> dragObject.logInstanceId);
+    }
+
     /**
      * Call this from a drag source view like this:
      *
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 61938d1..74d8dca 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -1208,7 +1208,9 @@
                         newIcon.requestFocus();
                     }
                     if (finalItem != null) {
-                        mStatsLogManager.logger().withItemInfo(finalItem)
+                        StatsLogger logger = mStatsLogManager.logger().withItemInfo(finalItem);
+                        mDragController.getLogInstanceId().map(logger::withInstanceId)
+                                .orElse(logger)
                                 .log(LAUNCHER_FOLDER_CONVERTED_TO_ICON);
                     }
                 }
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 0292d20..cc80a88 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -95,9 +95,13 @@
         @UiEvent(doc = "User dragged a launcher item")
         LAUNCHER_ITEM_DRAG_STARTED(383),
 
-        @UiEvent(doc = "A dragged launcher item is successfully dropped")
+        @UiEvent(doc = "A dragged launcher item is successfully dropped onto workspace, hotseat "
+                + "open folder etc")
         LAUNCHER_ITEM_DROP_COMPLETED(385),
 
+        @UiEvent(doc = "A dragged launcher item is successfully dropped onto a folder icon.")
+        LAUNCHER_ITEM_DROP_COMPLETED_ON_FOLDER_ICON(697),
+
         @UiEvent(doc = "A dragged launcher item is successfully dropped on another item "
                 + "resulting in a new folder creation")
         LAUNCHER_ITEM_DROP_FOLDER_CREATED(386),
@@ -350,6 +354,15 @@
 
         @UiEvent(doc = "Launcher exited from AllApps state.")
         LAUNCHER_ALLAPPS_EXIT(693),
+
+        @UiEvent(doc = "User closed the AllApps keyboard.")
+        LAUNCHER_ALLAPPS_KEYBOARD_CLOSED(694),
+
+        @UiEvent(doc = "User switched to Main tab in AllApps screen.")
+        LAUNCHER_ALLAPPS_SWITCHED_TO_MAIN_TAB(695),
+
+        @UiEvent(doc = "User switched to Work tab in AllApps screen.")
+        LAUNCHER_ALLAPPS_SWITCHED_TO_WORK_TAB(696),
         ;
 
         // ADD MORE
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index cc783f7..cd2ef35 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.folder.FolderNameInfos;
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.logger.LauncherAtom.Attribute;
+import com.android.launcher3.logger.LauncherAtom.FolderIcon;
 import com.android.launcher3.logger.LauncherAtom.FromState;
 import com.android.launcher3.logger.LauncherAtom.ToState;
 import com.android.launcher3.model.ModelWriter;
@@ -208,8 +209,13 @@
 
     @Override
     public LauncherAtom.ItemInfo buildProto(FolderInfo fInfo) {
+        FolderIcon.Builder folderIcon = FolderIcon.newBuilder()
+                .setCardinality(contents.size());
+        if (LabelState.SUGGESTED.equals(getLabelState())) {
+            folderIcon.setLabelInfo(title.toString());
+        }
         return getDefaultItemInfoBuilder()
-                .setFolderIcon(LauncherAtom.FolderIcon.newBuilder().setCardinality(contents.size()))
+                .setFolderIcon(folderIcon)
                 .setRank(rank)
                 .setAttribute(getLabelState().mLogAttribute)
                 .setContainerInfo(getContainerInfo())