Merge "Reduce the iconSize to fit inside the cellSize when display size largest" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 228c34a..22ed567 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -97,3 +97,10 @@
     description: "Enables full width two pane widget picker for tablets in landscape and portrait"
     bug: "315055849"
 }
+
+flag {
+    name: "enable_support_for_archiving"
+    namespace: "launcher"
+    description: "Enables support for archived apps in Launcher3, such as empty progress bar etc."
+    bug: "210590852"
+}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index f25b652..2ebbe6f 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1290,7 +1290,7 @@
     /**
      * Returns view on launcher that corresponds to the closing app in the list of app targets
      */
-    private @Nullable View findLauncherView(RemoteAnimationTarget[] appTargets) {
+    public @Nullable View findLauncherView(RemoteAnimationTarget[] appTargets) {
         for (RemoteAnimationTarget appTarget : appTargets) {
             if (appTarget.mode == MODE_CLOSING) {
                 View launcherView = findLauncherView(appTarget);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 2f7f6f3..48c83da 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -21,9 +21,7 @@
 import static com.android.app.animation.Interpolators.FINAL_FRAME;
 import static com.android.app.animation.Interpolators.INSTANT;
 import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
-import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_SHOW;
 import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED;
@@ -59,7 +57,6 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.launcher3.Alarm;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
@@ -949,8 +946,7 @@
             return false;
         }
         // Do not stash if pinned taskbar and hardware keyboard is attached.
-        if (mActivity.isHardwareKeyboard() && enableTaskbarPinning()
-                && LauncherPrefs.get(mActivity).get(TASKBAR_PINNING)) {
+        if (mActivity.isHardwareKeyboard() && DisplayController.isPinnedTaskbar(mActivity)) {
             return false;
         }
         return mIsImeShowing || mIsImeSwitcherShowing;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
index f66bc60..1a75535 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
@@ -67,8 +67,6 @@
 
     private static AppWidgetHost sWidgetHost = null;
 
-    private final SparseArray<AppWidgetHostView> mViews = new SparseArray<>();
-
     private final @Nullable RemoteViews.InteractionHandler mInteractionHandler;
 
     private final @NonNull IntConsumer mAppWidgetRemovedCallback;
@@ -112,16 +110,12 @@
 
     @Override
     protected void updateDeferredView() {
-        super.updateDeferredView();
         int count = mPendingUpdateMap.size();
         for (int i = 0; i < count; i++) {
             int widgetId = mPendingUpdateMap.keyAt(i);
             AppWidgetHostView view = mViews.get(widgetId);
-            if (view == null) {
-                continue;
-            }
             PendingUpdate pendingUpdate = mPendingUpdateMap.valueAt(i);
-            if (pendingUpdate == null) {
+            if (view == null || pendingUpdate == null) {
                 continue;
             }
             if (pendingUpdate.providerInfo != null) {
@@ -172,7 +166,6 @@
     @Override
     public void deleteAppWidgetId(int appWidgetId) {
         super.deleteAppWidgetId(appWidgetId);
-        mViews.remove(appWidgetId);
         sListeners.remove(appWidgetId);
     }
 
@@ -238,7 +231,6 @@
     @Override
     public LauncherAppWidgetHostView createView(@NonNull Context context, int appWidgetId,
             @NonNull LauncherAppWidgetProviderInfo appWidget) {
-
         if (appWidget.isCustomWidget()) {
             LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
             lahv.setAppWidget(appWidgetId, appWidget);
@@ -252,7 +244,6 @@
         } else {
             widgetView = new LauncherAppWidgetHostView(context);
         }
-        widgetView.setIsWidgetCachingDisabled(true);
         widgetView.setInteractionHandler(mInteractionHandler);
         widgetView.setAppWidget(appWidgetId, appWidget);
         mViews.put(appWidgetId, widgetView);
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 0f88aac..b9029ea 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -54,12 +54,14 @@
 
 import com.android.internal.view.AppearanceRegion;
 import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.systemui.shared.system.QuickStepContract;
 
@@ -108,6 +110,7 @@
     private final PointF mInitialTouchPos = new PointF();
 
     private RemoteAnimationTarget mBackTarget;
+    private View mLauncherTargetView;
     private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
     private boolean mSpringAnimationInProgress = false;
     private boolean mAnimatorSetInProgress = false;
@@ -303,11 +306,22 @@
             int insetBottom = mStartRect.bottom - appTarget.contentInsets.bottom;
             mStartRect.set(mStartRect.left, mStartRect.top, mStartRect.right, insetBottom);
         }
+        mLauncherTargetView = mQuickstepTransitionManager.findLauncherView(
+                new RemoteAnimationTarget[]{ mBackTarget });
+        setLauncherTargetViewVisible(false);
         mCurrentRect.set(mStartRect);
         addScrimLayer();
         mTransaction.apply();
     }
 
+    private void setLauncherTargetViewVisible(boolean isVisible) {
+        if (mLauncherTargetView instanceof BubbleTextView) {
+            ((BubbleTextView) mLauncherTargetView).setIconVisible(isVisible);
+        } else if (mLauncherTargetView instanceof LauncherAppWidgetHostView) {
+            mLauncherTargetView.setAlpha(isVisible ? 1f : 0f);
+        }
+    }
+
     void addScrimLayer() {
         ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl();
         SurfaceControl parent = viewRootImpl != null
@@ -436,6 +450,8 @@
             mLauncher.getStateManager().moveToRestState();
         }
 
+        setLauncherTargetViewVisible(true);
+
         // Explicitly close opened floating views (which is typically called from
         // Launcher#onResumed, but in the predictive back flow launcher is not resumed until
         // the transition is fully finished.)
@@ -470,6 +486,8 @@
         mInitialTouchPos.set(0, 0);
         mAnimatorSetInProgress = false;
         mSpringAnimationInProgress = false;
+        setLauncherTargetViewVisible(true);
+        mLauncherTargetView = null;
         // We don't call customizeStatusBarAppearance here to prevent the status bar update with
         // the legacy appearance. It should be refreshed after the transition done.
         mOverridingStatusBarFlags = false;
diff --git a/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
index fc450f0..0913fca 100644
--- a/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
+++ b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
@@ -5,9 +5,10 @@
 import android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType
 import android.app.backup.BackupRestoreEventLogger.BackupRestoreError
 import android.content.Context
-import com.android.launcher3.Flags
+import com.android.launcher3.Flags.enableLauncherBrMetrics
 import com.android.launcher3.LauncherSettings.Favorites
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
+import com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCHER_BR_METRICS
 
 /**
  * Concrete implementation for wrapper to log Restore event metrics for both success and failure to
@@ -44,7 +45,7 @@
         count: Int,
         @BackupRestoreError error: String?
     ) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
             restoreEventLogger.logItemsRestoreFailed(dataType, count, error)
         }
     }
@@ -56,7 +57,7 @@
      * @param count the number of data items restored.
      */
     override fun logLauncherItemsRestored(@BackupRestoreDataType dataType: String, count: Int) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
             restoreEventLogger.logItemsRestored(dataType, count)
         }
     }
@@ -67,7 +68,7 @@
      * @param favoritesId The id of the item type from [Favorites] that was restored.
      */
     override fun logSingleFavoritesItemRestored(favoritesId: Int) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
             restoreEventLogger.logItemsRestored(favoritesIdToDataType(favoritesId), 1)
         }
     }
@@ -79,7 +80,7 @@
      * @param count number of items that restored.
      */
     override fun logFavoritesItemsRestored(favoritesId: Int, count: Int) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
             restoreEventLogger.logItemsRestored(favoritesIdToDataType(favoritesId), count)
         }
     }
@@ -94,7 +95,7 @@
         favoritesId: Int,
         @BackupRestoreError error: String?
     ) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
             restoreEventLogger.logItemsRestoreFailed(favoritesIdToDataType(favoritesId), 1, error)
         }
     }
@@ -111,7 +112,7 @@
         count: Int,
         @BackupRestoreError error: String?
     ) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
             restoreEventLogger.logItemsRestoreFailed(
                 favoritesIdToDataType(favoritesId),
                 count,
@@ -125,7 +126,7 @@
      * done restoring items for Launcher.
      */
     override fun reportLauncherRestoreResults() {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
             BackupManager(context).reportDelayedRestoreResult(restoreEventLogger)
         }
     }
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index a9fa337..193cc2b 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -667,8 +667,10 @@
 
             MAIN_EXECUTOR.execute(() -> {
                 // Only animate from taskView if it's already visible
-                boolean shouldLaunchFromTaskView = mLaunchingTaskView != null &&
-                        mLaunchingTaskView.getRecentsView().isTaskViewVisible(mLaunchingTaskView);
+                boolean shouldLaunchFromTaskView = mLaunchingTaskView != null
+                        && mLaunchingTaskView.getRecentsView() != null
+                        && mLaunchingTaskView.getRecentsView().isTaskViewVisible(
+                        mLaunchingTaskView);
                 mSplitAnimationController.playSplitLaunchAnimation(
                         shouldLaunchFromTaskView ? mLaunchingTaskView : null,
                         mLaunchingIconView,
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index afb63a1..ebe3365 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -336,7 +336,9 @@
 
     @Test
     @TaskbarModeSwitch
-    @Ignore // b/314873201
+    @ScreenRecord // b/314873201
+    // Staging; will be promoted to presubmit if stable
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     public void testQuickSwitchToPreviousAppForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
         startTestActivity(2);
diff --git a/res/drawable-v31/bg_deferred_app_widget.xml b/res/drawable-v31/bg_deferred_app_widget.xml
deleted file mode 100644
index a08998d..0000000
--- a/res/drawable-v31/bg_deferred_app_widget.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:inset="8dp">
-    <shape android:shape="rectangle">
-        <corners android:radius="@android:dimen/system_app_widget_background_radius" />
-        <solid android:color="#77000000" />
-    </shape>
-</inset>
diff --git a/res/drawable/bg_deferred_app_widget.xml b/res/drawable/bg_deferred_app_widget.xml
deleted file mode 100644
index 07bae48..0000000
--- a/res/drawable/bg_deferred_app_widget.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2015, 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.
-*/
--->
-
-<inset
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:inset="8dp">
-    <color android:color="#77000000" />
-</inset>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 91da7e6..a57eaa3 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -923,6 +923,8 @@
             if (mIcon instanceof PreloadIconDrawable) {
                 preloadIconDrawable = (PreloadIconDrawable) mIcon;
                 preloadIconDrawable.setLevel(progressLevel);
+                // TODO(b/302115555): For archived apps, show icon as disabled if active session
+                //  exists.
                 preloadIconDrawable.setIsDisabled(info.getProgressLevel() == 0);
             } else {
                 preloadIconDrawable = makePreloadIcon();
@@ -948,6 +950,7 @@
         final PreloadIconDrawable preloadDrawable = newPendingIcon(getContext(), info);
 
         preloadDrawable.setLevel(progressLevel);
+        // TODO(b/302115555): For archived apps, show icon as disabled if active session exists.
         preloadDrawable.setIsDisabled(info.getProgressLevel() == 0);
         return preloadDrawable;
     }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 11dc6e2..e0e35a4 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1715,11 +1715,7 @@
         mModel.removeCallbacks(this);
         mRotationHelper.destroy();
 
-        try {
-            mAppWidgetHolder.stopListening();
-        } catch (NullPointerException ex) {
-            Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
-        }
+        mAppWidgetHolder.stopListening();
         mAppWidgetHolder.destroy();
 
         TextKeyListener.getInstance().release();
@@ -2478,7 +2474,7 @@
      */
     private LauncherAppWidgetInfo completeRestoreAppWidget(int appWidgetId, int finalRestoreFlag) {
         LauncherAppWidgetHostView view = mWorkspace.getWidgetForAppWidgetId(appWidgetId);
-        if ((view == null) || !(view instanceof PendingAppWidgetHostView)) {
+        if (!(view instanceof PendingAppWidgetHostView)) {
             Log.e(TAG, "Widget update called, when the widget no longer exists.");
             return null;
         }
@@ -2489,8 +2485,9 @@
             info.pendingItemInfo = null;
         }
 
-        if (((PendingAppWidgetHostView) view).isReinflateIfNeeded()) {
-            view.reInflate();
+        PendingAppWidgetHostView pv = (PendingAppWidgetHostView) view;
+        if (pv.isReinflateIfNeeded()) {
+            pv.reInflate();
         }
 
         getModelWriter().updateItemInDatabase(info);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 9a19526..5ae2d71 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -36,11 +36,7 @@
 import android.content.pm.LauncherApps;
 import android.os.UserHandle;
 import android.util.Log;
-import android.util.SparseArray;
-import android.widget.RemoteViews;
 
-import androidx.annotation.GuardedBy;
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.graphics.IconShape;
@@ -77,12 +73,6 @@
     private final InvariantDeviceProfile mInvariantDeviceProfile;
     private final RunnableList mOnTerminateCallback = new RunnableList();
 
-    // WORKAROUND: b/269335387 remove this after widget background listener is enabled
-    /* Array of RemoteViews cached by Launcher process */
-    @GuardedBy("itself")
-    @NonNull
-    public final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>();
-
     public static LauncherAppState getInstance(final Context context) {
         return INSTANCE.get(context);
     }
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 1ba5f8e..a1f6ebe 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -225,10 +225,10 @@
         for (FloatingHeaderRow row : mAllRows) {
             row.setup(this, mAllRows, tabsHidden);
         }
-        updateExpectedHeight();
 
         mTabsHidden = tabsHidden;
         maybeSetTabVisibility(VISIBLE);
+        updateExpectedHeight();
         mMainRV = mainRV;
         mWorkRV = workRV;
         mSearchRV = searchRV;
diff --git a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
index bdac05d..063dad1 100644
--- a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
+++ b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
@@ -22,6 +22,8 @@
         const val RESTORE_ERROR_SHORTCUT_NOT_FOUND = "shortcut_not_found"
         const val RESTORE_ERROR_APP_NOT_INSTALLED = "app_not_installed"
         const val RESTORE_ERROR_WIDGETS_DISABLED = "widgets_disabled"
+        const val RESTORE_ERROR_PROFILE_NOT_RESTORED = "profile_not_restored"
+        const val RESTORE_ERROR_WIDGET_REMOVED = "widget_not_found"
 
         fun newInstance(context: Context?): LauncherRestoreEventLogger {
             return ResourceBasedOverride.Overrides.getObject(
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index aa6d1f2..61e853e 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -167,6 +167,8 @@
             "Enable the ability to generate monochromatic icons, if it is not provided by the app");
 
     // TODO(Block 8): Clean up flags
+    public static final BooleanFlag ENABLE_LAUNCHER_BR_METRICS = getDebugFlag(305984208,
+            "ENABLE_LAUNCHER_BR_METRICS", TEAMFOOD, "Enable metrics for Launcher restore");
 
     // TODO(Block 9): Clean up flags
     public static final BooleanFlag MULTI_SELECT_EDIT_MODE = getDebugFlag(270709220,
@@ -387,10 +389,6 @@
             "ENABLE_NEW_MIGRATION_LOGIC", ENABLED,
             "Enable the new grid migration logic, keeping pages when src < dest");
 
-    public static final BooleanFlag ENABLE_CACHED_WIDGET = getDebugFlag(270395008,
-            "ENABLE_CACHED_WIDGET", ENABLED,
-            "Show previously cached widgets as opposed to deferred widget where available");
-
     // TODO(Block 25): Clean up flags
     public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
             "ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED,
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 190eb78..7cbfc37 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -205,6 +205,8 @@
                             && installInfo.state == PackageInstallInfo.STATUS_INSTALLING) {
                         continue;
                     }
+                    // TODO(b/302115555): Handle the case when archived apps are to be updated
+                    //  during unarchival start.
                     appInfo.setProgressLevel(installInfo);
 
                     updatedAppInfos.add(appInfo);
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 8dc2ab3..7b9f6fa 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -17,6 +17,8 @@
 package com.android.launcher3.model;
 
 import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
+import static com.android.launcher3.Flags.enableSupportForArchiving;
+import static com.android.launcher3.Flags.enableLauncherBrMetrics;
 import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
 import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
@@ -131,6 +133,7 @@
  *   - all apps icons
  *   - deep shortcuts within apps
  */
+@SuppressWarnings("NewApi")
 public class LoaderTask implements Runnable {
     private static final String TAG = "LoaderTask";
     public static final String SMARTSPACE_ON_HOME_SCREEN = "pref_smartspace_home_screen";
@@ -230,8 +233,11 @@
         LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
         mIsRestoreFromBackup =
                 (Boolean) LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE);
-        LauncherRestoreEventLogger restoreEventLogger = LauncherRestoreEventLogger
-                .Companion.newInstance(mApp.getContext());
+        LauncherRestoreEventLogger restoreEventLogger = null;
+        if (enableLauncherBrMetrics()) {
+            restoreEventLogger = LauncherRestoreEventLogger.Companion
+                    .newInstance(mApp.getContext());
+        }
         try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
 
             List<ShortcutInfo> allShortcuts = new ArrayList<>();
@@ -362,9 +368,11 @@
             transaction.commit();
             memoryLogger.clearLogs();
             if (mIsRestoreFromBackup) {
-                restoreEventLogger.reportLauncherRestoreResults();
                 mIsRestoreFromBackup = false;
                 LauncherPrefs.get(mApp.getContext()).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false));
+                if (restoreEventLogger != null) {
+                    restoreEventLogger.reportLauncherRestoreResults();
+                }
             }
         } catch (CancellationException e) {
             // Loader stopped, ignore
@@ -419,7 +427,7 @@
         final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context);
 
         ModelDbController dbController = mApp.getModel().getModelDbController();
-        dbController.tryMigrateDB();
+        dbController.tryMigrateDB(restoreEventLogger);
         Log.d(TAG, "loadWorkspace: loading default favorites");
         dbController.loadDefaultFavoritesIfNecessary();
 
@@ -772,13 +780,21 @@
                                     PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
                         }
 
-                        if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
+                        if ((c.restoreFlag != 0
+                                || (enableSupportForArchiving()
+                                && activityInfo != null
+                                && activityInfo.getApplicationInfo().isArchived))
+                                && !TextUtils.isEmpty(targetPkg)) {
                             tempPackageKey.update(targetPkg, c.user);
                             SessionInfo si = installingPkgs.get(tempPackageKey);
                             if (si == null) {
                                 info.runtimeStatusFlags
                                         &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
-                            } else if (activityInfo == null) {
+                            } else if (activityInfo == null
+                                    // For archived apps, include progress info in case there is
+                                    // a pending install session post restart of device.
+                                    || (enableSupportForArchiving()
+                                    && activityInfo.getApplicationInfo().isArchived)) {
                                 int installProgress = (int) (si.getProgress() * 100);
 
                                 info.setProgressLevel(installProgress,
@@ -1095,6 +1111,8 @@
             for (int i = 0; i < apps.size(); i++) {
                 LauncherActivityInfo app = apps.get(i);
                 AppInfo appInfo = new AppInfo(app, user, quietMode);
+                // TODO(b/302115555): Handle the case when archived apps with active sessions are
+                //  loaded.
 
                 iconRequestInfos.add(new IconRequestInfo<>(
                         appInfo, app, /* useLowResIcon= */ false));
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index d2b7161..c68274a 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -19,6 +19,7 @@
 import static android.util.Base64.NO_WRAP;
 
 import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
 import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
 import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY;
 import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL;
@@ -48,6 +49,7 @@
 import android.util.Log;
 import android.util.Xml;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.AutoInstallsLayout;
@@ -62,6 +64,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.provider.LauncherDbUtils;
@@ -86,6 +89,7 @@
     private static final String TAG = "LauncherProvider";
 
     private static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
+    private static final String RESTORE_ERROR_GRID_MIGRATION_FAILURE = "grid_migration_failed";
     public static final String EXTRA_DB_NAME = "db_name";
 
     protected DatabaseHelper mOpenHelper;
@@ -261,8 +265,12 @@
     /**
      * Migrates the DB if needed. If the migration failed, it clears the DB.
      */
-    public void tryMigrateDB() {
+    public void tryMigrateDB(@Nullable LauncherRestoreEventLogger restoreEventLogger) {
+
         if (!migrateGridIfNeeded()) {
+            if (restoreEventLogger != null) {
+                sendMetricsForFailedMigration(restoreEventLogger, getDb());
+            }
             FileLog.d(TAG, "Migration failed: resetting launcher database");
             createEmptyDB();
             LauncherPrefs.get(mContext).putSync(
@@ -313,6 +321,30 @@
     }
 
     /**
+     * In case of migration failure, report metrics for the count of each itemType in the DB.
+     * @param restoreEventLogger logger used to report Launcher restore metrics
+     */
+    private void sendMetricsForFailedMigration(LauncherRestoreEventLogger restoreEventLogger,
+            SQLiteDatabase db) {
+        try (Cursor cursor = db.rawQuery(
+                "SELECT itemType, COUNT(*) AS count FROM favorites GROUP BY itemType",
+                null
+        )) {
+            if (cursor.moveToFirst()) {
+                do {
+                    restoreEventLogger.logFavoritesItemsRestoreFailed(
+                            cursor.getInt(cursor.getColumnIndexOrThrow(ITEM_TYPE)),
+                            cursor.getInt(cursor.getColumnIndexOrThrow("count")),
+                            RESTORE_ERROR_GRID_MIGRATION_FAILURE
+                    );
+                } while (cursor.moveToNext());
+            }
+        } catch (Exception e) {
+            FileLog.e(TAG, "sendMetricsForFailedDb: Error reading from database", e);
+        }
+    }
+
+    /**
      * Returns the underlying model database
      */
     public SQLiteDatabase getDb() {
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 4f2d398..069e96b 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -15,9 +15,11 @@
  */
 package com.android.launcher3.model;
 
+import static com.android.launcher3.Flags.enableSupportForArchiving;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
 import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
 import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_RESTORED_ICON;
 
@@ -67,6 +69,7 @@
  * Handles updates due to changes in package manager (app installed/updated/removed)
  * or when a user availability changes.
  */
+@SuppressWarnings("NewApi")
 public class PackageUpdatedTask extends BaseModelUpdateTask {
 
     // TODO(b/290090023): Set to false after root causing is done.
@@ -269,6 +272,16 @@
                                             : PackageManagerHelper.getLoadingProgress(
                                                     activities.get(0)),
                                     PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+                            // In case an app is archived, we need to make sure that archived state
+                            // in WorkspaceItemInfo is refreshed.
+                            if (enableSupportForArchiving() && !activities.isEmpty()) {
+                                boolean newArchivalState = activities.get(
+                                        0).getActivityInfo().isArchived;
+                                if (newArchivalState != si.isArchived()) {
+                                    si.runtimeStatusFlags ^= FLAG_ARCHIVED;
+                                    infoUpdated = true;
+                                }
+                            }
                             if (si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
                                 iconCache.getTitleAndIcon(si, si.usingLowResIcon());
                                 infoUpdated = true;
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index 6c2f589..872ce4b 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.model.data;
 
+import static com.android.launcher3.Flags.enableSupportForArchiving;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
 
 import android.content.ComponentName;
@@ -40,6 +41,7 @@
 /**
  * Represents an app in AllAppsView.
  */
+@SuppressWarnings("NewApi")
 public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory {
 
     public static final AppInfo[] EMPTY_ARRAY = new AppInfo[0];
@@ -172,6 +174,9 @@
         if (PackageManagerHelper.isAppSuspended(appInfo)) {
             info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
         }
+        if (enableSupportForArchiving() && lai.getActivityInfo().isArchived) {
+            info.runtimeStatusFlags |= FLAG_ARCHIVED;
+        }
         info.runtimeStatusFlags |= (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
                 ? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES;
 
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 5141db9..58b12b1 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.model.data;
 
+import static com.android.launcher3.Flags.enableSupportForArchiving;
+
 import android.content.Context;
 import android.content.Intent;
 import android.os.Process;
@@ -114,6 +116,12 @@
     public static final int FLAG_NOT_PINNABLE = 1 << 13;
 
     /**
+     * Flag indicating whether the package related to the item & user corresponds to that of
+     * archived app.
+     */
+    public static final int FLAG_ARCHIVED = 1 << 14;
+
+    /**
      * Status associated with the system state of the underlying item. This is calculated every
      * time a new info is created and not persisted on the disk.
      */
@@ -143,6 +151,15 @@
     }
 
     /**
+     * Returns true if the app corresponding to the item is archived. */
+    public boolean isArchived() {
+        if (!enableSupportForArchiving()) {
+            return false;
+        }
+        return (runtimeStatusFlags & FLAG_ARCHIVED) != 0;
+    }
+
+    /**
      * Indicates whether we're using a low res icon
      */
     public boolean usingLowResIcon() {
@@ -158,7 +175,7 @@
     public boolean isAppStartable() {
         return ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0)
                 && (((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0)
-                    || mProgressLevel == 100);
+                    || mProgressLevel == 100 || isArchived());
     }
 
     /**
@@ -167,7 +184,10 @@
      * progress.
      */
     public int getProgressLevel() {
-        if ((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
+        if (((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0)
+                // This condition for archived apps is so that in case unarchival/update of
+                // archived app is cancelled, the state transitions back to 0% installed state.
+                || isArchived()) {
             return mProgressLevel;
         }
         return 100;
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 3ce194d..c67ec5a 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -148,9 +148,19 @@
 
 
     public final boolean isPromise() {
-        return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON);
+        return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)
+                // For archived apps, promise icons are always ready to be displayed.
+                || isArchived();
     }
 
+    /**
+     * Returns true if the workspace item supports promise icon UI. There are a few cases where they
+     * are supported:
+     * 1. Icons to be restored via backup/restore.
+     * 2. Icons added as an auto-install app.
+     * 3. Icons added due to it being an active install session created by the user.
+     * 4. Icons for archived apps.
+     */
     public boolean hasPromiseIconUi() {
         return isPromise() && !hasStatusFlag(FLAG_SUPPORTS_WEB_UI);
     }
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index cb3c16c..ca27eb2 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.pm;
 
+import static com.android.launcher3.Flags.enableSupportForArchiving;
+
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherApps;
@@ -51,6 +53,7 @@
 /**
  * Utility class to tracking install sessions
  */
+@SuppressWarnings("NewApi")
 public class InstallSessionHelper {
 
     @NonNull
@@ -227,6 +230,11 @@
     }
 
     public boolean verifySessionInfo(@Nullable final PackageInstaller.SessionInfo sessionInfo) {
+        // For archived apps we always want to show promise icons and the checks below don't apply.
+        if (enableSupportForArchiving() && sessionInfo != null && sessionInfo.isUnarchival()) {
+            return true;
+        }
+
         return verify(sessionInfo) != null
                 && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
                 && sessionInfo.getAppIcon() != null
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index 41908d3..e4a2045 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.pm;
 
+import static com.android.launcher3.Flags.enableSupportForArchiving;
 import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle;
 import static com.android.launcher3.pm.PackageInstallInfo.STATUS_FAILED;
 import static com.android.launcher3.pm.PackageInstallInfo.STATUS_INSTALLED;
@@ -36,6 +37,7 @@
 import java.lang.ref.WeakReference;
 import java.util.Objects;
 
+@SuppressWarnings("NewApi")
 @WorkerThread
 public class InstallSessionTracker extends PackageInstaller.SessionCallback {
 
@@ -77,6 +79,12 @@
         }
 
         helper.tryQueuePromiseAppIcon(sessionInfo);
+
+        if (enableSupportForArchiving() && sessionInfo != null && sessionInfo.isUnarchival()) {
+            // For archived apps, icon could already be present on the workspace. To make sure
+            // the icon state is updated, we send a change event.
+            callback.onPackageStateChanged(PackageInstallInfo.fromInstallingState(sessionInfo));
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index fbe877d..a969c8f 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -18,12 +18,19 @@
 
 import static android.os.Process.myUserHandle;
 
+import static com.android.launcher3.Flags.enableLauncherBrMetrics;
 import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
 import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS;
 import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
 import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS;
 import static com.android.launcher3.LauncherPrefs.RESTORE_DEVICE;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_PROFILE_NOT_RESTORED;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_WIDGETS_DISABLED;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_WIDGET_REMOVED;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCHER_BR_METRICS;
 import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
 import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID;
 
@@ -53,6 +60,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.DeviceGridState;
 import com.android.launcher3.model.LoaderTask;
@@ -124,8 +132,11 @@
         FileLog.d(TAG, "performRestore: starting restore from db");
         try (SQLiteTransaction t = new SQLiteTransaction(db)) {
             RestoreDbTask task = new RestoreDbTask();
-            task.sanitizeDB(context, controller, db, new BackupManager(context));
-            task.restoreAppWidgetIdsIfExists(context, controller);
+            BackupManager backupManager = new BackupManager(context);
+            LauncherRestoreEventLogger restoreEventLogger =
+                    LauncherRestoreEventLogger.Companion.newInstance(context);
+            task.sanitizeDB(context, controller, db, backupManager, restoreEventLogger);
+            task.restoreAppWidgetIdsIfExists(context, controller, restoreEventLogger);
             t.commit();
             return true;
         } catch (Exception e) {
@@ -148,7 +159,8 @@
      */
     @VisibleForTesting
     protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db,
-            BackupManager backupManager) throws Exception {
+            BackupManager backupManager, LauncherRestoreEventLogger restoreEventLogger)
+            throws Exception {
         logFavoritesTable(db, "Old Launcher Database before sanitizing:", null, null);
         // Primary user ids
         long myProfileId = controller.getSerialNumberForUser(myUserHandle());
@@ -187,6 +199,9 @@
         Arrays.fill(args, "?");
         final String where = "profileId NOT IN (" + TextUtils.join(", ", Arrays.asList(args)) + ")";
         logFavoritesTable(db, "items to delete from unrestored profiles:", where, profileIds);
+        if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+            reportUnrestoredProfiles(db, where, profileIds, restoreEventLogger);
+        }
         int itemsDeletedCount = db.delete(Favorites.TABLE_NAME, where, profileIds);
         FileLog.d(TAG, itemsDeletedCount + " total items from unrestored user(s) were deleted");
 
@@ -346,21 +361,24 @@
         DeviceGridState deviceGridState = new DeviceGridState(context);
         FileLog.d(TAG, "restore initiated from backup: DeviceGridState=" + deviceGridState);
         LauncherPrefs.get(context).putSync(RESTORE_DEVICE.to(deviceGridState.getDeviceType()));
-        LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(true));
+        if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+            LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(true));
+        }
     }
 
     @WorkerThread
     @VisibleForTesting
-    void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller) {
+    void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller,
+            LauncherRestoreEventLogger restoreEventLogger) {
         LauncherPrefs lp = LauncherPrefs.get(context);
         if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) {
             AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID);
-            restoreAppWidgetIds(context, controller,
+            restoreAppWidgetIds(context, controller, restoreEventLogger,
                     IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(),
                     IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(),
                     host);
         } else {
-            FileLog.d(TAG, "No app widget ids were received from backup to restore.");
+            FileLog.d(TAG, "Did not receive new app widget id map during Launcher restore");
         }
 
         lp.remove(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS);
@@ -371,10 +389,13 @@
      */
     @WorkerThread
     private void restoreAppWidgetIds(Context context, ModelDbController controller,
-            int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) {
+            LauncherRestoreEventLogger launcherRestoreEventLogger, int[] oldWidgetIds,
+            int[] newWidgetIds, @NonNull AppWidgetHost host) {
         if (WidgetsModel.GO_DISABLE_WIDGETS) {
             FileLog.e(TAG, "Skipping widget ID remap as widgets not supported");
             host.deleteHost();
+            launcherRestoreEventLogger.logFavoritesItemsRestoreFailed(Favorites.ITEM_TYPE_APPWIDGET,
+                    oldWidgetIds.length, RESTORE_ERROR_WIDGETS_DISABLED);
             return;
         }
         if (!RestoreDbTask.isPending(context)) {
@@ -438,11 +459,16 @@
                         FileLog.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
                                 + oldWidgetId);
                         host.deleteAppWidgetId(newWidgetIds[i]);
+                        launcherRestoreEventLogger.logSingleFavoritesItemRestoreFailed(
+                                ITEM_TYPE_APPWIDGET,
+                                RESTORE_ERROR_WIDGET_REMOVED
+                        );
                     }
                 }
             }
         }
 
+        logFavoritesTable(controller.getDb(), "launcher db after remap widget ids", null, null);
         LauncherAppState app = LauncherAppState.getInstanceNoCreate();
         if (app != null) {
             app.getModel().forceReload();
@@ -477,17 +503,16 @@
             StringBuilder builder = new StringBuilder();
             builder.append("[");
             for (int i = 0; i < widgetIdList.size(); i++) {
-                builder.append("[")
+                builder.append("[appWidgetId=")
                         .append(widgetIdList.get(i))
-                        .append(", ")
+                        .append(", restoreFlag=")
                         .append(widgetRestoreList.get(i))
-                        .append(", ")
+                        .append(", profileId=")
                         .append(widgetProfileIdList.get(i))
                         .append("]");
             }
             builder.append("]");
-            Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
-                    + builder);
+            Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: " + builder);
         } catch (Exception ex) {
             Log.e(TAG, "Getting widget ids from the database failed", ex);
         }
@@ -546,7 +571,7 @@
      */
     public static void logFavoritesTable(SQLiteDatabase database, @NonNull String logHeader,
             String where, String[] profileIds) {
-        try (Cursor itemsToDelete = database.query(
+        try (Cursor cursor = database.query(
                 /* table */ Favorites.TABLE_NAME,
                 /* columns */ DB_COLUMNS_TO_LOG,
                 /* selection */ where,
@@ -555,26 +580,53 @@
                 /* having */ null,
                 /* orderBy */ null
         )) {
-            if (itemsToDelete.moveToFirst()) {
-                String[] columnNames = itemsToDelete.getColumnNames();
+            if (cursor.moveToFirst()) {
+                String[] columnNames = cursor.getColumnNames();
                 StringBuilder stringBuilder = new StringBuilder(logHeader + "\n");
                 do {
                     for (String columnName : columnNames) {
                         stringBuilder.append(columnName)
                                 .append("=")
-                                .append(itemsToDelete.getString(
-                                        itemsToDelete.getColumnIndex(columnName)))
+                                .append(cursor.getString(
+                                        cursor.getColumnIndex(columnName)))
                                 .append(" ");
                     }
                     stringBuilder.append("\n");
-                } while (itemsToDelete.moveToNext());
+                } while (cursor.moveToNext());
                 FileLog.d(TAG, stringBuilder.toString());
             } else {
-                FileLog.d(TAG, "logFavoritesTable: No items found from query for"
+                FileLog.d(TAG, "logFavoritesTable: No items found from query for "
                         + "\"" + logHeader + "\"");
             }
         } catch (Exception e) {
             FileLog.e(TAG, "logFavoritesTable: Error reading from database", e);
         }
     }
+
+
+    /**
+     * Queries and reports the count of each itemType to be removed due to unrestored profiles.
+     * @param database The Launcher db to query from.
+     * @param where Query being used for to find unrestored profiles
+     * @param profileIds profile ids that were not restored
+     * @param restoreEventLogger Backup/Restore Logger to report metrics
+     */
+    private void reportUnrestoredProfiles(SQLiteDatabase database, String where,
+            String[] profileIds, LauncherRestoreEventLogger restoreEventLogger) {
+        final String query = "SELECT itemType, COUNT(*) AS count FROM favorites WHERE "
+                + where + " GROUP BY itemType";
+        try (Cursor cursor = database.rawQuery(query, profileIds)) {
+            if (cursor.moveToFirst()) {
+                do {
+                    restoreEventLogger.logFavoritesItemsRestoreFailed(
+                            cursor.getInt(cursor.getColumnIndexOrThrow(ITEM_TYPE)),
+                            cursor.getInt(cursor.getColumnIndexOrThrow("count")),
+                            RESTORE_ERROR_PROFILE_NOT_RESTORED
+                    );
+                } while (cursor.moveToNext());
+            }
+        } catch (Exception e) {
+            FileLog.e(TAG, "reportUnrestoredProfiles: Error reading from database", e);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 839f98c..ff8b381 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.touch;
 
+import static com.android.launcher3.Flags.enableSupportForArchiving;
 import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_PENDING_APPWIDGET;
 import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
@@ -319,7 +320,8 @@
         }
 
         // Check for abandoned promise
-        if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {
+        if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()
+                && (!enableSupportForArchiving() || !shortcut.isArchived())) {
             String packageName = shortcut.getIntent().getComponent() != null
                     ? shortcut.getIntent().getComponent().getPackageName()
                     : shortcut.getIntent().getPackage();
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 6f305ce..dcbf7d1 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -285,7 +285,7 @@
         primaryIconView.setTranslationX(0);
         secondaryIconView.setTranslationX(0);
         if (enableOverviewIconMenu()) {
-            if (isRtl) {
+            if (primaryIconView.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
                 primaryIconView.setTranslationY(groupedTaskViewHeight - primarySnapshotHeight);
                 secondaryIconView.setTranslationY(0);
             } else {
@@ -295,25 +295,14 @@
         } else if (splitConfig.initiatedFromSeascape) {
             // if the split was initiated from seascape,
             // the task on the right (secondary) is slightly larger
-            if (isRtl) {
-                primaryIconView.setTranslationY(bottomToMidpointOffset - insetOffset);
-                secondaryIconView.setTranslationY(bottomToMidpointOffset - insetOffset
-                        + taskIconHeight);
-            } else {
-                primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
-                        + taskIconHeight);
-                secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
-            }
+            primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
+                    + taskIconHeight);
+            secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
         } else {
             // if not,
             // the task on the left (primary) is slightly larger
-            if (isRtl) {
-                primaryIconView.setTranslationY(bottomToMidpointOffset);
-                secondaryIconView.setTranslationY(bottomToMidpointOffset + taskIconHeight);
-            } else {
-                primaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
-                secondaryIconView.setTranslationY(-bottomToMidpointOffset);
-            }
+            primaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
+            secondaryIconView.setTranslationY(-bottomToMidpointOffset);
         }
 
         primaryIconView.setLayoutParams(primaryIconParams);
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 18f583d..1419dc4 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -175,6 +175,13 @@
         sTransientTaskbarStatusForTests = enable;
     }
 
+    /**
+     * Returns whether the taskbar is pinned in gesture navigation mode.
+     */
+    public static boolean isPinnedTaskbar(Context context) {
+        return INSTANCE.get(context).getInfo().isPinnedTaskbar();
+    }
+
     @Override
     public void close() {
         mDestroyed = true;
@@ -423,6 +430,12 @@
             }
             return true;
         }
+        /**
+         * Returns whether the taskbar is pinned in gesture navigation mode.
+         */
+        public boolean isPinnedTaskbar() {
+            return navigationMode == NavigationMode.NO_BUTTON && !isTransientTaskbar();
+        }
 
         /**
          * Returns {@code true} if the bounds represent a tablet.
diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
deleted file mode 100644
index f42142e..0000000
--- a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2017 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.widget;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.text.Layout;
-import android.text.StaticLayout;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.RemoteViews;
-
-import com.android.launcher3.R;
-
-/**
- * A widget host views created while the host has not bind to the system service.
- */
-public class DeferredAppWidgetHostView extends LauncherAppWidgetHostView {
-
-    private final TextPaint mPaint;
-    private Layout mSetupTextLayout;
-
-    public DeferredAppWidgetHostView(Context context) {
-        super(context);
-        setWillNotDraw(false);
-
-        mPaint = new TextPaint();
-        mPaint.setColor(Color.WHITE);
-        mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
-                mLauncher.getDeviceProfile().iconTextSizePx,
-                getResources().getDisplayMetrics()));
-        setBackgroundResource(R.drawable.bg_deferred_app_widget);
-    }
-
-    @Override
-    public void updateAppWidget(RemoteViews remoteViews) {
-        // Not allowed
-    }
-
-    @Override
-    public void addView(View child) {
-        // Not allowed
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        AppWidgetProviderInfo info = getAppWidgetInfo();
-        if (info == null || TextUtils.isEmpty(info.label)) {
-            return;
-        }
-
-        // Use double padding so that there is extra space between background and text if possible.
-        int availableWidth = getMeasuredWidth() - 2 * (getPaddingLeft() + getPaddingRight());
-        if (availableWidth <= 0) {
-            availableWidth = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
-        }
-        if (mSetupTextLayout != null && mSetupTextLayout.getText().equals(info.label)
-                && mSetupTextLayout.getWidth() == availableWidth) {
-            return;
-        }
-        mSetupTextLayout = new StaticLayout(info.label, mPaint, availableWidth,
-                Layout.Alignment.ALIGN_CENTER, 1, 0, true);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mSetupTextLayout != null) {
-            canvas.translate((getWidth() - mSetupTextLayout.getWidth()) / 2,
-                    (getHeight() - mSetupTextLayout.getHeight()) / 2);
-            mSetupTextLayout.draw(canvas);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
index 9c21ea2..739e204 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
@@ -89,7 +89,7 @@
     @NonNull
     public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
-        return mHolder.onCreateView(context, appWidgetId, appWidget);
+        return mHolder.onCreateView(context, appWidgetId);
     }
 
     /**
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 12b47e6..e0de269 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -45,7 +45,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -96,8 +95,6 @@
 
     private boolean mTrackingWidgetUpdate = false;
 
-    private boolean mIsWidgetCachingDisabled = false;
-
     public LauncherAppWidgetHostView(Context context) {
         super(context);
         mLauncher = Launcher.getLauncher(context);
@@ -144,10 +141,6 @@
         }
     }
 
-    public void setIsWidgetCachingDisabled(boolean isWidgetCachingDisabled) {
-        mIsWidgetCachingDisabled = isWidgetCachingDisabled;
-    }
-
     @Override
     @TargetApi(Build.VERSION_CODES.Q)
     public void updateAppWidget(RemoteViews remoteViews) {
@@ -157,19 +150,11 @@
                     TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId());
             mTrackingWidgetUpdate = false;
         }
-        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()
-                && !mIsWidgetCachingDisabled) {
+        if (isDeferringUpdates()) {
             mLastRemoteViews = remoteViews;
-            if (isDeferringUpdates()) {
-                return;
-            }
-        } else {
-            if (isDeferringUpdates()) {
-                mLastRemoteViews = remoteViews;
-                return;
-            }
-            mLastRemoteViews = null;
+            return;
         }
+        mLastRemoteViews = null;
 
         super.updateAppWidget(remoteViews);
 
@@ -438,22 +423,6 @@
         scheduleNextAdvance();
     }
 
-    public void reInflate() {
-        if (!isAttachedToWindow()) {
-            return;
-        }
-        LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
-        if (info == null) {
-            // This occurs when LauncherAppWidgetHostView is used to render a preview layout.
-            return;
-        }
-        // Remove and rebind the current widget (which was inflated in the wrong
-        // orientation), but don't delete it from the database
-        mLauncher.removeItem(this, info, false  /* deleteFromDb */,
-                "widget removed because of configuration change");
-        mLauncher.bindAppWidget(info);
-    }
-
     @Override
     protected boolean shouldAllowDirectClick() {
         if (getTag() instanceof ItemInfo) {
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index 6acc83d..fbd48cf 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -28,7 +28,6 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.SparseArray;
-import android.widget.RemoteViews;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
@@ -36,10 +35,8 @@
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.testing.TestLogging;
@@ -70,11 +67,9 @@
     private final AppWidgetHost mWidgetHost;
 
     @NonNull
-    private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
+    protected final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
     @NonNull
     private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
-    @NonNull
-    private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>();
 
     protected int mFlags = FLAG_STATE_IS_NORMAL;
 
@@ -121,25 +116,12 @@
      * Update any views which have been deferred because the host was not listening.
      */
     protected void updateDeferredView() {
+        // Update any views which have been deferred because the host was not listening.
         // We go in reverse order and inflate any deferred or cached widget
         for (int i = mViews.size() - 1; i >= 0; i--) {
             LauncherAppWidgetHostView view = mViews.valueAt(i);
-            if (view instanceof DeferredAppWidgetHostView) {
-                view.reInflate();
-            }
-            if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-                final int appWidgetId = mViews.keyAt(i);
-                if (view == mDeferredViews.get(appWidgetId)) {
-                    // If the widget view was deferred, we'll need to call super.createView here
-                    // to make the binder call to system process to fetch cumulative updates to this
-                    // widget, as well as setting up this view for future updates.
-                    mWidgetHost.createView(view.mLauncher, appWidgetId,
-                            view.getAppWidgetInfo());
-                    // At this point #onCreateView should have been called, which in turn returned
-                    // the deferred view. There's no reason to keep the reference anymore, so we
-                    // removed it here.
-                    mDeferredViews.remove(appWidgetId);
-                }
+            if (view instanceof PendingAppWidgetHostView pv) {
+                pv.reInflate();
             }
         }
     }
@@ -173,12 +155,6 @@
     public void deleteAppWidgetId(int appWidgetId) {
         mWidgetHost.deleteAppWidgetId(appWidgetId);
         mViews.remove(appWidgetId);
-        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-            final LauncherAppState state = LauncherAppState.getInstance(mContext);
-            synchronized (state.mCachedRemoteViews) {
-                state.mCachedRemoteViews.delete(appWidgetId);
-            }
-        }
     }
 
     /**
@@ -319,17 +295,6 @@
         if (WidgetsModel.GO_DISABLE_WIDGETS) {
             return;
         }
-        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-            // Cache the content from the widgets when Launcher stops listening to widget updates
-            final LauncherAppState state = LauncherAppState.getInstance(mContext);
-            synchronized (state.mCachedRemoteViews) {
-                for (int i = 0; i < mViews.size(); i++) {
-                    final int appWidgetId = mViews.keyAt(i);
-                    final LauncherAppWidgetHostView view = mViews.get(appWidgetId);
-                    state.mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews);
-                }
-            }
-        }
         mWidgetHost.stopListening();
         setListeningFlag(false);
     }
@@ -360,6 +325,7 @@
     @NonNull
     public AppWidgetHostView createView(@NonNull Context context, int appWidgetId,
             @NonNull LauncherAppWidgetProviderInfo appWidget) {
+
         if (appWidget.isCustomWidget()) {
             LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
             lahv.setAppWidget(0, appWidget);
@@ -369,24 +335,8 @@
             // Since the launcher hasn't started listening to widget updates, we can't simply call
             // super.createView here because the later will make a binder call to retrieve
             // RemoteViews from system process.
-            // TODO: have launcher always listens to widget updates in background so that this
-            //  check can be removed altogether.
-            if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-                final RemoteViews cachedRemoteViews = getCachedRemoteViews(appWidgetId);
-                if (cachedRemoteViews != null) {
-                    // We've found RemoteViews from cache for this widget, so we will instantiate a
-                    // widget host view and populate it with the cached RemoteViews.
-                    final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
-                    view.setAppWidget(appWidgetId, appWidget);
-                    view.updateAppWidget(cachedRemoteViews);
-                    mDeferredViews.put(appWidgetId, view);
-                    mViews.put(appWidgetId, view);
-                    return view;
-                }
-            }
-            // If cache misses or not enabled, a placeholder for the widget will be returned.
-            DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
-            view.setAppWidget(appWidgetId, appWidget);
+            LauncherAppWidgetHostView view =
+                    new PendingAppWidgetHostView(context, appWidgetId, appWidget);
             mViews.put(appWidgetId, view);
             return view;
         } else {
@@ -402,7 +352,7 @@
                 // will update.
                 LauncherAppWidgetHostView view = mViews.get(appWidgetId);
                 if (view == null) {
-                    view = onCreateView(mContext, appWidgetId, appWidget);
+                    view = onCreateView(mContext, appWidgetId);
                 }
                 view.setAppWidget(appWidgetId, appWidget);
                 view.switchToErrorView();
@@ -423,23 +373,17 @@
 
     /**
      * Called to return a proper view when creating a view
-     * @param context The context for which the widget view is created
+     *
+     * @param context     The context for which the widget view is created
      * @param appWidgetId The ID of the added widget
-     * @param appWidget The provider info of the added widget
      * @return A view for the specified app widget
      */
     @NonNull
-    public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
-            AppWidgetProviderInfo appWidget) {
+    public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId) {
         final LauncherAppWidgetHostView view;
         if (getPendingView(appWidgetId) != null) {
             view = getPendingView(appWidgetId);
             removePendingView(appWidgetId);
-        } else if (mDeferredViews.get(appWidgetId) != null) {
-            // In case the widget view is deferred, we will simply return the deferred view as
-            // opposed to instantiate a new instance of LauncherAppWidgetHostView since launcher
-            // already added the former to the workspace.
-            view = mDeferredViews.get(appWidgetId);
         } else {
             view = new LauncherAppWidgetHostView(context);
         }
@@ -453,10 +397,6 @@
     public void clearViews() {
         LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost;
         tempHost.clearViews();
-        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-            // Clear previously cached content from existing widgets
-            mDeferredViews.clear();
-        }
         mViews.clear();
     }
 
@@ -496,14 +436,6 @@
         return (flags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN;
     }
 
-    @Nullable
-    private RemoteViews getCachedRemoteViews(int appWidgetId) {
-        final LauncherAppState state = LauncherAppState.getInstance(mContext);
-        synchronized (state.mCachedRemoteViews) {
-            return state.mCachedRemoteViews.get(appWidgetId);
-        }
-    }
-
     /**
      * Returns the new LauncherWidgetHolder instance
      */
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 1c88c4a..2bd4c7e 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -24,11 +24,13 @@
 import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.text.Layout;
 import android.text.StaticLayout;
 import android.text.TextPaint;
+import android.text.TextUtils;
 import android.util.SizeF;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
@@ -46,7 +48,6 @@
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.util.Themes;
 
 import java.util.List;
@@ -56,11 +57,20 @@
     private static final float SETUP_ICON_SIZE_FACTOR = 2f / 5;
     private static final float MIN_SATUNATION = 0.7f;
 
+    private static final int FLAG_DRAW_SETTINGS = 1;
+    private static final int FLAG_DRAW_ICON = 2;
+    private static final int FLAG_DRAW_LABEL = 4;
+
+    private static final int DEFERRED_ALPHA = 0x77;
+
     private final Rect mRect = new Rect();
     private OnClickListener mClickListener;
     private final LauncherAppWidgetInfo mInfo;
     private final int mStartState;
     private final boolean mDisabledForSafeMode;
+    private final CharSequence mLabel;
+
+    private int mDragFlags;
 
     private Drawable mCenterDrawable;
     private Drawable mSettingIconDrawable;
@@ -72,18 +82,8 @@
 
     public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
             IconCache cache, boolean disabledForSafeMode) {
-        super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
-
-        mInfo = info;
-        mStartState = info.restoreStatus;
-        mDisabledForSafeMode = disabledForSafeMode;
-
-        mPaint = new TextPaint();
-        mPaint.setColor(Themes.getAttrColor(getContext(), android.R.attr.textColorPrimary));
-        mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
-                mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
-        setBackgroundResource(R.drawable.pending_widget_bg);
-        setWillNotDraw(false);
+        this(context, info, disabledForSafeMode,
+                context.getResources().getText(R.string.gadget_complete_setup_text));
 
         super.updateAppWidget(null);
         setOnClickListener(mLauncher.getItemOnClickListener());
@@ -97,15 +97,62 @@
         }
     }
 
+    public PendingAppWidgetHostView(
+            Context context, int appWidgetId, LauncherAppWidgetProviderInfo appWidget) {
+        this(context, new LauncherAppWidgetInfo(appWidgetId, appWidget.provider), false,
+                appWidget.label);
+        getBackground().mutate().setAlpha(DEFERRED_ALPHA);
+
+        mCenterDrawable = new ColorDrawable(Color.TRANSPARENT);
+        mDragFlags = FLAG_DRAW_LABEL;
+        mDrawableSizeChanged = true;
+    }
+
+    private PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
+            boolean disabledForSafeMode, CharSequence label) {
+        super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
+
+        mInfo = info;
+        mStartState = info.restoreStatus;
+        mDisabledForSafeMode = disabledForSafeMode;
+        mLabel = label;
+
+        mPaint = new TextPaint();
+        mPaint.setColor(Themes.getAttrColor(getContext(), android.R.attr.textColorPrimary));
+        mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
+                mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
+
+        setWillNotDraw(false);
+        setBackgroundResource(R.drawable.pending_widget_bg);
+    }
+
     @Override
     public void updateAppWidget(RemoteViews remoteViews) {
         WidgetManagerHelper widgetManagerHelper = new WidgetManagerHelper(getContext());
         if (widgetManagerHelper.isAppWidgetRestored(mInfo.appWidgetId)) {
-            super.updateAppWidget(remoteViews);
             reInflate();
         }
     }
 
+    /**
+     * Forces the Launcher to reinflate the widget view
+     */
+    public void reInflate() {
+        if (!isAttachedToWindow()) {
+            return;
+        }
+        LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+        if (info == null) {
+            // This occurs when LauncherAppWidgetHostView is used to render a preview layout.
+            return;
+        }
+        // Remove and rebind the current widget (which was inflated in the wrong
+        // orientation), but don't delete it from the database
+        mLauncher.removeItem(this, info, false  /* deleteFromDb */,
+                "widget removed because of configuration change");
+        mLauncher.bindAppWidget(info);
+    }
+
     @Override
     public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
             int maxHeight) {
@@ -147,7 +194,10 @@
             mCenterDrawable.setCallback(null);
             mCenterDrawable = null;
         }
+        mDragFlags = 0;
         if (info.bitmap.icon != null) {
+            mDragFlags = FLAG_DRAW_ICON;
+
             Drawable widgetCategoryIcon = getWidgetCategoryIcon();
             // The view displays three modes,
             //   1) App icon in the center
@@ -169,6 +219,8 @@
                         : widgetCategoryIcon;
                 mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
                 updateSettingColor(info.bitmap.color);
+
+                mDragFlags |= FLAG_DRAW_SETTINGS | FLAG_DRAW_LABEL;
             } else {
                 mCenterDrawable = widgetCategoryIcon == null
                         ? newPendingIcon(getContext(), info)
@@ -239,68 +291,63 @@
         int availableWidth = getWidth() - paddingLeft - paddingRight - 2 * minPadding;
         int availableHeight = getHeight() - paddingTop - paddingBottom - 2 * minPadding;
 
-        if (mSettingIconDrawable == null) {
-            int maxSize = grid.iconSizePx;
-            int size = Math.min(maxSize, Math.min(availableWidth, availableHeight));
+        float iconSize = ((mDragFlags & FLAG_DRAW_ICON) == 0) ? 0
+                : Math.max(0, Math.min(availableWidth, availableHeight));
+        // Use twice the setting size factor, as the setting is drawn at a corner and the
+        // icon is drawn in the center.
+        float settingIconScaleFactor = ((mDragFlags & FLAG_DRAW_SETTINGS) == 0) ? 0
+                : 1 + SETUP_ICON_SIZE_FACTOR * 2;
 
-            mRect.set(0, 0, size, size);
-            mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2);
-            mCenterDrawable.setBounds(mRect);
-        } else  {
-            float iconSize = Math.max(0, Math.min(availableWidth, availableHeight));
+        int maxSize = Math.max(availableWidth, availableHeight);
+        if (iconSize * settingIconScaleFactor > maxSize) {
+            // There is an overlap
+            iconSize = maxSize / settingIconScaleFactor;
+        }
 
-            // Use twice the setting size factor, as the setting is drawn at a corner and the
-            // icon is drawn in the center.
-            float settingIconScaleFactor = 1 + SETUP_ICON_SIZE_FACTOR * 2;
-            int maxSize = Math.max(availableWidth, availableHeight);
-            if (iconSize * settingIconScaleFactor > maxSize) {
-                // There is an overlap
-                iconSize = maxSize / settingIconScaleFactor;
+        int actualIconSize = (int) Math.min(iconSize, grid.iconSizePx);
+
+        // Icon top when we do not draw the text
+        int iconTop = (getHeight() - actualIconSize) / 2;
+        mSetupTextLayout = null;
+
+        if (availableWidth > 0 && !TextUtils.isEmpty(mLabel)
+                && ((mDragFlags & FLAG_DRAW_LABEL) != 0)) {
+            // Recreate the setup text.
+            mSetupTextLayout = new StaticLayout(
+                    mLabel, mPaint, availableWidth, Layout.Alignment.ALIGN_CENTER, 1, 0, true);
+            int textHeight = mSetupTextLayout.getHeight();
+
+            // Extra icon size due to the setting icon
+            float minHeightWithText = textHeight + actualIconSize * settingIconScaleFactor
+                    + grid.iconDrawablePaddingPx;
+
+            if (minHeightWithText < availableHeight) {
+                // We can draw the text as well
+                iconTop = (getHeight() - textHeight
+                        - grid.iconDrawablePaddingPx - actualIconSize) / 2;
+
+            } else {
+                // We can't draw the text. Let the iconTop be same as before.
+                mSetupTextLayout = null;
             }
+        }
 
-            int actualIconSize = (int) Math.min(iconSize, grid.iconSizePx);
+        mRect.set(0, 0, actualIconSize, actualIconSize);
+        mRect.offset((getWidth() - actualIconSize) / 2, iconTop);
+        mCenterDrawable.setBounds(mRect);
 
-            // Icon top when we do not draw the text
-            int iconTop = (getHeight() - actualIconSize) / 2;
-            mSetupTextLayout = null;
-
-            if (availableWidth > 0) {
-                // Recreate the setup text.
-                mSetupTextLayout = new StaticLayout(
-                        getResources().getText(R.string.gadget_complete_setup_text), mPaint,
-                        availableWidth, Layout.Alignment.ALIGN_CENTER, 1, 0, true);
-                int textHeight = mSetupTextLayout.getHeight();
-
-                // Extra icon size due to the setting icon
-                float minHeightWithText = textHeight + actualIconSize * settingIconScaleFactor
-                        + grid.iconDrawablePaddingPx;
-
-                if (minHeightWithText < availableHeight) {
-                    // We can draw the text as well
-                    iconTop = (getHeight() - textHeight -
-                            grid.iconDrawablePaddingPx - actualIconSize) / 2;
-
-                } else {
-                    // We can't draw the text. Let the iconTop be same as before.
-                    mSetupTextLayout = null;
-                }
-            }
-
-            mRect.set(0, 0, actualIconSize, actualIconSize);
-            mRect.offset((getWidth() - actualIconSize) / 2, iconTop);
-            mCenterDrawable.setBounds(mRect);
-
+        if (mSettingIconDrawable != null) {
             mRect.left = paddingLeft + minPadding;
             mRect.right = mRect.left + (int) (SETUP_ICON_SIZE_FACTOR * actualIconSize);
             mRect.top = paddingTop + minPadding;
             mRect.bottom = mRect.top + (int) (SETUP_ICON_SIZE_FACTOR * actualIconSize);
             mSettingIconDrawable.setBounds(mRect);
+        }
 
-            if (mSetupTextLayout != null) {
-                // Set up position for dragging the text
-                mRect.left = paddingLeft + minPadding;
-                mRect.top = mCenterDrawable.getBounds().bottom + grid.iconDrawablePaddingPx;
-            }
+        if (mSetupTextLayout != null) {
+            // Set up position for dragging the text
+            mRect.left = paddingLeft + minPadding;
+            mRect.top = mCenterDrawable.getBounds().bottom + grid.iconDrawablePaddingPx;
         }
     }
 
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 5cf96c8..2596b75 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -23,6 +23,14 @@
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
+
+        <receiver android:name="com.android.launcher3.compat.PromiseIconUiTest$UnarchiveBroadcastReceiver"
+                  android:enabled="true"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.UNARCHIVE_PACKAGE"/>
+            </intent-filter>
+        </receiver>
     </application>
 
     <instrumentation
diff --git a/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
index fb364ad..dbb2715 100644
--- a/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
+++ b/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
@@ -64,7 +64,7 @@
         runOnExecutorSync(MODEL_EXECUTOR, () -> {
             ModelDbController controller = model.getModelDbController();
             // Migrate any previous data so that the DB state is correct
-            controller.tryMigrateDB();
+            controller.tryMigrateDB(null /* restoreEventLogger */);
 
             // Create DB again to load fresh data
             controller.createEmptyDB();
diff --git a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
index 8200c94..2dc1cb2 100644
--- a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
+++ b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
@@ -15,24 +15,38 @@
  */
 package com.android.launcher3.compat;
 
+import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.text.TextUtils;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.SystemUtil;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
+import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.rule.ViewCaptureRule;
 
 import org.junit.After;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.IOException;
 import java.util.UUID;
 
 
@@ -43,6 +57,14 @@
 @RunWith(AndroidJUnit4.class)
 public class TaplPromiseIconUiTest extends AbstractLauncherUiTest {
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    public static final String PACKAGE_NAME = "test.promise.app";
+    public static final String DUMMY_PACKAGE = "com.example.android.aardwolf";
+    public static final String DUMMY_LABEL = "Aardwolf";
+
     private int mSessionId = -1;
 
     @Override
@@ -55,18 +77,19 @@
     }
 
     @After
-    public void tearDown() {
+    public void tearDown() throws IOException {
         if (mSessionId > -1) {
             mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
         }
+        TestUtil.uninstallDummyApp();
     }
 
     /**
      * Create a session and return the id.
      */
-    private int createSession(String label, Bitmap icon) throws Throwable {
+    private int createSession(String packageName, String label, Bitmap icon) throws Throwable {
         SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
-        params.setAppPackageName("test.promise.app");
+        params.setAppPackageName(packageName);
         params.setAppLabel(label);
         params.setAppIcon(icon);
         params.setInstallReason(PackageManager.INSTALL_REASON_USER);
@@ -80,7 +103,8 @@
                 info != null && TextUtils.equals(info.title, appLabel);
 
         // Create and add test session
-        mSessionId = createSession(appLabel, Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8));
+        mSessionId = createSession(PACKAGE_NAME, appLabel,
+                Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8));
 
         // Verify promise icon is added
         waitForLauncherCondition("Test Promise App not found on workspace", launcher ->
@@ -103,7 +127,7 @@
                 info != null && TextUtils.equals(info.title, appLabel);
 
         // Create and add test session without icon or label
-        mSessionId = createSession(null, null);
+        mSessionId = createSession(PACKAGE_NAME, null, null);
 
         // Sleep for duration of animation if a view was to be added + some buffer time.
         Thread.sleep(Launcher.NEW_APPS_PAGE_MOVE_DELAY + Launcher.NEW_APPS_ANIMATION_DELAY + 500);
@@ -112,4 +136,42 @@
         waitForLauncherCondition("Test Promise App not found on workspace", launcher ->
                 launcher.getWorkspace().getFirstMatch(findPromiseApp) == null);
     }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+    public void testPromiseIcon_addedArchivedApp() throws Throwable {
+        installDummyAppAndWaitForUIUpdate();
+        assertThat(
+                SystemUtil.runShellCommand(
+                        String.format("pm archive %s", DUMMY_PACKAGE))).isEqualTo(
+                "Success\n");
+
+        final ItemOperator findPromiseApp = (info, view) ->
+                info != null && TextUtils.equals(info.title, DUMMY_LABEL);
+
+        // Create and add test session
+        mSessionId = createSession(DUMMY_PACKAGE, /* label= */ "",
+                Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8));
+
+        // Verify promise icon is added
+        waitForLauncherCondition("Test Promise App not found on workspace", launcher ->
+                launcher.getWorkspace().getFirstMatch(findPromiseApp) != null);
+
+        // Remove session
+        mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
+        mSessionId = -1;
+    }
+
+    // Dummy receiver to fulfill archiving platform requirements, unused in reality.
+    public static class UnarchiveBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+        }
+    }
+
+    private void installDummyAppAndWaitForUIUpdate() throws IOException {
+        TestUtil.installDummyApp();
+        mLauncher.waitForModelQueueCleared();
+        mLauncher.waitForLauncherInitialized();
+    }
 }
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 10d9133..733f1e9 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -59,6 +59,7 @@
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
 import com.android.launcher3.model.ModelDbController;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.LauncherModelHelper;
@@ -90,6 +91,7 @@
     private SQLiteDatabase mMockDb;
     private Cursor mMockCursor;
     private LauncherPrefs mPrefs;
+    private LauncherRestoreEventLogger mMockRestoreEventLogger;
 
     @Before
     public void setup() {
@@ -100,6 +102,7 @@
         mMockDb = mock(SQLiteDatabase.class);
         mMockCursor = mock(Cursor.class);
         mPrefs = new LauncherPrefs(mContext);
+        mMockRestoreEventLogger = mock(LauncherRestoreEventLogger.class);
     }
 
     @After
@@ -178,7 +181,7 @@
         assertEquals(10, getItemCountForProfile(db, myProfileId_old));
         assertEquals(6, getItemCountForProfile(db, workProfileId_old));
 
-        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm);
+        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm, mMockRestoreEventLogger);
 
         // All the data has been migrated to the new user ids
         assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -207,7 +210,7 @@
         assertEquals(10, getItemCountForProfile(db, myProfileId_old));
         assertEquals(6, getItemCountForProfile(db, workProfileId_old));
 
-        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm);
+        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm, mMockRestoreEventLogger);
 
         // All the data has been migrated to the new user ids
         assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -219,7 +222,7 @@
     @Test
     public void givenLauncherPrefsHasNoIds_whenRestoreAppWidgetIdsIfExists_thenIdsAreRemoved() {
         // When
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
         // Then
         assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
     }
@@ -235,7 +238,7 @@
 
         // When
         setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
 
         // Then
         assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
@@ -257,7 +260,7 @@
 
         // When
         setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
 
         // Then
         assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
@@ -280,12 +283,13 @@
         when(mMockDb.query(any(), any(), any(), any(), any(), any(), any()))
                 .thenReturn(mMockCursor);
         when(mMockCursor.moveToFirst()).thenReturn(true);
+        when(mMockCursor.getColumnNames()).thenReturn(new String[] {});
         when(mMockCursor.isAfterLast()).thenReturn(true);
         RestoreDbTask.setPending(mContext);
 
         // When
         setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
 
         // Then
         assertThat(expectedHost.getAppWidgetIds()).isEqualTo(allExpectedIds);
diff --git a/tests/src/com/android/launcher3/util/ModelTestExtensions.kt b/tests/src/com/android/launcher3/util/ModelTestExtensions.kt
index 9d9bd517..6bd182b 100644
--- a/tests/src/com/android/launcher3/util/ModelTestExtensions.kt
+++ b/tests/src/com/android/launcher3/util/ModelTestExtensions.kt
@@ -30,7 +30,7 @@
         loadModelSync()
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
             modelDbController.run {
-                tryMigrateDB()
+                tryMigrateDB(null /* restoreEventLogger */)
                 createEmptyDB()
                 clearEmptyDbFlag()
             }
@@ -72,7 +72,7 @@
         loadModelSync()
         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
             val controller: ModelDbController = modelDbController
-            controller.tryMigrateDB()
+            controller.tryMigrateDB(null /* restoreEventLogger */)
             modelDbController.newTransaction().use { transaction ->
                 val values =
                     ContentValues().apply {
diff --git a/tests/src/com/android/launcher3/util/TestUtil.java b/tests/src/com/android/launcher3/util/TestUtil.java
index 683f323..95444ba 100644
--- a/tests/src/com/android/launcher3/util/TestUtil.java
+++ b/tests/src/com/android/launcher3/util/TestUtil.java
@@ -103,7 +103,9 @@
             out.close();
 
             final String result = UiDevice.getInstance(instrumentation)
-                    .executeShellCommand("pm install --user " + userId + " " + apkFilename);
+                    .executeShellCommand(String.format("pm install -i %s --user ",
+                            instrumentation.getContext().getPackageName())
+                            + userId + " " + apkFilename);
             Assert.assertTrue(
                     "Failed to install wellbeing test apk; make sure the device is rooted",
                     "Success".equals(result.replaceAll("\\s+", "")));
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7d3807e..508f39b 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -278,21 +278,35 @@
         assertNotNull("Cannot find content provider for " + testProviderAuthority, pi);
         ComponentName cn = new ComponentName(pi.packageName, pi.name);
 
+        final int iterations = isLauncherTest ? 300 : 100;
+
         if (pm.getComponentEnabledSetting(cn) != COMPONENT_ENABLED_STATE_ENABLED) {
             if (TestHelpers.isInLauncherProcess()) {
                 pm.setComponentEnabledSetting(cn, COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP);
             } else {
                 try {
                     final int userId = getContext().getUserId();
+                    final String launcherPidCommand = "pidof " + pi.packageName;
+                    final String initialPid = mDevice.executeShellCommand(launcherPidCommand);
+
                     mDevice.executeShellCommand(
                             "pm enable --user " + userId + " " + cn.flattenToString());
+
+                    // Wait for Launcher restart after enabling test provider.
+                    for (int i = 0; i < iterations; ++i) {
+                        final String currentPid = mDevice.executeShellCommand(launcherPidCommand)
+                                .replaceAll("\\s", "");
+                        if (!currentPid.isEmpty() && !currentPid.equals(initialPid)) break;
+                        if (i == iterations - 1) {
+                            fail("Launcher didn't restart after enabling test provider");
+                        }
+                        SystemClock.sleep(100);
+                    }
                 } catch (IOException e) {
                     fail(e.toString());
                 }
             }
 
-            final int iterations = isLauncherTest ? 300 : 100;
-
             // Wait for Launcher content provider to become enabled.
             for (int i = 0; i < iterations; ++i) {
                 final ContentProviderClient testProvider = getContext().getContentResolver()
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index c6fa31d..902ad5b 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -17,6 +17,7 @@
 package com.android.launcher3.tapl;
 
 import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_MODAL_TASK_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_SPLIT_SELECT_ORDINAL;
 
 import androidx.annotation.NonNull;
 import androidx.test.uiautomator.By;
@@ -42,8 +43,11 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "tap split menu item")) {
-            mLauncher.clickLauncherObject(
-                    mLauncher.findObjectInContainer(mMenu, By.textStartsWith("Split")));
+            mLauncher.runToState(() -> mLauncher.clickLauncherObject(
+                            mLauncher.findObjectInContainer(mMenu, By.textStartsWith("Split"))),
+                    OVERVIEW_SPLIT_SELECT_ORDINAL,
+                    "tapping split menu item"
+            );
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "tapped split menu item")) {