Adds logging for Launcher restore metrics in Launcher and LoaderTask

- Adds flag for indicating when we are loading after a restore, separate from the pending restore flag
- Adds many success/failure scenario metrics when loading and binding items

Flag: ACONFIG enable_launcher_br_metrics DEVELOPMENT
Test: locally verified
Bug: 307527314
Change-Id: I9d2660f6d9d7cd5813072201e96b1a64aec4ea4b
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index e41a8a5..11dc6e2 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -52,8 +52,10 @@
 import static com.android.launcher3.LauncherConstants.TraceEvents.ON_NEW_INTENT_EVT;
 import static com.android.launcher3.LauncherConstants.TraceEvents.ON_RESUME_EVT;
 import static com.android.launcher3.LauncherConstants.TraceEvents.ON_START_EVT;
+import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
 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.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.EDIT_MODE;
 import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
@@ -63,6 +65,8 @@
 import static com.android.launcher3.LauncherState.NO_SCALE;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
 import static com.android.launcher3.Utilities.postAsyncCallback;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_BIND_FAILURE;
+import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_INVALID_LOCATION;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
 import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
@@ -162,6 +166,7 @@
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.apppairs.AppPairIcon;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
 import com.android.launcher3.celllayout.CellPosMapper;
 import com.android.launcher3.celllayout.CellPosMapper.CellPos;
 import com.android.launcher3.celllayout.CellPosMapper.TwoPanelCellPosMapper;
@@ -2158,9 +2163,15 @@
         int newItemsScreenId = -1;
         int end = items.size();
         View newView = null;
+        LauncherRestoreEventLogger restoreEventLogger = null;
+        Boolean isRestoreFromBackup = (Boolean) LauncherPrefs.get(getApplicationContext())
+                .get(IS_FIRST_LOAD_AFTER_RESTORE);
+        if (isRestoreFromBackup) {
+            restoreEventLogger = LauncherRestoreEventLogger.Companion
+                    .newInstance(getApplicationContext());
+        }
         for (int i = 0; i < end; i++) {
             final ItemInfo item = items.get(i);
-
             // Short circuit if we are loading dock items for a configuration which has no dock
             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
                     mHotseat == null) {
@@ -2187,12 +2198,17 @@
                             (FolderInfo) item);
                     break;
                 }
-                case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                case ITEM_TYPE_APPWIDGET:
                 case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: {
-                    view = inflateAppWidget((LauncherAppWidgetInfo) item);
+                    view = inflateAppWidget((LauncherAppWidgetInfo) item, restoreEventLogger);
                     if (view == null) {
                         continue;
                     }
+                    // Widgets have more checks when inflating, so we have to wait until here
+                    // to mark restored, instead of logging in LoaderTask.
+                    if (restoreEventLogger != null) {
+                        restoreEventLogger.logSingleFavoritesItemRestored(item.itemType);
+                    }
                     break;
                 }
                 default:
@@ -2216,6 +2232,10 @@
                     if (FeatureFlags.IS_STUDIO_BUILD) {
                         throw (new RuntimeException(desc));
                     } else {
+                        if (restoreEventLogger != null) {
+                            restoreEventLogger.logSingleFavoritesItemRestoreFailed(item.itemType,
+                                    RESTORE_ERROR_INVALID_LOCATION);
+                        }
                         getModelWriter().deleteItemFromDatabase(item, desc);
                         continue;
                     }
@@ -2274,6 +2294,9 @@
         } else if (focusFirstItemForAccessibility && viewToFocus != null) {
             viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         }
+        if (restoreEventLogger != null) {
+            restoreEventLogger.reportLauncherRestoreResults();
+        }
         workspace.requestLayout();
     }
 
@@ -2281,14 +2304,15 @@
      * Add the views for a widget to the workspace.
      */
     public void bindAppWidget(LauncherAppWidgetInfo item) {
-        View view = inflateAppWidget(item);
+        View view = inflateAppWidget(item, null);
         if (view != null) {
             mWorkspace.addInScreen(view, item);
             mWorkspace.requestLayout();
         }
     }
 
-    private View inflateAppWidget(LauncherAppWidgetInfo item) {
+    private View inflateAppWidget(LauncherAppWidgetInfo item,
+            @Nullable LauncherRestoreEventLogger restoreEventLogger) {
         if (item.hasOptionFlag(LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET)) {
             item.providerName = QsbContainerView.getSearchComponentName(this);
             if (item.providerName == null) {
@@ -2305,11 +2329,9 @@
         }
 
         TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
-
         try {
             final LauncherAppWidgetProviderInfo appWidgetInfo;
             String removalReason = "";
-
             if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
                 // If the provider is not ready, bind as a pending widget.
                 appWidgetInfo = null;
@@ -2349,6 +2371,10 @@
                             "Removing restored widget: id=" + item.appWidgetId
                             + " belongs to component " + item.providerName + " user " + item.user
                             + ", as the provider is null and " + removalReason);
+                    if (restoreEventLogger != null) {
+                        restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+                                ITEM_TYPE_APPWIDGET, RESTORE_ERROR_BIND_FAILURE);
+                    }
                     return null;
                 }
 
@@ -2419,6 +2445,10 @@
                 if (appWidgetInfo == null) {
                     FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
                     getModelWriter().deleteWidgetInfo(item, getAppWidgetHolder(), removalReason);
+                    if (restoreEventLogger != null) {
+                        restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+                                ITEM_TYPE_APPWIDGET, RESTORE_ERROR_BIND_FAILURE);
+                    }
                     return null;
                 }