From d24d33925ae8f2f3ad3b06158c826c7fd895bcde Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 10 Jan 2024 12:03:30 -0800 Subject: [PATCH] Using WidgetInflater in loader task This removes duplicate logic for widget inflation. Since the widget inflation can now happen during loader, the restore logging can also be moved completely to the loader Bug: 318539160 Test: atest TaplBinderTests Flag: None Change-Id: If9f336e7bf49ee7df121d7d9852b674d98124895 --- src/com/android/launcher3/Launcher.java | 34 +- .../LauncherRestoreEventLogger.kt | 53 ++- .../android/launcher3/model/LoaderCursor.java | 20 +- .../android/launcher3/model/LoaderTask.java | 18 +- .../launcher3/model/ModelDbController.java | 4 +- .../launcher3/model/WorkspaceItemProcessor.kt | 331 +++++------------- .../launcher3/provider/LauncherDbUtils.java | 2 +- .../launcher3/provider/RestoreDbTask.java | 10 +- .../launcher3/util/PackageManagerHelper.java | 4 - .../launcher3/widget/WidgetInflater.kt | 32 +- .../launcher3/widget/WidgetManagerHelper.java | 3 +- .../custom/CustomAppWidgetProviderInfo.java | 15 +- .../widget/custom/CustomWidgetManager.java | 72 ++-- .../systemui/plugins/CustomWidgetPlugin.java | 11 +- .../launcher3/model/LoaderCursorTest.java | 2 +- .../android/launcher3/model/LoaderTaskTest.kt | 24 +- .../launcher3/util/LauncherModelHelper.java | 2 +- 17 files changed, 237 insertions(+), 400 deletions(-) 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,