diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index b5dd10ec3d..a2f6bf98c7 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -52,7 +52,6 @@ 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; @@ -65,8 +64,6 @@ 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; @@ -165,7 +162,6 @@ 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; @@ -2161,13 +2157,6 @@ 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 @@ -2198,15 +2187,10 @@ public class Launcher extends StatefulActivity } case ITEM_TYPE_APPWIDGET: case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: { - view = inflateAppWidget((LauncherAppWidgetInfo) item, restoreEventLogger); + view = inflateAppWidget((LauncherAppWidgetInfo) item); 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: @@ -2230,10 +2214,6 @@ 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; } @@ -2292,9 +2272,6 @@ public class Launcher extends StatefulActivity } else if (focusFirstItemForAccessibility && viewToFocus != null) { viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); } - if (restoreEventLogger != null) { - restoreEventLogger.reportLauncherRestoreResults(); - } workspace.requestLayout(); } @@ -2302,24 +2279,19 @@ public class Launcher extends StatefulActivity * Add the views for a widget to the workspace. */ public void bindAppWidget(LauncherAppWidgetInfo item) { - View view = inflateAppWidget(item, null); + View view = inflateAppWidget(item); if (view != null) { mWorkspace.addInScreen(view, item); mWorkspace.requestLayout(); } } - private View inflateAppWidget(LauncherAppWidgetInfo item, - @Nullable LauncherRestoreEventLogger restoreEventLogger) { + private View inflateAppWidget(LauncherAppWidgetInfo item) { TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId); try { InflationResult inflationResult = mWidgetInflater.inflateAppWidget(item); if (inflationResult.getType() == WidgetInflater.TYPE_DELETE) { getModelWriter().deleteItemFromDatabase(item, inflationResult.getReason()); - if (restoreEventLogger != null) { - restoreEventLogger.logSingleFavoritesItemRestoreFailed( - ITEM_TYPE_APPWIDGET, RESTORE_ERROR_BIND_FAILURE); - } return null; } diff --git a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt index 063dad12e4..e6654b1547 100644 --- a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt +++ b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt @@ -1,6 +1,7 @@ package com.android.launcher3.backuprestore import android.content.Context +import androidx.annotation.StringDef import com.android.launcher3.LauncherSettings.Favorites import com.android.launcher3.R import com.android.launcher3.util.ResourceBasedOverride @@ -11,20 +12,42 @@ import com.android.launcher3.util.ResourceBasedOverride */ open class LauncherRestoreEventLogger : ResourceBasedOverride { + /** Enumeration of potential errors returned to calls of pause/resume app updates. */ + @Retention(AnnotationRetention.SOURCE) + @StringDef( + RestoreError.PROFILE_DELETED, + RestoreError.MISSING_INFO, + RestoreError.MISSING_WIDGET_PROVIDER, + RestoreError.INVALID_LOCATION, + RestoreError.SHORTCUT_NOT_FOUND, + RestoreError.APP_NOT_INSTALLED, + RestoreError.WIDGETS_DISABLED, + RestoreError.PROFILE_NOT_RESTORED, + RestoreError.WIDGET_REMOVED, + RestoreError.GRID_MIGRATION_FAILURE, + RestoreError.NO_SEARCH_WIDGET, + RestoreError.INVALID_WIDGET_ID + ) + annotation class RestoreError { + companion object { + const val PROFILE_DELETED = "user_profile_deleted" + const val MISSING_INFO = "missing_information_when_loading" + const val MISSING_WIDGET_PROVIDER = "missing_widget_provider" + const val INVALID_LOCATION = "invalid_size_or_location" + const val SHORTCUT_NOT_FOUND = "shortcut_not_found" + const val APP_NOT_INSTALLED = "app_not_installed" + const val WIDGETS_DISABLED = "widgets_disabled" + const val PROFILE_NOT_RESTORED = "profile_not_restored" + const val WIDGET_REMOVED = "widget_not_found" + const val GRID_MIGRATION_FAILURE = "grid_migration_failed" + const val NO_SEARCH_WIDGET = "no_search_widget" + const val INVALID_WIDGET_ID = "invalid_widget_id" + } + } + 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" - 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( LauncherRestoreEventLogger::class.java, @@ -80,7 +103,7 @@ open class LauncherRestoreEventLogger : ResourceBasedOverride { * @param favoritesId The id of the item type from [Favorites] that was not restored. * @param error error type for why the data was not restored. */ - open fun logSingleFavoritesItemRestoreFailed(favoritesId: Int, error: String?) { + open fun logSingleFavoritesItemRestoreFailed(favoritesId: Int, @RestoreError error: String?) { // no-op } @@ -91,7 +114,11 @@ open class LauncherRestoreEventLogger : ResourceBasedOverride { * @param count number of items that failed to restore. * @param error error type for why the data was not restored. */ - open fun logFavoritesItemsRestoreFailed(favoritesId: Int, count: Int, error: String?) { + open fun logFavoritesItemsRestoreFailed( + favoritesId: Int, + count: Int, + @RestoreError error: String? + ) { // no-op } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 4370043569..1044dfb4de 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -41,6 +41,8 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; +import com.android.launcher3.backuprestore.LauncherRestoreEventLogger; +import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; import com.android.launcher3.logging.FileLog; @@ -70,6 +72,7 @@ public class LoaderCursor extends CursorWrapper { private final Context mContext; private final IconCache mIconCache; private final InvariantDeviceProfile mIDP; + private final @Nullable LauncherRestoreEventLogger mRestoreEventLogger; private final IntArray mItemsToRemove = new IntArray(); private final IntArray mRestoredRows = new IntArray(); @@ -107,7 +110,8 @@ public class LoaderCursor extends CursorWrapper { public int itemType; public int restoreFlag; - public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState) { + public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState, + @Nullable LauncherRestoreEventLogger restoreEventLogger) { super(cursor); mApp = app; @@ -115,6 +119,7 @@ public class LoaderCursor extends CursorWrapper { mContext = app.getContext(); mIconCache = app.getIconCache(); mIDP = app.getInvariantDeviceProfile(); + mRestoreEventLogger = restoreEventLogger; // Init column indices mIconIndex = getColumnIndexOrThrow(Favorites.ICON); @@ -390,9 +395,12 @@ public class LoaderCursor extends CursorWrapper { /** * Marks the current item for removal */ - public void markDeleted(String reason) { + public void markDeleted(String reason, @RestoreError String errorType) { FileLog.e(TAG, reason); mItemsToRemove.add(id); + if (mRestoreEventLogger != null) { + mRestoreEventLogger.logSingleFavoritesItemRestoreFailed(itemType, errorType); + } } /** @@ -431,6 +439,9 @@ public class LoaderCursor extends CursorWrapper { mApp.getModel().getModelDbController().update(TABLE_NAME, values, Utilities.createDbSelectionQuery(Favorites._ID, mRestoredRows), null); } + if (mRestoreEventLogger != null) { + mRestoreEventLogger.reportLauncherRestoreResults(); + } } /** @@ -473,8 +484,11 @@ public class LoaderCursor extends CursorWrapper { } if (checkItemPlacement(info, dataModel.isFirstPagePinnedItemEnabled)) { dataModel.addItem(mContext, info, false, logger); + if (mRestoreEventLogger != null) { + mRestoreEventLogger.logSingleFavoritesItemRestored(itemType); + } } else { - markDeleted("Item position overlap"); + markDeleted("Item position overlap", RestoreError.INVALID_LOCATION); } } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 795450a247..7c3d7589dc 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -95,7 +95,7 @@ import com.android.launcher3.util.LooperIdleLock; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.TraceHelper; -import com.android.launcher3.widget.WidgetManagerHelper; +import com.android.launcher3.widget.WidgetInflater; import java.util.ArrayList; import java.util.Collections; @@ -403,9 +403,8 @@ public class LoaderTask implements Runnable { @Nullable LauncherRestoreEventLogger restoreEventLogger) { final Context context = mApp.getContext(); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); - final boolean isSafeMode = pmHelper.isSafeMode(); final boolean isSdCardReady = Utilities.isBootCompleted(); - final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context); + final WidgetInflater widgetInflater = new WidgetInflater(context); ModelDbController dbController = mApp.getModel().getModelDbController(); dbController.tryMigrateDB(restoreEventLogger); @@ -422,13 +421,12 @@ public class LoaderTask implements Runnable { FileLog.d(TAG, "loadWorkspace: Packages with active install sessions: " + installingPkgs.keySet().stream().map(info -> info.mPackageName).toList()); - final PackageUserKey tempPackageKey = new PackageUserKey(null, null); mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs); mShortcutKeyToPinnedShortcuts = new HashMap<>(); final LoaderCursor c = new LoaderCursor( dbController.query(TABLE_NAME, null, selection, null, null), - mApp, mUserManagerState); + mApp, mUserManagerState, mIsRestoreFromBackup ? restoreEventLogger : null); final Bundle extras = c.getExtras(); mDbName = extras == null ? null : extras.getString(ModelDbController.EXTRA_DB_NAME); try { @@ -438,11 +436,11 @@ public class LoaderTask implements Runnable { List> iconRequestInfos = new ArrayList<>(); WorkspaceItemProcessor itemProcessor = new WorkspaceItemProcessor(c, memoryLogger, - restoreEventLogger, mUserManagerState, mLauncherApps, mPendingPackages, - mShortcutKeyToPinnedShortcuts, mApp, mIconCache, mBgDataModel, - mWidgetProvidersMap, mIsRestoreFromBackup, installingPkgs, isSdCardReady, - tempPackageKey, widgetHelper, pmHelper, iconRequestInfos, unlockedUsers, - isSafeMode, allDeepShortcuts); + mUserManagerState, mLauncherApps, mPendingPackages, + mShortcutKeyToPinnedShortcuts, mApp, mBgDataModel, + mWidgetProvidersMap, installingPkgs, isSdCardReady, + widgetInflater, pmHelper, iconRequestInfos, unlockedUsers, + allDeepShortcuts); while (!mStopped && c.moveToNext()) { itemProcessor.processItem(); diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java index c68274af2b..6c6471347e 100644 --- a/src/com/android/launcher3/model/ModelDbController.java +++ b/src/com/android/launcher3/model/ModelDbController.java @@ -65,6 +65,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.backuprestore.LauncherRestoreEventLogger.RestoreError; import com.android.launcher3.logging.FileLog; import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.LauncherDbUtils; @@ -89,7 +90,6 @@ public class ModelDbController { 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; @@ -335,7 +335,7 @@ public class ModelDbController { restoreEventLogger.logFavoritesItemsRestoreFailed( cursor.getInt(cursor.getColumnIndexOrThrow(ITEM_TYPE)), cursor.getInt(cursor.getColumnIndexOrThrow("count")), - RESTORE_ERROR_GRID_MIGRATION_FAILURE + RestoreError.GRID_MIGRATION_FAILURE ); } while (cursor.moveToNext()); } diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt index 5389d38ab9..697fbc8fda 100644 --- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt +++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt @@ -32,22 +32,19 @@ import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherSettings.Favorites import com.android.launcher3.Utilities -import com.android.launcher3.backuprestore.LauncherRestoreEventLogger -import com.android.launcher3.icons.IconCache +import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError import com.android.launcher3.logging.FileLog import com.android.launcher3.model.data.IconRequestInfo import com.android.launcher3.model.data.ItemInfoWithIcon import com.android.launcher3.model.data.LauncherAppWidgetInfo import com.android.launcher3.model.data.WorkspaceItemInfo import com.android.launcher3.pm.PackageInstallInfo -import com.android.launcher3.qsb.QsbContainerView import com.android.launcher3.shortcuts.ShortcutKey import com.android.launcher3.util.ComponentKey import com.android.launcher3.util.PackageManagerHelper import com.android.launcher3.util.PackageUserKey import com.android.launcher3.widget.LauncherAppWidgetProviderInfo -import com.android.launcher3.widget.WidgetManagerHelper -import com.android.launcher3.widget.custom.CustomWidgetManager +import com.android.launcher3.widget.WidgetInflater /** * This items is used by LoaderTask to process items that have been loaded from the Launcher's DB. @@ -59,26 +56,26 @@ import com.android.launcher3.widget.custom.CustomWidgetManager class WorkspaceItemProcessor( private val c: LoaderCursor, private val memoryLogger: LoaderMemoryLogger?, - private val restoreEventLogger: LauncherRestoreEventLogger?, private val userManagerState: UserManagerState, private val launcherApps: LauncherApps, private val pendingPackages: MutableSet, private val shortcutKeyToPinnedShortcuts: Map, private val app: LauncherAppState, - private val iconCache: IconCache, private val bgDataModel: BgDataModel, private val widgetProvidersMap: MutableMap, - private val isRestoreFromBackup: Boolean, private val installingPkgs: HashMap, private val isSdCardReady: Boolean, - private val tempPackageKey: PackageUserKey, - private val widgetHelper: WidgetManagerHelper, + private val widgetInflater: WidgetInflater, private val pmHelper: PackageManagerHelper, private val iconRequestInfos: MutableList>, private val unlockedUsers: LongSparseArray, - private val isSafeMode: Boolean, private val allDeepShortcuts: MutableList ) { + + private val isSafeMode = app.isSafeModeEnabled + private val tempPackageKey = PackageUserKey(null, null) + private val iconCache = app.iconCache + /** * This is the entry point for processing 1 workspace item. This method is like the midfielder * that delegates the actual processing to either processAppShortcut, processFolder, or @@ -91,13 +88,7 @@ class WorkspaceItemProcessor( try { if (c.user == null) { // User has been deleted, remove the item. - c.markDeleted("User has been deleted") - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_PROFILE_DELETED - ) - } + c.markDeleted("User has been deleted", RestoreError.PROFILE_DELETED) return } when (c.itemType) { @@ -140,13 +131,7 @@ class WorkspaceItemProcessor( var allowMissingTarget = false var intent = c.parseIntent() if (intent == null) { - c.markDeleted("Invalid or null intent") - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO - ) - } + c.markDeleted("Invalid or null intent", RestoreError.MISSING_INFO) return } var disabledState = @@ -156,13 +141,7 @@ class WorkspaceItemProcessor( var cn = intent.component val targetPkg = if (cn == null) intent.getPackage() else cn.packageName if (TextUtils.isEmpty(targetPkg)) { - c.markDeleted("Shortcuts can't have null package") - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO - ) - } + c.markDeleted("Shortcuts can't have null package", RestoreError.MISSING_INFO) return } @@ -179,9 +158,6 @@ class WorkspaceItemProcessor( if (launcherApps.isActivityEnabled(cn, c.user)) { // no special handling necessary for this item c.markRestored() - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestored(c.itemType) - } } else { // Gracefully try to find a fallback activity. intent = pmHelper.getAppLaunchIntent(targetPkg, c.user) @@ -189,13 +165,10 @@ class WorkspaceItemProcessor( c.restoreFlag = 0 c.updater().put(Favorites.INTENT, intent.toUri(0)).commit() } else { - c.markDeleted("Intent null, unable to find a launch target") - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO - ) - } + c.markDeleted( + "Intent null, unable to find a launch target", + RestoreError.MISSING_INFO + ) return } } @@ -225,14 +198,9 @@ class WorkspaceItemProcessor( } else -> { c.markDeleted( - "removing app that is not restored and not installing. package: $targetPkg" + "removing app that is not restored and not installing. package: $targetPkg", + RestoreError.APP_NOT_INSTALLED ) - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED - ) - } return } } @@ -254,13 +222,10 @@ class WorkspaceItemProcessor( } else -> { // Do not wait for external media load anymore. - c.markDeleted("Invalid package removed: $targetPkg") - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED - ) - } + c.markDeleted( + "Invalid package removed: $targetPkg", + RestoreError.APP_NOT_INSTALLED + ) return } } @@ -290,14 +255,9 @@ class WorkspaceItemProcessor( if (pinnedShortcut == null) { // The shortcut is no longer valid. c.markDeleted( - "Pinned shortcut not found from request. package=${key.packageName}, user=${c.user}" + "Pinned shortcut not found from request. package=${key.packageName}, user=${c.user}", + RestoreError.SHORTCUT_NOT_FOUND ) - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_SHORTCUT_NOT_FOUND - ) - } return } info = WorkspaceItemInfo(pinnedShortcut, app.context) @@ -316,9 +276,6 @@ class WorkspaceItemProcessor( info.runtimeStatusFlags = info.runtimeStatusFlags or ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER } - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestored(c.itemType) - } } else -> { // item type == ITEM_TYPE_SHORTCUT info = c.loadSimpleWorkspaceItem() @@ -416,9 +373,6 @@ class WorkspaceItemProcessor( // no special handling required for restored folders c.markRestored() - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestored(c.itemType) - } c.checkAndAddItem(folderInfo, bgDataModel, memoryLogger) } @@ -441,185 +395,94 @@ class WorkspaceItemProcessor( */ @VisibleForTesting fun processWidget() { - if (WidgetsModel.GO_DISABLE_WIDGETS && c.itemType == Favorites.ITEM_TYPE_APPWIDGET) { - c.markDeleted("Only legacy shortcuts can have null package") - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_WIDGETS_DISABLED - ) - } + val component = ComponentName.unflattenFromString(c.appWidgetProvider)!! + val appWidgetInfo = LauncherAppWidgetInfo(c.appWidgetId, component) + c.applyCommonProperties(appWidgetInfo) + appWidgetInfo.spanX = c.spanX + appWidgetInfo.spanY = c.spanY + appWidgetInfo.options = c.options + appWidgetInfo.user = c.user + appWidgetInfo.sourceContainer = c.appWidgetSource + appWidgetInfo.restoreStatus = c.restoreFlag + if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) { + c.markDeleted( + "Widget has invalid size: ${appWidgetInfo.spanX}x${appWidgetInfo.spanY}", + RestoreError.INVALID_LOCATION + ) + return + } + if (!c.isOnWorkspaceOrHotseat) { + c.markDeleted( + "Widget found where container != CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!", + RestoreError.INVALID_LOCATION + ) + return + } + if (appWidgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) { + appWidgetInfo.bindOptions = c.parseIntent() + } + val inflationResult = widgetInflater.inflateAppWidget(appWidgetInfo) + var shouldUpdate = inflationResult.isUpdate + if (inflationResult.type == WidgetInflater.TYPE_DELETE) { + c.markDeleted(inflationResult.reason, inflationResult.restoreErrorType) return } - // Read all Launcher-specific widget details - val customWidget = (c.itemType == Favorites.ITEM_TYPE_CUSTOM_APPWIDGET) - val appWidgetId = c.appWidgetId - val savedProvider = c.appWidgetProvider - val component: ComponentName? - if (c.options and LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET != 0) { - component = QsbContainerView.getSearchComponentName(app.context) - if (component == null) { - c.markDeleted("Discarding SearchWidget without package name") - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO - ) - } - return - } - } else { - component = ComponentName.unflattenFromString(savedProvider) - } - val isIdValid = !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) - val wasProviderReady = !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) - val providerKey = ComponentKey(component, c.user) - if (!widgetProvidersMap.containsKey(providerKey)) { - if (customWidget) { - widgetProvidersMap[providerKey] = - CustomWidgetManager.INSTANCE[app.context].getWidgetProvider(component) - } else { - widgetProvidersMap[providerKey] = widgetHelper.findProvider(component, c.user) - } - } - val provider = widgetProvidersMap[providerKey] - val isProviderReady = LoaderTask.isValidProvider(provider) - if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) { - c.markDeleted("Deleting widget that isn't installed anymore: $provider") - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED - ) - } - } else { - val appWidgetInfo: LauncherAppWidgetInfo - if (isProviderReady) { - appWidgetInfo = LauncherAppWidgetInfo(appWidgetId, provider!!.provider) + val lapi = inflationResult.widgetInfo + if (inflationResult.type == WidgetInflater.TYPE_PENDING) { + tempPackageKey.update(component.packageName, c.user) + val si = installingPkgs[tempPackageKey] - // The provider is available. So the widget is either - // available or not available. We do not need to track - // any future restore updates. - var status = - (c.restoreFlag and - LauncherAppWidgetInfo.FLAG_RESTORE_STARTED.inv() and - LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY.inv()) - if (!wasProviderReady) { - // If provider was not previously ready, update status and UI flag. - - // Id would be valid only if the widget restore broadcast received. - if (isIdValid) { - status = status or LauncherAppWidgetInfo.FLAG_UI_NOT_READY - } - } - appWidgetInfo.restoreStatus = status - } else { - Log.v( - TAG, - "Widget restore pending id=${c.id} appWidgetId=$appWidgetId status=${c.restoreFlag}" - ) - appWidgetInfo = LauncherAppWidgetInfo(appWidgetId, component) - appWidgetInfo.restoreStatus = c.restoreFlag - tempPackageKey.update(component!!.packageName, c.user) - val si = installingPkgs[tempPackageKey] - val installProgress = if (si == null) null else (si.getProgress() * 100).toInt() - when { - c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) -> { - // Restore has started once. - } - installProgress != null -> { - // App restore has started. Update the flag - appWidgetInfo.restoreStatus = - appWidgetInfo.restoreStatus or - LauncherAppWidgetInfo.FLAG_RESTORE_STARTED - } - !isSafeMode -> { - c.markDeleted("Unrestored widget removed: $component") - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED - ) - } - return - } - } - appWidgetInfo.installProgress = installProgress ?: 0 - } - if (appWidgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) { - appWidgetInfo.bindOptions = c.parseIntent() - } - c.applyCommonProperties(appWidgetInfo) - appWidgetInfo.spanX = c.spanX - appWidgetInfo.spanY = c.spanY - appWidgetInfo.options = c.options - appWidgetInfo.user = c.user - appWidgetInfo.sourceContainer = c.appWidgetSource - if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) { - c.markDeleted( - "Widget has invalid size: ${appWidgetInfo.spanX}x${appWidgetInfo.spanY}" - ) - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_INVALID_LOCATION - ) - } - return - } - val widgetProviderInfo = - widgetHelper.getLauncherAppWidgetInfo(appWidgetId, appWidgetInfo.targetComponent) if ( - widgetProviderInfo != null && - (appWidgetInfo.spanX < widgetProviderInfo.minSpanX || - appWidgetInfo.spanY < widgetProviderInfo.minSpanY) + !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) && + !isSafeMode && + (si == null) && + (lapi == null) ) { + // Restore never started + c.markDeleted( + "Unrestored widget removed: $component", + RestoreError.APP_NOT_INSTALLED + ) + return + } else if ( + !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) && si != null + ) { + shouldUpdate = true + appWidgetInfo.restoreStatus = + appWidgetInfo.restoreStatus or LauncherAppWidgetInfo.FLAG_RESTORE_STARTED + } + appWidgetInfo.installProgress = if (si == null) 0 else (si.getProgress() * 100).toInt() + appWidgetInfo.pendingItemInfo = + WidgetsModel.newPendingItemInfo( + app.context, + appWidgetInfo.providerName, + appWidgetInfo.user + ) + iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, false) + } + if (shouldUpdate) { + c.updater() + .put(Favorites.APPWIDGET_PROVIDER, component.flattenToString()) + .put(Favorites.APPWIDGET_ID, appWidgetInfo.appWidgetId) + .put(Favorites.RESTORED, appWidgetInfo.restoreStatus) + .commit() + } + if (lapi != null) { + widgetProvidersMap[ComponentKey(lapi.provider, lapi.user)] = inflationResult.widgetInfo + if (appWidgetInfo.spanX < lapi.minSpanX || appWidgetInfo.spanY < lapi.minSpanY) { FileLog.d( TAG, - "Widget ${widgetProviderInfo.component} minSizes not meet:" + - " span=${appWidgetInfo.spanX}x${appWidgetInfo.spanY}" + - " minSpan=${widgetProviderInfo.minSpanX}x${widgetProviderInfo.minSpanY}" + "Widget ${lapi.component} minSizes not meet: span=${appWidgetInfo.spanX}x${appWidgetInfo.spanY} minSpan=${lapi.minSpanX}x${lapi.minSpanY}" ) - logWidgetInfo(app.invariantDeviceProfile, widgetProviderInfo) + logWidgetInfo(app.invariantDeviceProfile, lapi) } - if (!c.isOnWorkspaceOrHotseat) { - c.markDeleted( - "Widget found where container != CONTAINER_DESKTOP" + - " nor CONTAINER_HOTSEAT - ignoring!" - ) - if (isRestoreFromBackup) { - restoreEventLogger?.logSingleFavoritesItemRestoreFailed( - c.itemType, - LauncherRestoreEventLogger.RESTORE_ERROR_INVALID_LOCATION - ) - } - return - } - if (!customWidget) { - val providerName = appWidgetInfo.providerName.flattenToString() - if (providerName != savedProvider || appWidgetInfo.restoreStatus != c.restoreFlag) { - c.updater() - .put(Favorites.APPWIDGET_PROVIDER, providerName) - .put(Favorites.RESTORED, appWidgetInfo.restoreStatus) - .commit() - } - } - if (appWidgetInfo.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED) { - appWidgetInfo.pendingItemInfo = - WidgetsModel.newPendingItemInfo( - app.context, - appWidgetInfo.providerName, - appWidgetInfo.user - ) - iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, false) - } - c.checkAndAddItem(appWidgetInfo, bgDataModel) } + c.checkAndAddItem(appWidgetInfo, bgDataModel) } companion object { - private val TAG = WorkspaceItemProcessor::class.java.simpleName + private const val TAG = "WorkspaceItemProcessor" private fun logWidgetInfo( idp: InvariantDeviceProfile, widgetProviderInfo: LauncherAppWidgetProviderInfo diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java index 30958d9c59..1f159471a0 100644 --- a/src/com/android/launcher3/provider/LauncherDbUtils.java +++ b/src/com/android/launcher3/provider/LauncherDbUtils.java @@ -109,7 +109,7 @@ public class LauncherDbUtils { UserManagerState ums = new UserManagerState(); ums.init(UserCache.INSTANCE.get(context), context.getSystemService(UserManager.class)); - LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums); + LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums, null); IntSet deletedShortcuts = new IntSet(); while (lc.moveToNext()) { diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index 9750d251ab..1c53855adb 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -27,9 +27,6 @@ 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.provider.LauncherDbUtils.dropTable; import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID; @@ -60,6 +57,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.backuprestore.LauncherRestoreEventLogger.RestoreError; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.DeviceGridState; import com.android.launcher3.model.LoaderTask; @@ -394,7 +392,7 @@ public class RestoreDbTask { 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); + oldWidgetIds.length, RestoreError.WIDGETS_DISABLED); return; } if (!RestoreDbTask.isPending(context)) { @@ -460,7 +458,7 @@ public class RestoreDbTask { host.deleteAppWidgetId(newWidgetIds[i]); launcherRestoreEventLogger.logSingleFavoritesItemRestoreFailed( ITEM_TYPE_APPWIDGET, - RESTORE_ERROR_WIDGET_REMOVED + RestoreError.WIDGET_REMOVED ); } } @@ -620,7 +618,7 @@ public class RestoreDbTask { restoreEventLogger.logFavoritesItemsRestoreFailed( cursor.getInt(cursor.getColumnIndexOrThrow(ITEM_TYPE)), cursor.getInt(cursor.getColumnIndexOrThrow("count")), - RESTORE_ERROR_PROFILE_NOT_RESTORED + RestoreError.PROFILE_NOT_RESTORED ); } while (cursor.moveToNext()); } diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 3f7a1287f6..2b5aaf5520 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -119,10 +119,6 @@ public class PackageManagerHelper { } } - public boolean isSafeMode() { - return mPm.isSafeMode(); - } - @Nullable public Intent getAppLaunchIntent(@Nullable final String pkg, @NonNull final UserHandle user) { List activities = mLauncherApps.getActivityList(pkg, user); diff --git a/src/com/android/launcher3/widget/WidgetInflater.kt b/src/com/android/launcher3/widget/WidgetInflater.kt index 00707f5969..dd50b71cb1 100644 --- a/src/com/android/launcher3/widget/WidgetInflater.kt +++ b/src/com/android/launcher3/widget/WidgetInflater.kt @@ -19,6 +19,7 @@ package com.android.launcher3.widget import android.content.Context import com.android.launcher3.Launcher import com.android.launcher3.LauncherAppState +import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError import com.android.launcher3.logging.FileLog import com.android.launcher3.model.WidgetsModel import com.android.launcher3.model.data.LauncherAppWidgetInfo @@ -37,7 +38,8 @@ class WidgetInflater(private val context: Context) { if (item.providerName == null) { return InflationResult( TYPE_DELETE, - reason = "search widget removed because search component cannot be found" + reason = "search widget removed because search component cannot be found", + restoreErrorType = RestoreError.NO_SEARCH_WIDGET ) } } @@ -46,19 +48,25 @@ class WidgetInflater(private val context: Context) { } val appWidgetInfo: LauncherAppWidgetProviderInfo? var removalReason = "" - if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) { - // If the provider is not ready, bind as a pending widget. - appWidgetInfo = null - removalReason = "the provider isn't ready." - } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { + @RestoreError var logReason = RestoreError.APP_NOT_INSTALLED + var update = false + + if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { // The widget id is not valid. Try to find the widget based on the provider info. appWidgetInfo = widgetHelper.findProvider(item.providerName, item.user) if (appWidgetInfo == null) { if (WidgetsModel.GO_DISABLE_WIDGETS) { removalReason = "widgets are disabled on go device." + logReason = RestoreError.WIDGETS_DISABLED } else { removalReason = "WidgetManagerHelper cannot find a provider from provider info." + logReason = RestoreError.MISSING_WIDGET_PROVIDER } + } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) { + // since appWidgetInfo is not null anymore, update the provider status + item.restoreStatus = + item.restoreStatus and LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY.inv() + update = true } } else { appWidgetInfo = @@ -66,19 +74,19 @@ class WidgetInflater(private val context: Context) { if (appWidgetInfo == null) { if (item.appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) { removalReason = "CustomWidgetManager cannot find provider from that widget id." + logReason = RestoreError.MISSING_INFO } else { removalReason = ("AppWidgetManager cannot find provider for that widget id." + " It could be because AppWidgetService is not available, or the" + " appWidgetId has not been bound to a the provider yet, or you" + " don't have access to that appWidgetId.") + logReason = RestoreError.INVALID_WIDGET_ID } } } - var update = false - - // If the provider is ready, but the width is not yet restored, try to restore it. + // If the provider is ready, but the widget is not yet restored, try to restore it. if ( !item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) && item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED @@ -87,9 +95,8 @@ class WidgetInflater(private val context: Context) { return InflationResult( type = TYPE_DELETE, reason = - "Removing restored widget: id=${item.appWidgetId} belongs to component" + - " ${item.providerName} user ${item.user}" + - ", as the provider is null and $removalReason" + "Removing restored widget: id=${item.appWidgetId} belongs to component ${item.providerName} user ${item.user}, as the provider is null and $removalReason", + restoreErrorType = logReason ) } @@ -182,6 +189,7 @@ class WidgetInflater(private val context: Context) { data class InflationResult( val type: Int, val reason: String? = null, + @RestoreError val restoreErrorType: String = RestoreError.APP_NOT_INSTALLED, val isUpdate: Boolean = false, val widgetInfo: LauncherAppWidgetProviderInfo? = null ) diff --git a/src/com/android/launcher3/widget/WidgetManagerHelper.java b/src/com/android/launcher3/widget/WidgetManagerHelper.java index 0860e72420..058523b530 100644 --- a/src/com/android/launcher3/widget/WidgetManagerHelper.java +++ b/src/com/android/launcher3/widget/WidgetManagerHelper.java @@ -61,8 +61,7 @@ public class WidgetManagerHelper { int appWidgetId, ComponentName componentName) { // For custom widgets. - if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID && !CustomWidgetManager - .INSTANCE.get(mContext).getWidgetIdForCustomProvider(componentName).equals("")) { + if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) { return CustomWidgetManager.INSTANCE.get(mContext).getWidgetProvider(componentName); } diff --git a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java index 44571a6c4a..398b1df394 100644 --- a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java @@ -33,13 +33,9 @@ import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; public class CustomAppWidgetProviderInfo extends LauncherAppWidgetProviderInfo implements Parcelable { - public final String providerId; - - protected CustomAppWidgetProviderInfo(Parcel parcel, boolean readSelf, String providerId) { + protected CustomAppWidgetProviderInfo(Parcel parcel, boolean readSelf) { super(parcel); if (readSelf) { - this.providerId = parcel.readString(); - provider = new ComponentName(parcel.readString(), CLS_CUSTOM_WIDGET_PREFIX + parcel.readString()); @@ -53,8 +49,6 @@ public class CustomAppWidgetProviderInfo extends LauncherAppWidgetProviderInfo spanY = parcel.readInt(); minSpanX = parcel.readInt(); minSpanY = parcel.readInt(); - } else { - this.providerId = providerId; } } @@ -77,7 +71,6 @@ public class CustomAppWidgetProviderInfo extends LauncherAppWidgetProviderInfo @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); - out.writeString(providerId); out.writeString(provider.getPackageName()); out.writeString(provider.getClassName()); @@ -93,12 +86,12 @@ public class CustomAppWidgetProviderInfo extends LauncherAppWidgetProviderInfo out.writeInt(minSpanY); } - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator<>() { @Override public CustomAppWidgetProviderInfo createFromParcel(Parcel parcel) { - return new CustomAppWidgetProviderInfo(parcel, true, ""); + return new CustomAppWidgetProviderInfo(parcel, true); } @Override diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java index 7cf022175b..2fdf35429d 100644 --- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java +++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java @@ -18,6 +18,7 @@ package com.android.launcher3.widget.custom; import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET; import static com.android.launcher3.model.data.LauncherAppWidgetInfo.CUSTOM_WIDGET_ID; +import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; @@ -44,7 +45,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.function.Consumer; import java.util.stream.Stream; @@ -57,17 +57,16 @@ public class CustomWidgetManager implements PluginListener, new MainThreadInitializedObject<>(CustomWidgetManager::new); private static final String TAG = "CustomWidgetManager"; + private static final String PLUGIN_PKG = "android"; private final Context mContext; - private final HashMap mPlugins; + private final HashMap mPlugins; private final List mCustomWidgets; - private final HashMap mWidgetsIdMap; private Consumer mWidgetRefreshCallback; private CustomWidgetManager(Context context) { mContext = context; mPlugins = new HashMap<>(); mCustomWidgets = new ArrayList<>(); - mWidgetsIdMap = new HashMap<>(); PluginManagerWrapper.INSTANCE.get(context) .addPluginListener(this, CustomWidgetPlugin.class, true); @@ -78,8 +77,7 @@ public class CustomWidgetManager implements PluginListener, Class cls = Class.forName(s); CustomWidgetPlugin plugin = (CustomWidgetPlugin) cls.getDeclaredConstructor(Context.class).newInstance(context); - mPlugins.put(plugin.getId(), plugin); - onPluginConnected(mPlugins.get(plugin.getId()), context); + onPluginConnected(plugin, context); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException | NoSuchMethodException | InvocationTargetException e) { @@ -102,35 +100,17 @@ public class CustomWidgetManager implements PluginListener, Parcel parcel = Parcel.obtain(); providers.get(0).writeToParcel(parcel, 0); parcel.setDataPosition(0); - CustomAppWidgetProviderInfo info = newInfo(plugin.getId(), plugin, parcel, context); + CustomAppWidgetProviderInfo info = newInfo(plugin, parcel); parcel.recycle(); + mPlugins.put(info.provider, plugin); mCustomWidgets.add(info); - mWidgetsIdMap.put(info.provider, plugin.getId()); } @Override public void onPluginDisconnected(CustomWidgetPlugin plugin) { - String providerId = plugin.getId(); - if (mPlugins.containsKey(providerId)) { - mPlugins.remove(providerId); - } - - ComponentName cn = null; - for (Map.Entry entry: mWidgetsIdMap.entrySet()) { - if (entry.getValue().equals(providerId)) { - cn = (ComponentName) entry.getKey(); - } - } - - if (cn != null) { - mWidgetsIdMap.remove(cn); - for (int i = 0; i < mCustomWidgets.size(); i++) { - if (mCustomWidgets.get(i).getComponent().equals(cn)) { - mCustomWidgets.remove(i); - return; - } - } - } + ComponentName cn = getWidgetProviderComponent(plugin); + mPlugins.remove(cn); + mCustomWidgets.removeIf(w -> w.getComponent().equals(cn)); } /** @@ -145,7 +125,7 @@ public class CustomWidgetManager implements PluginListener, */ public void onViewCreated(LauncherAppWidgetHostView view) { CustomAppWidgetProviderInfo info = (CustomAppWidgetProviderInfo) view.getAppWidgetInfo(); - CustomWidgetPlugin plugin = mPlugins.get(info.providerId); + CustomWidgetPlugin plugin = mPlugins.get(info.provider); if (plugin == null) return; plugin.onViewCreated(view); } @@ -158,33 +138,19 @@ public class CustomWidgetManager implements PluginListener, return mCustomWidgets.stream(); } - /** - * Returns the widget id for a specific provider. - */ - public String getWidgetIdForCustomProvider(@NonNull ComponentName provider) { - if (mWidgetsIdMap.containsKey(provider)) { - return mWidgetsIdMap.get(provider); - } else { - return ""; - } - } - /** * Returns the widget provider in respect to given widget id. */ @Nullable - public LauncherAppWidgetProviderInfo getWidgetProvider(ComponentName componentName) { - for (LauncherAppWidgetProviderInfo info : mCustomWidgets) { - if (info.provider.equals(componentName)) return info; - } - return null; + public LauncherAppWidgetProviderInfo getWidgetProvider(ComponentName cn) { + return mCustomWidgets.stream() + .filter(w -> w.getComponent().equals(cn)).findAny().orElse(null); } - private static CustomAppWidgetProviderInfo newInfo(String providerId, CustomWidgetPlugin plugin, - Parcel parcel, Context context) { - CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo( - parcel, false, providerId); - plugin.updateWidgetInfo(info, context); + private CustomAppWidgetProviderInfo newInfo(CustomWidgetPlugin plugin, Parcel parcel) { + CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false); + info.provider = getWidgetProviderComponent(plugin); + plugin.updateWidgetInfo(info, mContext); return info; } @@ -195,4 +161,8 @@ public class CustomWidgetManager implements PluginListener, return CUSTOM_WIDGET_ID - mCustomWidgets.indexOf(getWidgetProvider(componentName)); } + private ComponentName getWidgetProviderComponent(CustomWidgetPlugin plugin) { + return new ComponentName( + PLUGIN_PKG, CLS_CUSTOM_WIDGET_PREFIX + plugin.getClass().getName()); + } } diff --git a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java index af4f22c287..6452ea2b64 100644 --- a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java +++ b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java @@ -39,13 +39,16 @@ public interface CustomWidgetPlugin extends Plugin { /** * Get the UUID for the custom widget. + * + * @deprecated Not used */ - String getId(); + @Deprecated + default String getId() { + return ""; + } /** * Used to modify a widgets' info. */ - default void updateWidgetInfo(AppWidgetProviderInfo info, Context context) { - - } + default void updateWidgetInfo(AppWidgetProviderInfo info, Context context) { } } diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index 389ec5c09c..56ac960c21 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -101,7 +101,7 @@ public class LoaderCursorTest { }); UserManagerState ums = new UserManagerState(); - mLoaderCursor = new LoaderCursor(mCursor, mApp, ums); + mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, null); ums.allUsers.put(0, Process.myUserHandle()); } diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt index dbca9d1dba..cb57918bcc 100644 --- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt +++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt @@ -1,25 +1,23 @@ package com.android.launcher3.model +import android.appwidget.AppWidgetManager import android.os.UserHandle import android.platform.test.flag.junit.SetFlagsRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.Flags import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherAppState import com.android.launcher3.LauncherModel import com.android.launcher3.LauncherModel.LoaderTransaction -import com.android.launcher3.LauncherPrefs import com.android.launcher3.icons.IconCache import com.android.launcher3.icons.cache.CachingLogic import com.android.launcher3.icons.cache.IconCacheUpdateHandler -import com.android.launcher3.pm.InstallSessionHelper import com.android.launcher3.pm.UserCache -import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper +import com.android.launcher3.ui.TestViewHelpers import com.android.launcher3.util.Executors.MODEL_EXECUTOR +import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext import com.android.launcher3.util.LooperIdleLock -import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext import com.android.launcher3.util.UserIconInfo import com.google.common.truth.Truth import java.util.concurrent.CountDownLatch @@ -29,6 +27,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.times @@ -36,13 +35,14 @@ import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import org.mockito.Spy +import org.mockito.kotlin.doReturn private const val INSERTION_STATEMENT_FILE = "databases/workspace_items.sql" @SmallTest @RunWith(AndroidJUnit4::class) class LoaderTaskTest { - private lateinit var context: SandboxContext + private var context = SandboxModelContext() @Mock private lateinit var app: LauncherAppState @Mock private lateinit var bgAllAppsList: AllAppsList @Mock private lateinit var modelDelegate: ModelDelegate @@ -62,14 +62,6 @@ class LoaderTaskTest { fun setup() { MockitoAnnotations.initMocks(this) - context = - SandboxContext( - InstrumentationRegistry.getInstrumentation().targetContext, - InstallSessionHelper.INSTANCE, - LauncherPrefs.INSTANCE, - ItemInstallQueue.INSTANCE, - PluginManagerWrapper.INSTANCE - ) val idp = InvariantDeviceProfile().apply { numRows = 5 @@ -77,7 +69,11 @@ class LoaderTaskTest { numDatabaseHotseatIcons = 5 } context.putObject(InvariantDeviceProfile.INSTANCE, idp) + context.putObject(LauncherAppState.INSTANCE, app) + doReturn(TestViewHelpers.findWidgetProvider(false)) + .`when`(context.spyService(AppWidgetManager::class.java)) + .getAppWidgetInfo(anyInt()) `when`(app.context).thenReturn(context) `when`(app.model).thenReturn(launcherModel) `when`(launcherModel.beginLoader(any(LoaderTask::class.java))).thenReturn(transaction) diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java index 244dc269b6..e806d1d6f2 100644 --- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java +++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java @@ -233,7 +233,7 @@ public class LauncherModelHelper { private final PackageManager mPm; private final File mDbDir; - SandboxModelContext() { + public SandboxModelContext() { super(ApplicationProvider.getApplicationContext(), UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE, LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,