diff --git a/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt index 645ecf41a1..fc450f0e96 100644 --- a/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt +++ b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt @@ -29,8 +29,8 @@ class LauncherRestoreEventLoggerImpl(val context: Context) : LauncherRestoreEven @BackupRestoreDataType private const val DATA_TYPE_APP_PAIR = "app_pair" } - private val backupManager: BackupManager = BackupManager(context) - private val restoreEventLogger: BackupRestoreEventLogger = backupManager.delayedRestoreLogger + private val restoreEventLogger: BackupRestoreEventLogger = + BackupManager(context).delayedRestoreLogger /** * For logging when multiple items of a given data type failed to restore. @@ -72,6 +72,18 @@ class LauncherRestoreEventLoggerImpl(val context: Context) : LauncherRestoreEven } } + /** + * Helper to log successfully restoring multiple items from the Favorites table. + * + * @param favoritesId The id of the item type from [Favorites] that was restored. + * @param count number of items that restored. + */ + override fun logFavoritesItemsRestored(favoritesId: Int, count: Int) { + if (Flags.enableLauncherBrMetrics()) { + restoreEventLogger.logItemsRestored(favoritesIdToDataType(favoritesId), count) + } + } + /** * Helper to log a failure to restore a single item from the Favorites table. * @@ -114,7 +126,7 @@ class LauncherRestoreEventLoggerImpl(val context: Context) : LauncherRestoreEven */ override fun reportLauncherRestoreResults() { if (Flags.enableLauncherBrMetrics()) { - backupManager.reportDelayedRestoreResult(restoreEventLogger) + BackupManager(context).reportDelayedRestoreResult(restoreEventLogger) } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index e41a8a544c..11dc6e2056 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_CREATE_EVT; 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_OFFSET; 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.allapps.DiscoveryBounce; 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 @@ public class Launcher extends StatefulActivity 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 @@ public class Launcher extends StatefulActivity (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 @@ public class Launcher extends StatefulActivity 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 @@ public class Launcher extends StatefulActivity } else if (focusFirstItemForAccessibility && viewToFocus != null) { viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); } + if (restoreEventLogger != null) { + restoreEventLogger.reportLauncherRestoreResults(); + } workspace.requestLayout(); } @@ -2281,14 +2304,15 @@ public class Launcher extends StatefulActivity * 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 @@ public class Launcher extends StatefulActivity } 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 @@ public class Launcher extends StatefulActivity "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 @@ public class Launcher extends StatefulActivity 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; } diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt index 78056e625b..51ba5c6b44 100644 --- a/src/com/android/launcher3/LauncherPrefs.kt +++ b/src/com/android/launcher3/LauncherPrefs.kt @@ -34,6 +34,7 @@ import com.android.launcher3.config.FeatureFlags.LPNH_TIMEOUT_MS import com.android.launcher3.model.DeviceGridState import com.android.launcher3.pm.InstallSessionHelper import com.android.launcher3.provider.RestoreDbTask +import com.android.launcher3.provider.RestoreDbTask.FIRST_LOAD_AFTER_RESTORE_KEY import com.android.launcher3.states.RotationHelper import com.android.launcher3.util.DisplayController import com.android.launcher3.util.MainThreadInitializedObject @@ -417,6 +418,13 @@ class LauncherPrefs(private val encryptedContext: Context) { InvariantDeviceProfile.TYPE_PHONE, EncryptionType.MOVE_TO_DEVICE_PROTECTED ) + @JvmField + val IS_FIRST_LOAD_AFTER_RESTORE = + backedUpItem( + FIRST_LOAD_AFTER_RESTORE_KEY, + false, + EncryptionType.MOVE_TO_DEVICE_PROTECTED + ) @JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "") @JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "") @JvmField diff --git a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt index 16b185495a..bdac05df9e 100644 --- a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt +++ b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt @@ -14,6 +14,15 @@ open class LauncherRestoreEventLogger : ResourceBasedOverride { companion object { const val TAG = "LauncherRestoreEventLogger" + // Restore Errors + const val RESTORE_ERROR_PROFILE_DELETED = "user_profile_deleted" + const val RESTORE_ERROR_MISSING_INFO = "missing_information_when_loading" + const val RESTORE_ERROR_BIND_FAILURE = "binding_to_view_failed" + const val RESTORE_ERROR_INVALID_LOCATION = "invalid_size_or_location" + 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" + fun newInstance(context: Context?): LauncherRestoreEventLogger { return ResourceBasedOverride.Overrides.getObject( LauncherRestoreEventLogger::class.java, @@ -53,6 +62,16 @@ open class LauncherRestoreEventLogger : ResourceBasedOverride { // no-op } + /** + * Helper to log successfully restoring multiple items from the Favorites table. + * + * @param favoritesId The id of the item type from [Favorites] that was restored. + * @param count number of items that restored. + */ + open fun logFavoritesItemsRestored(favoritesId: Int, count: Int) { + // no-op + } + /** * Helper to log a failure to restore a single item from the Favorites table. * diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index 683354bf45..ec6b94dfeb 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -259,7 +259,7 @@ public class PreviewSurfaceRenderer { query += " or " + LauncherSettings.Favorites.SCREEN + " = " + Workspace.SECOND_SCREEN_ID; } - loadWorkspace(new ArrayList<>(), query, null); + loadWorkspace(new ArrayList<>(), query, null, null); final SparseArray spanInfo = getLoadedLauncherWidgetInfo(previewContext.getBaseContext()); diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index a98ec6484a..8dc2ab3175 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -17,9 +17,16 @@ package com.android.launcher3.model; import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN; +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; import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; +import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED; +import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_INVALID_LOCATION; +import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO; +import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_PROFILE_DELETED; +import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_SHORTCUT_NOT_FOUND; +import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_WIDGETS_DISABLED; import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL; import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION; @@ -69,6 +76,7 @@ import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; +import com.android.launcher3.backuprestore.LauncherRestoreEventLogger; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderGridOrganizer; @@ -134,6 +142,7 @@ public class LoaderTask implements Runnable { private final AllAppsList mBgAllAppsList; protected final BgDataModel mBgDataModel; private final ModelDelegate mModelDelegate; + private boolean mIsRestoreFromBackup; private FirstScreenBroadcast mFirstScreenBroadcast; @@ -148,7 +157,6 @@ public class LoaderTask implements Runnable { private final IconCache mIconCache; private final UserManagerState mUserManagerState; - protected final Map mWidgetProvidersMap = new ArrayMap<>(); private Map mShortcutKeyToPinnedShortcuts; @@ -172,7 +180,6 @@ public class LoaderTask implements Runnable { mBgDataModel = bgModel; mModelDelegate = modelDelegate; mLauncherBinder = launcherBinder; - mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class); mUserManager = mApp.getContext().getSystemService(UserManager.class); mUserCache = UserCache.getInstance(mApp.getContext()); @@ -221,9 +228,14 @@ public class LoaderTask implements Runnable { TraceHelper.INSTANCE.beginSection(TAG); LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger(); + mIsRestoreFromBackup = + (Boolean) LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE); + LauncherRestoreEventLogger restoreEventLogger = LauncherRestoreEventLogger + .Companion.newInstance(mApp.getContext()); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { + List allShortcuts = new ArrayList<>(); - loadWorkspace(allShortcuts, "", memoryLogger); + loadWorkspace(allShortcuts, "", memoryLogger, restoreEventLogger); // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db. // sanitizeData should not be invoked if the workspace is loaded from a db different @@ -314,8 +326,8 @@ public class LoaderTask implements Runnable { mLauncherBinder.bindWidgets(); logASplit("bindWidgets"); verifyNotStopped(); - LauncherPrefs prefs = LauncherPrefs.get(mApp.getContext()); + if (SMARTSPACE_AS_A_WIDGET.get() && prefs.get(SHOULD_SHOW_SMARTSPACE)) { mLauncherBinder.bindSmartspaceWidget(); // Turn off pref. @@ -349,6 +361,11 @@ public class LoaderTask implements Runnable { mModelDelegate.modelLoadComplete(); transaction.commit(); memoryLogger.clearLogs(); + if (mIsRestoreFromBackup) { + restoreEventLogger.reportLauncherRestoreResults(); + mIsRestoreFromBackup = false; + LauncherPrefs.get(mApp.getContext()).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false)); + } } catch (CancellationException e) { // Loader stopped, ignore logASplit("Cancelled"); @@ -367,10 +384,12 @@ public class LoaderTask implements Runnable { protected void loadWorkspace( List allDeepShortcuts, String selection, - LoaderMemoryLogger memoryLogger) { + LoaderMemoryLogger memoryLogger, + @Nullable LauncherRestoreEventLogger restoreEventLogger + ) { Trace.beginSection("LoadWorkspace"); try { - loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger); + loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger, restoreEventLogger); } finally { Trace.endSection(); } @@ -391,7 +410,8 @@ public class LoaderTask implements Runnable { private void loadWorkspaceImpl( List allDeepShortcuts, String selection, - @Nullable LoaderMemoryLogger memoryLogger) { + @Nullable LoaderMemoryLogger memoryLogger, + @Nullable LauncherRestoreEventLogger restoreEventLogger) { final Context context = mApp.getContext(); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); final boolean isSafeMode = pmHelper.isSafeMode(); @@ -458,8 +478,8 @@ public class LoaderTask implements Runnable { List> iconRequestInfos = new ArrayList<>(); while (!mStopped && c.moveToNext()) { - processWorkspaceItem(c, memoryLogger, installingPkgs, isSdCardReady, - tempPackageKey, widgetHelper, pmHelper, + processWorkspaceItem(c, memoryLogger, restoreEventLogger, installingPkgs, + isSdCardReady, tempPackageKey, widgetHelper, pmHelper, iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts); } tryLoadWorkspaceIconsInBulk(iconRequestInfos); @@ -518,6 +538,7 @@ public class LoaderTask implements Runnable { private void processWorkspaceItem(LoaderCursor c, LoaderMemoryLogger memoryLogger, + @Nullable LauncherRestoreEventLogger restoreEventLogger, HashMap installingPkgs, boolean isSdCardReady, PackageUserKey tempPackageKey, @@ -531,7 +552,11 @@ public class LoaderTask implements Runnable { try { if (c.user == null) { // User has been deleted, remove the item. - c.markDeleted("User has been deleted"); + c.markDeleted("User of this item has been deleted"); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_PROFILE_DELETED); + } return; } @@ -542,6 +567,10 @@ public class LoaderTask implements Runnable { Intent intent = c.parseIntent(); if (intent == null) { c.markDeleted("Invalid or null intent"); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_MISSING_INFO); + } return; } @@ -552,6 +581,10 @@ public class LoaderTask implements Runnable { if (TextUtils.isEmpty(targetPkg)) { c.markDeleted("Shortcuts can't have null package"); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_MISSING_INFO); + } return; } @@ -569,6 +602,9 @@ public class LoaderTask implements Runnable { if (mLauncherApps.isActivityEnabled(cn, c.user)) { // no special handling necessary for this item c.markRestored(); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestored(c.itemType); + } } else { // Gracefully try to find a fallback activity. intent = pmHelper.getAppLaunchIntent(targetPkg, c.user); @@ -579,7 +615,11 @@ public class LoaderTask implements Runnable { intent.toUri(0)).commit(); cn = intent.getComponent(); } else { - c.markDeleted("Unable to find a launch target"); + c.markDeleted("Intent null, unable to find a launch target"); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_MISSING_INFO); + } return; } } @@ -606,6 +646,10 @@ public class LoaderTask implements Runnable { } else { c.markDeleted("removing app that is not restored and not " + "installing. package: " + targetPkg); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED); + } return; } } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) { @@ -623,6 +667,10 @@ public class LoaderTask implements Runnable { } else { // Do not wait for external media load anymore. c.markDeleted("Invalid package removed: " + targetPkg); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED); + } return; } } @@ -652,8 +700,12 @@ public class LoaderTask implements Runnable { ShortcutInfo pinnedShortcut = mShortcutKeyToPinnedShortcuts.get(key); if (pinnedShortcut == null) { // The shortcut is no longer valid. - c.markDeleted("Pinned shortcut not found for package: " - + key.getPackageName()); + c.markDeleted("Pinned shortcut not found from request." + + " package=" + key.getPackageName() + ", user=" + c.user); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_SHORTCUT_NOT_FOUND); + } return; } info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext()); @@ -672,6 +724,9 @@ public class LoaderTask implements Runnable { info = c.loadSimpleWorkspaceItem(); info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER; } + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestored(c.itemType); + } } else { // item type == ITEM_TYPE_SHORTCUT info = c.loadSimpleWorkspaceItem(); @@ -751,13 +806,19 @@ public class LoaderTask implements Runnable { // no special handling required for restored folders c.markRestored(); - + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestored(c.itemType); + } c.checkAndAddItem(folderInfo, mBgDataModel, memoryLogger); break; case Favorites.ITEM_TYPE_APPWIDGET: if (WidgetsModel.GO_DISABLE_WIDGETS) { c.markDeleted("Only legacy shortcuts can have null package"); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_WIDGETS_DISABLED); + } return; } // Follow through @@ -774,6 +835,10 @@ public class LoaderTask implements Runnable { component = QsbContainerView.getSearchComponentName(mApp.getContext()); if (component == null) { c.markDeleted("Discarding SearchWidget without packagename "); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_MISSING_INFO); + } return; } } else { @@ -799,6 +864,10 @@ public class LoaderTask implements Runnable { final boolean isProviderReady = isValidProvider(provider); if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) { c.markDeleted("Deleting widget that isn't installed anymore: " + provider); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED); + } } else { LauncherAppWidgetInfo appWidgetInfo; if (isProviderReady) { @@ -841,6 +910,10 @@ public class LoaderTask implements Runnable { |= LauncherAppWidgetInfo.FLAG_RESTORE_STARTED; } else if (!isSafeMode) { c.markDeleted("Unrestored widget removed: " + component); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED); + } return; } @@ -862,6 +935,10 @@ public class LoaderTask implements Runnable { if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) { c.markDeleted("Widget has invalid size: " + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_INVALID_LOCATION); + } return; } LauncherAppWidgetProviderInfo widgetProviderInfo = @@ -875,12 +952,15 @@ public class LoaderTask implements Runnable { + "x" + appWidgetInfo.spanY + " minSpan=" + widgetProviderInfo.minSpanX + "x" + widgetProviderInfo.minSpanY); - logWidgetInfo(mApp.getInvariantDeviceProfile(), - widgetProviderInfo); + logWidgetInfo(mApp.getInvariantDeviceProfile(), widgetProviderInfo); } if (!c.isOnWorkspaceOrHotseat()) { c.markDeleted("Widget found where container != CONTAINER_DESKTOP" + "nor CONTAINER_HOTSEAT - ignoring!"); + if (mIsRestoreFromBackup && restoreEventLogger != null) { + restoreEventLogger.logSingleFavoritesItemRestoreFailed( + c.itemType, RESTORE_ERROR_INVALID_LOCATION); + } return; } diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index dc8cd3af65..20b2971f27 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -20,6 +20,7 @@ import static android.os.Process.myUserHandle; 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_APPLICATION; @@ -83,6 +84,7 @@ public class RestoreDbTask { private static final String TAG = "RestoreDbTask"; public static final String RESTORED_DEVICE_TYPE = "restored_task_pending"; + public static final String FIRST_LOAD_AFTER_RESTORE_KEY = "first_load_after_restore"; private static final String INFO_COLUMN_NAME = "name"; private static final String INFO_COLUMN_DEFAULT_VALUE = "dflt_value"; @@ -340,9 +342,10 @@ public class RestoreDbTask { * Marks the DB state as pending restoration */ public static void setPending(Context context) { - FileLog.d(TAG, "Restore data received through full backup"); - LauncherPrefs.get(context) - .putSync(RESTORE_DEVICE.to(new DeviceGridState(context).getDeviceType())); + 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)); } @WorkerThread