Merge "Allows Accessibility to focus on specified view in AbstractFloatingView." into ub-launcher3-rvc-dev
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index c6e8c20b..7e8e51e 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -53,6 +53,7 @@
     SearchResultContainer search_result_container = 7;
     ShortcutsContainer shortcuts_container = 8;
     SettingsContainer settings_container = 9;
+    PredictedHotseatContainer predicted_hotseat_container = 10;
   }
 }
 
@@ -151,6 +152,14 @@
   optional int32 index = 1;
 }
 
+// Represents hotseat container with prediction feature enabled.
+message PredictedHotseatContainer {
+  optional int32 index = 1;
+
+  // No of hotseat positions filled with predicted items.
+  optional int32 cardinality = 2;
+}
+
 message FolderContainer {
   optional int32 page_index = 1 [default = -1];
   optional int32 grid_x = 2 [default = -1];
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index ce6bb7d..0ace4cc 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -57,7 +57,7 @@
         LauncherAccessibilityDelegate.AccessibilityActionHandler {
 
     private static final int RING_SHADOW_COLOR = 0x99000000;
-    private static final float RING_EFFECT_RATIO = 0.11f;
+    private static final float RING_EFFECT_RATIO = 0.08f;
 
     boolean mIsDrawingDot = false;
     private final DeviceProfile mDeviceProfile;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
index f2438b6..414d7ae 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
@@ -41,6 +41,7 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.PointF;
@@ -78,9 +79,11 @@
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.LatencyTrackerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.TaskStackChangeListener;
 
 /**
  * Handles the navigation gestures when Launcher is the default home activity.
@@ -900,6 +903,21 @@
 
     protected abstract HomeAnimationFactory createHomeAnimationFactory(long duration);
 
+    private TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() {
+        @Override
+        public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+            if (task.taskId == mGestureState.getRunningTaskId()) {
+                // Since this is an edge case, just cancel and relaunch with default activity
+                // options (since we don't know if there's an associated app icon to launch from)
+                endRunningWindowAnim(true /* cancel */);
+                ActivityManagerWrapper.getInstance().unregisterTaskStackListener(
+                        mActivityRestartListener);
+                ActivityManagerWrapper.getInstance().startActivityFromRecents(task.taskId, null);
+            }
+        }
+    };
+
     @UiThread
     private void animateToProgressInternal(float start, float end, long duration,
             Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
@@ -907,6 +925,13 @@
         mGestureState.setEndTarget(target, false /* isAtomic */);
         maybeUpdateRecentsAttachedState();
 
+        // If we are transitioning to launcher, then listen for the activity to be restarted while
+        // the transition is in progress
+        if (mGestureState.getEndTarget().isLauncher) {
+            ActivityManagerWrapper.getInstance().registerTaskStackListener(
+                    mActivityRestartListener);
+        }
+
         if (mGestureState.getEndTarget() == HOME) {
             HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(duration);
             RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
@@ -1127,6 +1152,7 @@
         }
 
         mActivityInitListener.unregister();
+        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mActivityRestartListener);
         mTaskSnapshot = null;
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 226c818..4ca4e4c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -24,7 +24,6 @@
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.GestureState.DEFAULT_STATE;
-import static com.android.quickstep.util.RecentsOrientedState.isFixedRotationTransformEnabled;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
@@ -636,9 +635,7 @@
         if (TestProtocol.sDebugTracing) {
             Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.1");
         }
-        if (!isFixedRotationTransformEnabled()) {
-            return;
-        }
+
         baseInputConsumer.notifyOrientationSetup();
     }
 
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 798e400..98784ef 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
@@ -607,10 +607,6 @@
         }
     }
 
-    public boolean isCenterPageTask() {
-        return getScrollX() == getScrollForPage(getPageNearestToCenterOfScreen());
-    }
-
     @Override
     protected void onPageBeginTransition() {
         super.onPageBeginTransition();
@@ -620,7 +616,7 @@
     @Override
     protected void onPageEndTransition() {
         super.onPageEndTransition();
-        if (isCenterPageTask()) {
+        if (getScrollX() == getScrollForPage(getPageNearestToCenterOfScreen())) {
             LayoutUtils.setViewEnabled(mActionsView, true);
         }
         if (getNextPage() > 0) {
@@ -1904,7 +1900,7 @@
             anim.play(depthAnimator);
         }
         anim.play(progressAnim);
-        anim.setDuration(duration).setInterpolator(interpolator);
+        anim.setInterpolator(interpolator);
 
         mPendingAnimation = new PendingAnimation(duration);
         mPendingAnimation.add(anim);
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 5176f2c..cadf6c4 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
@@ -425,16 +425,13 @@
     }
 
     private boolean showTaskMenu(int action) {
-        if (!getRecentsView().isCenterPageTask()) {
-            getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
-        } else {
-            mMenuView = TaskMenuView.showForTask(this);
-            mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, buildProto());
-            UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
-                    LauncherLogProto.ItemType.TASK_ICON);
-            if (mMenuView != null) {
-                mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
-            }
+        getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
+        mMenuView = TaskMenuView.showForTask(this);
+        mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, buildProto());
+        UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
+                LauncherLogProto.ItemType.TASK_ICON);
+        if (mMenuView != null) {
+            mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
         }
         return mMenuView != null;
     }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index f39c176..07aed52 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -23,7 +23,6 @@
 import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
 import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
 import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
-import static com.android.quickstep.util.RecentsOrientedState.isFixedRotationTransformEnabled;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
@@ -197,10 +196,6 @@
     }
 
     private void setupOrientationSwipeHandler() {
-        if (!isFixedRotationTransformEnabled()) {
-            return;
-        }
-
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mFrozenTaskListener);
         mOnDestroyFrozenTaskRunnable = () -> ActivityManagerWrapper.getInstance()
                 .unregisterTaskStackListener(mFrozenTaskListener);
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 2adcfaa..be8eb48 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -17,6 +17,7 @@
 package com.android.quickstep.logging;
 
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
+import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.PREDICTED_HOTSEAT_CONTAINER;
 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;
 import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__HOME;
@@ -105,6 +106,19 @@
     }
 
     /**
+     * Logs a ranking event and accompanying {@link InstanceId} and package name.
+     */
+    @Override
+    public void log(EventEnum rankingEvent, InstanceId instanceId, @Nullable String packageName,
+            int position) {
+        SysUiStatsLog.write(SysUiStatsLog.RANKING_SELECTED,
+                rankingEvent.getId() /* event_id = 1; */,
+                packageName /* package_name = 2; */,
+                instanceId.getId() /* instance_id = 3; */,
+                position /* position_picked = 4; */);
+    }
+
+    /**
      * Logs an event and accompanying {@link LauncherState}s. If either of the state refers
      * to workspace state, then use pageIndex to pass in index of workspace.
      */
@@ -168,7 +182,7 @@
                 info.getFolderIcon().getFromLabelState().getNumber() /* fromState */,
                 info.getFolderIcon().getToLabelState().getNumber() /* toState */,
                 info.getFolderIcon().getLabelInfo() /* edittext */,
-                info.getFolderIcon().getCardinality() /* cardinality */);
+                getCardinality(info) /* cardinality */);
     }
 
     /**
@@ -232,11 +246,17 @@
                 getHierarchy(info) /* hierarchy */,
                 info.getIsWork() /* is_work_profile */,
                 info.getAttribute().getNumber() /* origin */,
-                info.getFolderIcon().getCardinality() /* cardinality */,
+                getCardinality(info) /* cardinality */,
                 info.getWidget().getSpanX(),
                 info.getWidget().getSpanY());
     }
 
+    private static int getCardinality(LauncherAtom.ItemInfo info) {
+        return info.getContainerInfo().getContainerCase().equals(PREDICTED_HOTSEAT_CONTAINER)
+                ? info.getContainerInfo().getPredictedHotseatContainer().getCardinality()
+                : info.getFolderIcon().getCardinality();
+    }
+
     private static String getPackageName(LauncherAtom.ItemInfo info) {
         switch (info.getItemCase()) {
             case APPLICATION:
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 922f5ac..7715cca 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -72,8 +72,6 @@
     private static final String TAG = "RecentsOrientedState";
     private static final boolean DEBUG = true;
 
-    private static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";
-
     private ContentObserver mSystemAutoRotateObserver = new ContentObserver(new Handler()) {
         @Override
         public void onChange(boolean selfChange) {
@@ -94,25 +92,22 @@
     private static final int FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY = 1 << 0;
     // Multiple orientation is only supported if density is < 600
     private static final int FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY = 1 << 1;
-    // Feature flag controlling the multi-orientation feature
-    private static final int FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_FLAG = 1 << 2;
     // Shared prefs for rotation, only if activity supports it
-    private static final int FLAG_HOME_ROTATION_ALLOWED_IN_PREFS = 1 << 3;
+    private static final int FLAG_HOME_ROTATION_ALLOWED_IN_PREFS = 1 << 2;
     // If the user has enabled system rotation
-    private static final int FLAG_SYSTEM_ROTATION_ALLOWED = 1 << 4;
+    private static final int FLAG_SYSTEM_ROTATION_ALLOWED = 1 << 3;
     // Multiple orientation is not supported in multiwindow mode
-    private static final int FLAG_MULTIWINDOW_ROTATION_ALLOWED = 1 << 5;
+    private static final int FLAG_MULTIWINDOW_ROTATION_ALLOWED = 1 << 4;
     // Whether to rotation sensor is supported on the device
-    private static final int FLAG_ROTATION_WATCHER_SUPPORTED = 1 << 6;
+    private static final int FLAG_ROTATION_WATCHER_SUPPORTED = 1 << 5;
     // Whether to enable rotation watcher when multi-rotation is supported
-    private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 7;
+    private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 6;
     // Enable home rotation for UI tests, ignoring home rotation value from prefs
-    private static final int FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING = 1 << 8;
+    private static final int FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING = 1 << 7;
 
     private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE =
             FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY
-            | FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY
-            | FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_FLAG;
+            | FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY;
 
     // State for which rotation watcher will be enabled. We skip it when home rotation or
     // multi-window is enabled as in that case, activity itself rotates.
@@ -123,9 +118,6 @@
     private SysUINavigationMode.NavigationModeChangeListener mNavModeChangeListener =
             newMode -> setFlag(FLAG_ROTATION_WATCHER_SUPPORTED, newMode != TWO_BUTTONS);
 
-    /** TODO: Remove once R ships. This is unlikely to change across different swipe gestures. */
-    private static boolean sFixedRotationEnabled;
-
     private final Context mContext;
     private final ContentResolver mContentResolver;
     private final SharedPreferences mSharedPrefs;
@@ -168,11 +160,6 @@
         if (originalSmallestWidth < 600) {
             mFlags |= FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY;
         }
-        sFixedRotationEnabled = Settings.Global.getInt(
-                context.getContentResolver(), FIXED_ROTATION_TRANSFORM_SETTING_NAME, 1) == 1;
-        if (sFixedRotationEnabled) {
-            mFlags |= FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_FLAG;
-        }
         initFlags();
     }
 
@@ -521,14 +508,6 @@
         }
     }
 
-    /**
-     * Returns true if system can keep Launcher fixed to portrait layout even if the
-     * foreground app is rotated
-     */
-    public static boolean isFixedRotationTransformEnabled() {
-        return sFixedRotationEnabled;
-    }
-
     @NonNull
     @Override
     public String toString() {
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index 08e1c98..7f1107f 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -15,6 +15,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="?attr/allAppsScrimColor"
     android:padding="48dp"
     android:orientation="vertical"
     android:gravity="center">
@@ -34,6 +35,7 @@
     <TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:id="@+id/work_apps_paused_content"
         android:textColor="?attr/workProfileOverlayTextColor"
         android:text="@string/work_apps_paused_body"
         android:textAlignment="center"
diff --git a/res/layout/work_mode_switch.xml b/res/layout/work_mode_switch.xml
index 9cb7ce8..b5237db 100644
--- a/res/layout/work_mode_switch.xml
+++ b/res/layout/work_mode_switch.xml
@@ -28,11 +28,11 @@
     android:gravity="start"
     android:lines="1"
     android:showText="false"
-    android:textSize="16sp"
+    android:textSize="@dimen/work_profile_footer_text_size"
     android:background="?attr/allAppsScrimColor"
     android:text="@string/work_profile_toggle_label"
-    android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_padding"
-    android:paddingLeft="@dimen/all_apps_work_profile_tab_footer_padding"
-    android:paddingRight="@dimen/all_apps_work_profile_tab_footer_padding"
-    android:paddingTop="@dimen/all_apps_work_profile_tab_footer_padding"
+    android:paddingBottom="@dimen/work_profile_footer_padding"
+    android:paddingLeft="@dimen/work_profile_footer_padding"
+    android:paddingRight="@dimen/work_profile_footer_padding"
+    android:paddingTop="@dimen/work_profile_footer_padding"
 />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 31b12ad..947e635 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -96,7 +96,6 @@
     <!-- The size of corner radius of the arrow in the arrow toast. -->
     <dimen name="arrow_toast_corner_radius">2dp</dimen>
 
-    <dimen name="all_apps_work_profile_tab_footer_padding">20dp</dimen>
 
 <!-- Search bar in All Apps -->
     <dimen name="all_apps_header_max_elevation">3dp</dimen>
@@ -105,6 +104,9 @@
 
     <dimen name="all_apps_divider_margin_vertical">8dp</dimen>
 
+    <dimen name="work_profile_footer_padding">20dp</dimen>
+    <dimen name="work_profile_footer_text_size">16sp</dimen>
+
 <!-- Widget tray -->
     <dimen name="widget_preview_label_vertical_padding">8dp</dimen>
     <dimen name="widget_preview_label_horizontal_padding">16dp</dimen>
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 32685b0..f6c392b 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1342,7 +1342,6 @@
 
         ValueAnimator stepAnimator = ValueAnimator.ofFloat(0, 1);
         stepAnimator.addUpdateListener(listener);
-        stepAnimator.setDuration(config.duration);
         stepAnimator.addListener(listener);
         animation.add(stepAnimator);
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 2ffe9d5..c989e7b 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -22,6 +22,8 @@
 
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Point;
@@ -441,6 +443,15 @@
         }
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        View overlay = mAH[AdapterHolder.WORK].getOverlayView();
+        int v = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ? GONE : VISIBLE;
+        overlay.findViewById(R.id.work_apps_paused_title).setVisibility(v);
+        overlay.findViewById(R.id.work_apps_paused_content).setVisibility(v);
+    }
+
     private void replaceRVContainer(boolean showTabs) {
         for (int i = 0; i < mAH.length; i++) {
             if (mAH[i].recyclerView != null) {
@@ -653,10 +664,12 @@
             recyclerView.setItemAnimator(new DefaultItemAnimator());
             if (workDisabled) {
                 overlayView.setAlpha(0);
-                appsList.updateItemFilter((info, cn) -> false);
                 recyclerView.addAutoSizedOverlay(overlayView);
                 overlayView.animate().alpha(1).withEndAction(
-                        () -> recyclerView.setItemAnimator(null)).start();
+                        () -> {
+                            appsList.updateItemFilter((info, cn) -> false);
+                            recyclerView.setItemAnimator(null);
+                        }).start();
             } else if (mInfoMatcher != null) {
                 appsList.updateItemFilter(mInfoMatcher);
                 overlayView.animate().alpha(0).withEndAction(() -> {
@@ -669,8 +682,12 @@
 
         void applyPadding() {
             if (recyclerView != null) {
-                int bottomOffset =
-                        mWorkModeSwitch != null && mIsWork ? mWorkModeSwitch.getHeight() : 0;
+                Resources res = getResources();
+                int switchH = res.getDimensionPixelSize(R.dimen.work_profile_footer_padding) * 2
+                        + mInsets.bottom + Utilities.calculateTextHeight(
+                        res.getDimension(R.dimen.work_profile_footer_text_size));
+
+                int bottomOffset = mWorkModeSwitch != null && mIsWork ? switchH : 0;
                 recyclerView.setPadding(padding.left, padding.top, padding.right,
                         padding.bottom + bottomOffset);
             }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 99ed0ad..8260336 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -189,7 +189,6 @@
                 : FAST_OUT_SLOW_IN;
 
         Animator anim = createSpringAnimation(mProgress, targetProgress);
-        anim.setDuration(config.duration);
         anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
         anim.addListener(getProgressAnimatorListener());
         builder.add(anim);
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index afeb341..4195933 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -69,7 +69,7 @@
     }
 
     public void add(Animator a, SpringProperty springProperty) {
-        mAnim.play(a);
+        mAnim.play(a.setDuration(mDuration));
         addAnimationHoldersRecur(a, mDuration, springProperty, mAnimHolders);
     }
 
@@ -87,7 +87,7 @@
         }
         ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
         anim.addListener(new AlphaUpdateListener(view));
-        anim.setDuration(mDuration).setInterpolator(interpolator);
+        anim.setInterpolator(interpolator);
         add(anim);
     }
 
@@ -105,7 +105,7 @@
     public <T> void addFloat(T target, FloatProperty<T> property, float from, float to,
             TimeInterpolator interpolator) {
         Animator anim = ObjectAnimator.ofFloat(target, property, from, to);
-        anim.setDuration(mDuration).setInterpolator(interpolator);
+        anim.setInterpolator(interpolator);
         add(anim);
     }
 
@@ -116,7 +116,7 @@
             return;
         }
         Animator anim = ObjectAnimator.ofInt(target, property, value);
-        anim.setDuration(mDuration).setInterpolator(interpolator);
+        anim.setInterpolator(interpolator);
         add(anim);
     }
 
@@ -125,7 +125,7 @@
      */
     public void addOnFrameCallback(Runnable runnable) {
         if (mProgressAnimator == null) {
-            mProgressAnimator = ValueAnimator.ofFloat(0, 1).setDuration(mDuration);
+            mProgressAnimator = ValueAnimator.ofFloat(0, 1);
         }
 
         mProgressAnimator.addUpdateListener(anim -> runnable.run());
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 26fd53f..8df6f90 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -98,6 +98,10 @@
             "FOLDER_NAME_SUGGEST", true,
             "Suggests folder names instead of blank text.");
 
+    public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(
+            "FOLDER_NAME_MAJORITY_RANKING", true,
+            "Suggests folder names based on majority based ranking.");
+
     public static final BooleanFlag APP_SEARCH_IMPROVEMENTS = new DeviceFlag(
             "APP_SEARCH_IMPROVEMENTS", true,
             "Adds localized title and keyword search and ranking");
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index f0a9efb..f216f81 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -141,6 +141,25 @@
         }
     }
 
+    /**
+     * Launcher specific ranking related events.
+     */
+    public enum LauncherRankingEvent implements EventEnum {
+
+        UNKNOWN(0);
+        // ADD MORE
+
+        private final int mId;
+
+        LauncherRankingEvent(int id) {
+            mId = id;
+        }
+
+        public int getId() {
+            return mId;
+        }
+    }
+
     protected LogStateProvider mStateProvider;
 
     /**
@@ -182,6 +201,19 @@
     }
 
     /**
+     * Log an event with ranked-choice information along with package. Does nothing if event.getId()
+     * <= 0.
+     *
+     * @param rankingEvent an enum implementing UiEventEnum interface.
+     * @param instanceId An identifier obtained from an InstanceIdSequence.
+     * @param packageName the package name of the relevant app, if known (null otherwise).
+     * @param position the position picked.
+     */
+    public void log(EventEnum rankingEvent, InstanceId instanceId, @Nullable String packageName,
+            int position) {
+    }
+
+    /**
      * Logs an event and accompanying {@link LauncherState}s. If either of the state refers
      * to workspace state, then use pageIndex to pass in index of workspace.
      */
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index 4bfabb0..5ba2c8e 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -32,7 +32,6 @@
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Point;
-import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -53,6 +52,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -259,64 +259,54 @@
         return diff;
     }
 
-    private static void insertEntryInDb(SQLiteDatabase db, Context context,
-            ArrayList<DbEntry> entriesFromSrcDb, DbEntry entry, String srcTableName,
-            String destTableName) {
-        int id = -1;
-        switch (entry.itemType) {
-            case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-            case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
-            case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
-                for (DbEntry e : entriesFromSrcDb) {
-                    if (TextUtils.equals(e.mIntent, entry.mIntent)) {
-                        id = e.id;
-                    }
-                }
+    private static void insertEntryInDb(SQLiteDatabase db, Context context, DbEntry entry,
+            String srcTableName, String destTableName) {
+        int id = copyEntryAndUpdate(db, context, entry, srcTableName, destTableName);
 
-                break;
+        if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+            for (int itemId : entry.mFolderItems.values()) {
+                copyEntryAndUpdate(db, context, itemId, id, srcTableName, destTableName);
             }
-            case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
-                for (DbEntry e : entriesFromSrcDb) {
-                    if (e.mFolderItems.size() == entry.mFolderItems.size()
-                            && e.mFolderItems.containsAll(entry.mFolderItems)) {
-                        id = e.id;
-                    }
-                }
-                break;
-            }
-            case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-            case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: {
-                for (DbEntry e : entriesFromSrcDb) {
-                    if (TextUtils.equals(e.mProvider, entry.mProvider)) {
-                        id = e.id;
-                        break;
-                    }
-                }
-                break;
-            }
-            default:
-                return;
         }
+    }
 
-        Cursor c = db.query(srcTableName, null, LauncherSettings.Favorites._ID + " = '" + id + "'",
+    private static int copyEntryAndUpdate(SQLiteDatabase db, Context context,
+            DbEntry entry, String srcTableName, String destTableName) {
+        return copyEntryAndUpdate(db, context, entry, -1, -1, srcTableName, destTableName);
+    }
+
+    private static int copyEntryAndUpdate(SQLiteDatabase db, Context context,
+            int id, int folderId, String srcTableName, String destTableName) {
+        return copyEntryAndUpdate(db, context, null, id, folderId, srcTableName, destTableName);
+    }
+
+    private static int copyEntryAndUpdate(SQLiteDatabase db, Context context,
+            DbEntry entry, int id, int folderId, String srcTableName, String destTableName) {
+        int newId = -1;
+        Cursor c = db.query(srcTableName, null,
+                LauncherSettings.Favorites._ID + " = '" + (entry != null ? entry.id : id) + "'",
                 null, null, null, null);
-
         while (c.moveToNext()) {
             ContentValues values = new ContentValues();
             DatabaseUtils.cursorRowToContentValues(c, values);
-            entry.updateContentValues(values);
-            values.put(LauncherSettings.Favorites._ID,
-                    LauncherSettings.Settings.call(context.getContentResolver(),
-                            LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt(
-                            LauncherSettings.Settings.EXTRA_VALUE));
+            if (entry != null) {
+                entry.updateContentValues(values);
+            } else {
+                values.put(LauncherSettings.Favorites.CONTAINER, folderId);
+            }
+            newId = LauncherSettings.Settings.call(context.getContentResolver(),
+                    LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt(
+                    LauncherSettings.Settings.EXTRA_VALUE);
+            values.put(LauncherSettings.Favorites._ID, newId);
             db.insert(destTableName, null, values);
         }
         c.close();
+        return newId;
     }
 
-    private static void removeEntryFromDb(SQLiteDatabase db, String tableName, IntArray entryId) {
+    private static void removeEntryFromDb(SQLiteDatabase db, String tableName, IntArray entryIds) {
         db.delete(tableName,
-                Utilities.createDbSelectionQuery(LauncherSettings.Favorites._ID, entryId), null);
+                Utilities.createDbSelectionQuery(LauncherSettings.Favorites._ID, entryIds), null);
     }
 
     private static HashSet<String> getValidPackages(Context context) {
@@ -381,8 +371,8 @@
                     continue;
                 }
                 if (findPlacement(entry)) {
-                    insertEntryInDb(mDb, mContext, mSrcReader.mWorkspaceEntries, entry,
-                            mSrcReader.mTableName, mDestReader.mTableName);
+                    insertEntryInDb(mDb, mContext, entry, mSrcReader.mTableName,
+                            mDestReader.mTableName);
                     iterator.remove();
                 }
             }
@@ -394,7 +384,7 @@
          * to speed up the search.
          */
         private boolean findPlacement(DbEntry entry) {
-            for (int y = mNextStartY; y >= 0; y--) {
+            for (int y = mNextStartY; y > 0; y--) {
                 for (int x = mNextStartX; x < mTrgX; x++) {
                     boolean fits = mOccupied.isRegionVacant(x, y, entry.spanX, entry.spanY);
                     boolean minFits = mOccupied.isRegionVacant(x, y, entry.minSpanX,
@@ -451,8 +441,8 @@
                     // to something other than -1.
                     entry.cellX = i;
                     entry.cellY = 0;
-                    insertEntryInDb(mDb, mContext, mSrcReader.mHotseatEntries, entry,
-                            mSrcReader.mTableName, mDestReader.mTableName);
+                    insertEntryInDb(mDb, mContext, entry, mSrcReader.mTableName,
+                            mDestReader.mTableName);
                     mOccupied.markCells(entry, true);
                 }
             }
@@ -669,10 +659,11 @@
             int total = 0;
             while (c.moveToNext()) {
                 try {
+                    int id = c.getInt(0);
                     String intent = c.getString(1);
                     verifyIntent(intent);
                     total++;
-                    entry.mFolderItems.add(intent);
+                    entry.mFolderItems.put(intent, id);
                 } catch (Exception e) {
                     removeEntryFromDb(mDb, mTableName, IntArray.wrap(c.getInt(0)));
                 }
@@ -711,7 +702,7 @@
 
         private String mIntent;
         private String mProvider;
-        private Set<String> mFolderItems = new HashSet<>();
+        private Map<String, Integer> mFolderItems = new HashMap<>();
 
         /** Comparator according to the reading order */
         @Override
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 8dcdec1..d52b7eb 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -337,10 +337,13 @@
     ContainerInfo getContainerInfo() {
         switch (container) {
             case CONTAINER_HOTSEAT:
-            case CONTAINER_HOTSEAT_PREDICTION:
                 return ContainerInfo.newBuilder()
                         .setHotseat(LauncherAtom.HotseatContainer.newBuilder().setIndex(screenId))
                         .build();
+            case CONTAINER_HOTSEAT_PREDICTION:
+                return ContainerInfo.newBuilder().setPredictedHotseatContainer(
+                        LauncherAtom.PredictedHotseatContainer.newBuilder().setIndex(screenId))
+                        .build();
             case CONTAINER_DESKTOP:
                 return ContainerInfo.newBuilder()
                         .setWorkspace(