diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index ad6ce7dbd2..2e1318b019 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -112,10 +112,23 @@ public class QuickstepModelDelegate extends ModelDelegate { } @Override - @WorkerThread - public void loadItems(UserManagerState ums, Map pinnedShortcuts) { + public void loadHotseatItems(UserManagerState ums, + Map pinnedShortcuts) { // TODO: Implement caching and preloading - super.loadItems(ums, pinnedShortcuts); + super.loadHotseatItems(ums, pinnedShortcuts); + + WorkspaceItemFactory hotseatFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, + mIDP.numDatabaseHotseatIcons, mHotseatState.containerId); + FixedContainerItems hotseatItems = new FixedContainerItems(mHotseatState.containerId, + mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get)); + mDataModel.extraItems.put(mHotseatState.containerId, hotseatItems); + } + + @Override + public void loadAllAppsItems(UserManagerState ums, + Map pinnedShortcuts) { + // TODO: Implement caching and preloading + super.loadAllAppsItems(ums, pinnedShortcuts); WorkspaceItemFactory allAppsFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, mIDP.numDatabaseAllAppsColumns, mAllAppsState.containerId); @@ -123,17 +136,22 @@ public class QuickstepModelDelegate extends ModelDelegate { mAllAppsState.containerId, mAllAppsState.storage.read(mApp.getContext(), allAppsFactory, ums.allUsers::get)); mDataModel.extraItems.put(mAllAppsState.containerId, allAppsPredictionItems); + } - WorkspaceItemFactory hotseatFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, - mIDP.numDatabaseHotseatIcons, mHotseatState.containerId); - FixedContainerItems hotseatItems = new FixedContainerItems(mHotseatState.containerId, - mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get)); - mDataModel.extraItems.put(mHotseatState.containerId, hotseatItems); + @Override + public void loadWidgetsRecommendationItems() { + // TODO: Implement caching and preloading + super.loadWidgetsRecommendationItems(); // Widgets prediction isn't used frequently. And thus, it is not persisted on disk. mDataModel.extraItems.put(mWidgetsRecommendationState.containerId, new FixedContainerItems(mWidgetsRecommendationState.containerId, new ArrayList<>())); + } + + @Override + public void markActive() { + super.markActive(); mActive = true; } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 6c62b31cbe..0a6a7cda9c 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -37,7 +37,6 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; @@ -72,24 +71,32 @@ public class LoaderCursor extends CursorWrapper { private final IconCache mIconCache; private final InvariantDeviceProfile mIDP; - private final IntArray itemsToRemove = new IntArray(); - private final IntArray restoredRows = new IntArray(); - private final IntSparseArrayMap occupied = new IntSparseArrayMap<>(); + private final IntArray mItemsToRemove = new IntArray(); + private final IntArray mRestoredRows = new IntArray(); + private final IntSparseArrayMap mOccupied = new IntSparseArrayMap<>(); - private final int iconPackageIndex; - private final int iconResourceIndex; - private final int iconIndex; - public final int titleIndex; + private final int mIconPackageIndex; + private final int mIconResourceIndex; + private final int mIconIndex; + public final int mTitleIndex; - private final int idIndex; - private final int containerIndex; - private final int itemTypeIndex; - private final int screenIndex; - private final int cellXIndex; - private final int cellYIndex; - private final int profileIdIndex; - private final int restoredIndex; - private final int intentIndex; + private final int mIdIndex; + private final int mContainerIndex; + private final int mItemTypeIndex; + private final int mScreenIndex; + private final int mCellXIndex; + private final int mCellYIndex; + private final int mProfileIdIndex; + private final int mRestoredIndex; + private final int mIntentIndex; + + private final int mAppWidgetIdIndex; + private final int mAppWidgetProviderIndex; + private final int mSpanXIndex; + private final int mSpanYIndex; + private final int mRankIndex; + private final int mOptionsIndex; + private final int mAppWidgetSourceIndex; @Nullable private LauncherActivityInfo mActivityInfo; @@ -114,20 +121,28 @@ public class LoaderCursor extends CursorWrapper { mPM = mContext.getPackageManager(); // Init column indices - iconIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON); - iconPackageIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE); - iconResourceIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE); - titleIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); + mIconIndex = getColumnIndexOrThrow(Favorites.ICON); + mIconPackageIndex = getColumnIndexOrThrow(Favorites.ICON_PACKAGE); + mIconResourceIndex = getColumnIndexOrThrow(Favorites.ICON_RESOURCE); + mTitleIndex = getColumnIndexOrThrow(Favorites.TITLE); - idIndex = getColumnIndexOrThrow(LauncherSettings.Favorites._ID); - containerIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER); - itemTypeIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); - screenIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN); - cellXIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX); - cellYIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); - profileIdIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID); - restoredIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.RESTORED); - intentIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + mIdIndex = getColumnIndexOrThrow(Favorites._ID); + mContainerIndex = getColumnIndexOrThrow(Favorites.CONTAINER); + mItemTypeIndex = getColumnIndexOrThrow(Favorites.ITEM_TYPE); + mScreenIndex = getColumnIndexOrThrow(Favorites.SCREEN); + mCellXIndex = getColumnIndexOrThrow(Favorites.CELLX); + mCellYIndex = getColumnIndexOrThrow(Favorites.CELLY); + mProfileIdIndex = getColumnIndexOrThrow(Favorites.PROFILE_ID); + mRestoredIndex = getColumnIndexOrThrow(Favorites.RESTORED); + mIntentIndex = getColumnIndexOrThrow(Favorites.INTENT); + + mAppWidgetIdIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_ID); + mAppWidgetProviderIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER); + mSpanXIndex = getColumnIndexOrThrow(Favorites.SPANX); + mSpanYIndex = getColumnIndexOrThrow(Favorites.SPANY); + mRankIndex = getColumnIndexOrThrow(Favorites.RANK); + mOptionsIndex = getColumnIndexOrThrow(Favorites.OPTIONS); + mAppWidgetSourceIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_SOURCE); } @Override @@ -137,18 +152,18 @@ public class LoaderCursor extends CursorWrapper { mActivityInfo = null; // Load common properties. - itemType = getInt(itemTypeIndex); - container = getInt(containerIndex); - id = getInt(idIndex); - serialNumber = getInt(profileIdIndex); + itemType = getInt(mItemTypeIndex); + container = getInt(mContainerIndex); + id = getInt(mIdIndex); + serialNumber = getInt(mProfileIdIndex); user = allUsers.get(serialNumber); - restoreFlag = getInt(restoredIndex); + restoreFlag = getInt(mRestoredIndex); } return result; } public Intent parseIntent() { - String intentDescription = getString(intentIndex); + String intentDescription = getString(mIntentIndex); try { return TextUtils.isEmpty(intentDescription) ? null : Intent.parseUri(intentDescription, 0); @@ -185,14 +200,14 @@ public class LoaderCursor extends CursorWrapper { public IconRequestInfo createIconRequestInfo( WorkspaceItemInfo wai, boolean useLowResIcon) { - String packageName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT - ? getString(iconPackageIndex) : null; - String resourceName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT - ? getString(iconResourceIndex) : null; - byte[] iconBlob = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT + String packageName = itemType == Favorites.ITEM_TYPE_SHORTCUT + ? getString(mIconPackageIndex) : null; + String resourceName = itemType == Favorites.ITEM_TYPE_SHORTCUT + ? getString(mIconResourceIndex) : null; + byte[] iconBlob = itemType == Favorites.ITEM_TYPE_SHORTCUT || itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT || restoreFlag != 0 - ? getBlob(iconIndex) : null; + ? getBlob(mIconIndex) : null; return new IconRequestInfo<>( wai, mActivityInfo, packageName, resourceName, iconBlob, useLowResIcon); @@ -202,7 +217,70 @@ public class LoaderCursor extends CursorWrapper { * Returns the title or empty string */ private String getTitle() { - return Utilities.trim(getString(titleIndex)); + return Utilities.trim(getString(mTitleIndex)); + } + + /** + * When loading an app widget for the workspace, returns it's app widget id + */ + public int getAppWidgetId() { + return getInt(mAppWidgetIdIndex); + } + + /** + * When loading an app widget for the workspace, returns the widget provider + */ + public String getAppWidgetProvider() { + return getString(mAppWidgetProviderIndex); + } + + /** + * Returns the x position for the item in the cell layout's grid + */ + public int getSpanX() { + return getInt(mSpanXIndex); + } + + /** + * Returns the y position for the item in the cell layout's grid + */ + public int getSpanY() { + return getInt(mSpanYIndex); + } + + /** + * Returns the rank for the item + */ + public int getRank() { + return getInt(mRankIndex); + } + + /** + * Returns the options for the item + */ + public int getOptions() { + return getInt(mOptionsIndex); + } + + /** + * When loading an app widget for the workspace, returns it's app widget source + */ + public int getAppWidgetSource() { + return getInt(mAppWidgetSourceIndex); + } + + /** + * Returns the screen that the item is on + */ + public int getScreen() { + return getInt(mScreenIndex); + } + + /** + * Returns the UX container that the item is in + */ + public int getContainer() { + return getInt(mContainerIndex); } /** @@ -320,7 +398,7 @@ public class LoaderCursor extends CursorWrapper { */ public void markDeleted(String reason) { FileLog.e(TAG, reason); - itemsToRemove.add(id); + mItemsToRemove.add(id); } /** @@ -328,10 +406,10 @@ public class LoaderCursor extends CursorWrapper { * @return true is any item was removed. */ public boolean commitDeleted() { - if (itemsToRemove.size() > 0) { + if (mItemsToRemove.size() > 0) { // Remove dead items mContext.getContentResolver().delete(mContentUri, Utilities.createDbSelectionQuery( - LauncherSettings.Favorites._ID, itemsToRemove), null); + Favorites._ID, mItemsToRemove), null); return true; } return false; @@ -342,7 +420,7 @@ public class LoaderCursor extends CursorWrapper { */ public void markRestored() { if (restoreFlag != 0) { - restoredRows.add(id); + mRestoredRows.add(id); restoreFlag = 0; } } @@ -352,13 +430,13 @@ public class LoaderCursor extends CursorWrapper { } public void commitRestoredItems() { - if (restoredRows.size() > 0) { + if (mRestoredRows.size() > 0) { // Update restored items that no longer require special handling ContentValues values = new ContentValues(); - values.put(LauncherSettings.Favorites.RESTORED, 0); + values.put(Favorites.RESTORED, 0); mContext.getContentResolver().update(mContentUri, values, Utilities.createDbSelectionQuery( - LauncherSettings.Favorites._ID, restoredRows), null); + Favorites._ID, mRestoredRows), null); } } @@ -366,8 +444,7 @@ public class LoaderCursor extends CursorWrapper { * Returns true is the item is on workspace or hotseat */ public boolean isOnWorkspaceOrHotseat() { - return container == LauncherSettings.Favorites.CONTAINER_DESKTOP || - container == LauncherSettings.Favorites.CONTAINER_HOTSEAT; + return container == Favorites.CONTAINER_DESKTOP || container == Favorites.CONTAINER_HOTSEAT; } /** @@ -381,9 +458,9 @@ public class LoaderCursor extends CursorWrapper { public void applyCommonProperties(ItemInfo info) { info.id = id; info.container = container; - info.screenId = getInt(screenIndex); - info.cellX = getInt(cellXIndex); - info.cellY = getInt(cellYIndex); + info.screenId = getInt(mScreenIndex); + info.cellX = getInt(mCellXIndex); + info.cellY = getInt(mCellYIndex); } public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) { @@ -396,7 +473,7 @@ public class LoaderCursor extends CursorWrapper { */ public void checkAndAddItem( ItemInfo info, BgDataModel dataModel, LoaderMemoryLogger logger) { - if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { + if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) { // Ensure that it is a valid intent. An exception here will // cause the item loading to get skipped ShortcutKey.fromItemInfo(info); @@ -413,9 +490,9 @@ public class LoaderCursor extends CursorWrapper { */ protected boolean checkItemPlacement(ItemInfo item) { int containerIndex = item.screenId; - if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + if (item.container == Favorites.CONTAINER_HOTSEAT) { final GridOccupancy hotseatOccupancy = - occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT); + mOccupied.get(Favorites.CONTAINER_HOTSEAT); if (item.screenId >= mIDP.numDatabaseHotseatIcons) { Log.e(TAG, "Error loading shortcut " + item @@ -438,19 +515,18 @@ public class LoaderCursor extends CursorWrapper { } else { final GridOccupancy occupancy = new GridOccupancy(mIDP.numDatabaseHotseatIcons, 1); occupancy.cells[item.screenId][0] = true; - occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy); + mOccupied.put(Favorites.CONTAINER_HOTSEAT, occupancy); return true; } - } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { + } else if (item.container != Favorites.CONTAINER_DESKTOP) { // Skip further checking if it is not the hotseat or workspace container return true; } final int countX = mIDP.numColumns; final int countY = mIDP.numRows; - if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP && - item.cellX < 0 || item.cellY < 0 || - item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) { + if (item.container == Favorites.CONTAINER_DESKTOP && item.cellX < 0 || item.cellY < 0 + || item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) { Log.e(TAG, "Error loading shortcut " + item + " into cell (" + containerIndex + "-" + item.screenId + ":" + item.cellX + "," + item.cellY @@ -458,7 +534,7 @@ public class LoaderCursor extends CursorWrapper { return false; } - if (!occupied.containsKey(item.screenId)) { + if (!mOccupied.containsKey(item.screenId)) { GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1); if (item.screenId == Workspace.FIRST_SCREEN_ID && FeatureFlags.QSB_ON_FIRST_SCREEN) { // Mark the first X columns (X is width of the search container) in the first row as @@ -468,9 +544,9 @@ public class LoaderCursor extends CursorWrapper { int spanY = 1; screen.markCells(0, 0, spanX, spanY, true); } - occupied.put(item.screenId, screen); + mOccupied.put(item.screenId, screen); } - final GridOccupancy occupancy = occupied.get(item.screenId); + final GridOccupancy occupancy = mOccupied.get(item.screenId); // Check if any workspace icons overlap with each other if (occupancy.isRegionVacant(item.cellX, item.cellY, item.spanX, item.spanY)) { diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 46a6a66c76..da9be499c8 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -58,7 +58,8 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; -import com.android.launcher3.LauncherSettings; +import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.LauncherSettings.Settings; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.Folder; @@ -198,7 +199,7 @@ public class LoaderTask implements Runnable { } Object traceToken = TraceHelper.INSTANCE.beginSection(TAG); - TimingLogger logger = new TimingLogger(TAG, "run"); + TimingLogger timingLogger = new TimingLogger(TAG, "run"); LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger(); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { List allShortcuts = new ArrayList<>(); @@ -208,7 +209,7 @@ public class LoaderTask implements Runnable { } finally { Trace.endSection(); } - logASplit(logger, "loadWorkspace"); + logASplit(timingLogger, "loadWorkspace"); // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db. // sanitizeData should not be invoked if the workspace is loaded from a db different @@ -216,22 +217,23 @@ public class LoaderTask implements Runnable { // (e.g. both grid preview and minimal device mode uses a different db) if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) { verifyNotStopped(); - sanitizeData(); - logASplit(logger, "sanitizeData"); + sanitizeFolders(mItemsDeleted); + sanitizeWidgetsShortcutsAndPackages(); + logASplit(timingLogger, "sanitizeData"); } verifyNotStopped(); mLauncherBinder.bindWorkspace(true /* incrementBindId */); - logASplit(logger, "bindWorkspace"); + logASplit(timingLogger, "bindWorkspace"); mModelDelegate.workspaceLoadComplete(); // Notify the installer packages of packages with active installs on the first screen. sendFirstScreenActiveInstallsBroadcast(); - logASplit(logger, "sendFirstScreenActiveInstallsBroadcast"); + logASplit(timingLogger, "sendFirstScreenActiveInstallsBroadcast"); // Take a break waitForIdle(); - logASplit(logger, "step 1 complete"); + logASplit(timingLogger, "step 1 complete"); verifyNotStopped(); // second step @@ -242,11 +244,11 @@ public class LoaderTask implements Runnable { } finally { Trace.endSection(); } - logASplit(logger, "loadAllApps"); + logASplit(timingLogger, "loadAllApps"); verifyNotStopped(); mLauncherBinder.bindAllApps(); - logASplit(logger, "bindAllApps"); + logASplit(timingLogger, "bindAllApps"); verifyNotStopped(); IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); @@ -254,69 +256,69 @@ public class LoaderTask implements Runnable { updateHandler.updateIcons(allActivityList, LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel()::onPackageIconsUpdated); - logASplit(logger, "update icon cache"); + logASplit(timingLogger, "update icon cache"); verifyNotStopped(); - logASplit(logger, "save shortcuts in icon cache"); + logASplit(timingLogger, "save shortcuts in icon cache"); updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(), mApp.getModel()::onPackageIconsUpdated); // Take a break waitForIdle(); - logASplit(logger, "step 2 complete"); + logASplit(timingLogger, "step 2 complete"); verifyNotStopped(); // third step List allDeepShortcuts = loadDeepShortcuts(); - logASplit(logger, "loadDeepShortcuts"); + logASplit(timingLogger, "loadDeepShortcuts"); verifyNotStopped(); mLauncherBinder.bindDeepShortcuts(); - logASplit(logger, "bindDeepShortcuts"); + logASplit(timingLogger, "bindDeepShortcuts"); verifyNotStopped(); - logASplit(logger, "save deep shortcuts in icon cache"); + logASplit(timingLogger, "save deep shortcuts in icon cache"); updateHandler.updateIcons(allDeepShortcuts, new ShortcutCachingLogic(), (pkgs, user) -> { }); // Take a break waitForIdle(); - logASplit(logger, "step 3 complete"); + logASplit(timingLogger, "step 3 complete"); verifyNotStopped(); // fourth step List allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null); - logASplit(logger, "load widgets"); + logASplit(timingLogger, "load widgets"); verifyNotStopped(); mLauncherBinder.bindWidgets(); - logASplit(logger, "bindWidgets"); + logASplit(timingLogger, "bindWidgets"); verifyNotStopped(); updateHandler.updateIcons(allWidgetsList, new ComponentWithIconCachingLogic(mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated); - logASplit(logger, "save widgets in icon cache"); + logASplit(timingLogger, "save widgets in icon cache"); // fifth step loadFolderNames(); verifyNotStopped(); updateHandler.finish(); - logASplit(logger, "finish icon update"); + logASplit(timingLogger, "finish icon update"); mModelDelegate.modelLoadComplete(); transaction.commit(); memoryLogger.clearLogs(); } catch (CancellationException e) { // Loader stopped, ignore - logASplit(logger, "Cancelled"); + logASplit(timingLogger, "Cancelled"); } catch (Exception e) { memoryLogger.printLogs(); throw e; } finally { - logger.dumpToLog(); + timingLogger.dumpToLog(); } TraceHelper.INSTANCE.endSection(traceToken); } @@ -326,9 +328,10 @@ public class LoaderTask implements Runnable { this.notify(); } - private void loadWorkspace(List allDeepShortcuts, LoaderMemoryLogger logger) { - loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI, - null /* selection */, logger); + private void loadWorkspace( + List allDeepShortcuts, LoaderMemoryLogger memoryLogger) { + loadWorkspace(allDeepShortcuts, Favorites.CONTENT_URI, + null /* selection */, memoryLogger); } protected void loadWorkspace( @@ -340,7 +343,7 @@ public class LoaderTask implements Runnable { List allDeepShortcuts, Uri contentUri, String selection, - @Nullable LoaderMemoryLogger logger) { + @Nullable LoaderMemoryLogger memoryLogger) { final Context context = mApp.getContext(); final ContentResolver contentResolver = context.getContentResolver(); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); @@ -356,13 +359,11 @@ public class LoaderTask implements Runnable { if (clearDb) { Log.d(TAG, "loadWorkspace: resetting launcher database"); - LauncherSettings.Settings.call(contentResolver, - LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); + Settings.call(contentResolver, Settings.METHOD_CREATE_EMPTY_DB); } Log.d(TAG, "loadWorkspace: loading default favorites"); - LauncherSettings.Settings.call(contentResolver, - LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES); + Settings.call(contentResolver, Settings.METHOD_LOAD_DEFAULT_FAVORITES); synchronized (mBgDataModel) { mBgDataModel.clear(); @@ -380,24 +381,8 @@ public class LoaderTask implements Runnable { contentResolver.query(contentUri, null, selection, null, null), contentUri, mApp, mUserManagerState); final Bundle extras = c.getExtras(); - mDbName = extras == null - ? null : extras.getString(LauncherSettings.Settings.EXTRA_DB_NAME); + mDbName = extras == null ? null : extras.getString(Settings.EXTRA_DB_NAME); try { - final int appWidgetIdIndex = c.getColumnIndexOrThrow( - LauncherSettings.Favorites.APPWIDGET_ID); - final int appWidgetProviderIndex = c.getColumnIndexOrThrow( - LauncherSettings.Favorites.APPWIDGET_PROVIDER); - final int spanXIndex = c.getColumnIndexOrThrow - (LauncherSettings.Favorites.SPANX); - final int spanYIndex = c.getColumnIndexOrThrow( - LauncherSettings.Favorites.SPANY); - final int rankIndex = c.getColumnIndexOrThrow( - LauncherSettings.Favorites.RANK); - final int optionsIndex = c.getColumnIndexOrThrow( - LauncherSettings.Favorites.OPTIONS); - final int sourceContainerIndex = c.getColumnIndexOrThrow( - LauncherSettings.Favorites.APPWIDGET_SOURCE); - final LongSparseArray unlockedUsers = new LongSparseArray<>(); mUserManagerState.init(mUserCache, mUserManager); @@ -425,437 +410,23 @@ public class LoaderTask implements Runnable { unlockedUsers.put(serialNo, userUnlocked); } - WorkspaceItemInfo info; - LauncherAppWidgetInfo appWidgetInfo; - LauncherAppWidgetProviderInfo widgetProviderInfo; - Intent intent; - String targetPkg; List> iconRequestInfos = new ArrayList<>(); while (!mStopped && c.moveToNext()) { - try { - if (c.user == null) { - // User has been deleted, remove the item. - c.markDeleted("User has been deleted"); - continue; - } - - boolean allowMissingTarget = false; - switch (c.itemType) { - case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: - case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: - case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: - intent = c.parseIntent(); - if (intent == null) { - c.markDeleted("Invalid or null intent"); - continue; - } - - int disabledState = mUserManagerState.isUserQuiet(c.serialNumber) - ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0; - ComponentName cn = intent.getComponent(); - targetPkg = cn == null ? intent.getPackage() : cn.getPackageName(); - - if (TextUtils.isEmpty(targetPkg) && - c.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { - c.markDeleted("Only legacy shortcuts can have null package"); - continue; - } - - // If there is no target package, its an implicit intent - // (legacy shortcut) which is always valid - boolean validTarget = TextUtils.isEmpty(targetPkg) || - mLauncherApps.isPackageEnabled(targetPkg, c.user); - - // If it's a deep shortcut, we'll use pinned shortcuts to restore it - if (cn != null && validTarget && c.itemType - != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { - // If the apk is present and the shortcut points to a specific - // component. - - // If the component is already present - if (mLauncherApps.isActivityEnabled(cn, c.user)) { - // no special handling necessary for this item - c.markRestored(); - } else { - // Gracefully try to find a fallback activity. - intent = pmHelper.getAppLaunchIntent(targetPkg, c.user); - if (intent != null) { - c.restoreFlag = 0; - c.updater().put( - LauncherSettings.Favorites.INTENT, - intent.toUri(0)).commit(); - cn = intent.getComponent(); - } else { - c.markDeleted("Unable to find a launch target"); - continue; - } - } - } - // else if cn == null => can't infer much, leave it - // else if !validPkg => could be restored icon or missing sd-card - - if (!TextUtils.isEmpty(targetPkg) && !validTarget) { - // Points to a valid app (superset of cn != null) but the apk - // is not available. - - if (c.restoreFlag != 0) { - // Package is not yet available but might be - // installed later. - FileLog.d(TAG, "package not yet restored: " + targetPkg); - - tempPackageKey.update(targetPkg, c.user); - if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) { - // Restore has started once. - } else if (installingPkgs.containsKey(tempPackageKey)) { - // App restore has started. Update the flag - c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED; - c.updater().put(LauncherSettings.Favorites.RESTORED, - c.restoreFlag).commit(); - } else { - c.markDeleted("Unrestored app removed: " + targetPkg); - continue; - } - } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) { - // Package is present but not available. - disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE; - // Add the icon on the workspace anyway. - allowMissingTarget = true; - } else if (!isSdCardReady) { - // SdCard is not ready yet. Package might get available, - // once it is ready. - Log.d(TAG, "Missing pkg, will check later: " + targetPkg); - mPendingPackages.add(new PackageUserKey(targetPkg, c.user)); - // Add the icon on the workspace anyway. - allowMissingTarget = true; - } else { - // Do not wait for external media load anymore. - c.markDeleted("Invalid package removed: " + targetPkg); - continue; - } - } - - if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) { - validTarget = false; - } - - if (validTarget) { - // The shortcut points to a valid target (either no target - // or something which is ready to be used) - c.markRestored(); - } - - boolean useLowResIcon = !c.isOnWorkspaceOrHotseat(); - - if (c.restoreFlag != 0) { - // Already verified above that user is same as default user - info = c.getRestoredItemInfo(intent); - } else if (c.itemType == - LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { - info = c.getAppShortcutInfo( - intent, - allowMissingTarget, - useLowResIcon, - !FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()); - } else if (c.itemType == - LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { - - ShortcutKey key = ShortcutKey.fromIntent(intent, c.user); - if (unlockedUsers.get(c.serialNumber)) { - ShortcutInfo pinnedShortcut = - shortcutKeyToPinnedShortcuts.get(key); - if (pinnedShortcut == null) { - // The shortcut is no longer valid. - c.markDeleted("Pinned shortcut not found"); - continue; - } - info = new WorkspaceItemInfo(pinnedShortcut, context); - // If the pinned deep shortcut is no longer published, - // use the last saved icon instead of the default. - mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon); - - if (pmHelper.isAppSuspended( - pinnedShortcut.getPackage(), info.user)) { - info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED; - } - intent = info.getIntent(); - allDeepShortcuts.add(pinnedShortcut); - } else { - // Create a shortcut info in disabled mode for now. - info = c.loadSimpleWorkspaceItem(); - info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER; - } - } else { // item type == ITEM_TYPE_SHORTCUT - info = c.loadSimpleWorkspaceItem(); - - // Shortcuts are only available on the primary profile - if (!TextUtils.isEmpty(targetPkg) - && pmHelper.isAppSuspended(targetPkg, c.user)) { - disabledState |= FLAG_DISABLED_SUSPENDED; - } - info.options = c.getInt(optionsIndex); - - // App shortcuts that used to be automatically added to Launcher - // didn't always have the correct intent flags set, so do that - // here - if (intent.getAction() != null && - intent.getCategories() != null && - intent.getAction().equals(Intent.ACTION_MAIN) && - intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) { - intent.addFlags( - Intent.FLAG_ACTIVITY_NEW_TASK | - Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - } - } - - if (info != null) { - if (info.itemType - != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { - // Skip deep shortcuts; their title and icons have already been - // loaded above. - iconRequestInfos.add( - c.createIconRequestInfo(info, useLowResIcon)); - } - - c.applyCommonProperties(info); - - info.intent = intent; - info.rank = c.getInt(rankIndex); - info.spanX = 1; - info.spanY = 1; - info.runtimeStatusFlags |= disabledState; - if (isSafeMode && !isSystemApp(context, intent)) { - info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE; - } - LauncherActivityInfo activityInfo = c.getLauncherActivityInfo(); - if (activityInfo != null) { - info.setProgressLevel( - PackageManagerHelper - .getLoadingProgress(activityInfo), - PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING); - } - - if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) { - tempPackageKey.update(targetPkg, c.user); - SessionInfo si = installingPkgs.get(tempPackageKey); - if (si == null) { - info.runtimeStatusFlags &= - ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; - } else if (activityInfo == null) { - int installProgress = (int) (si.getProgress() * 100); - - info.setProgressLevel( - installProgress, - PackageInstallInfo.STATUS_INSTALLING); - } - } - - c.checkAndAddItem(info, mBgDataModel, logger); - } else { - throw new RuntimeException("Unexpected null WorkspaceItemInfo"); - } - break; - - case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: - FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id); - c.applyCommonProperties(folderInfo); - - // Do not trim the folder label, as is was set by the user. - folderInfo.title = c.getString(c.titleIndex); - folderInfo.spanX = 1; - folderInfo.spanY = 1; - folderInfo.options = c.getInt(optionsIndex); - - // no special handling required for restored folders - c.markRestored(); - - c.checkAndAddItem(folderInfo, mBgDataModel, logger); - break; - - case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: - if (WidgetsModel.GO_DISABLE_WIDGETS) { - c.markDeleted("Only legacy shortcuts can have null package"); - continue; - } - // Follow through - case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: - // Read all Launcher-specific widget details - boolean customWidget = c.itemType == - LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; - - int appWidgetId = c.getInt(appWidgetIdIndex); - String savedProvider = c.getString(appWidgetProviderIndex); - final ComponentName component; - - boolean isSearchWidget = (c.getInt(optionsIndex) - & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0; - if (isSearchWidget) { - component = QsbContainerView.getSearchComponentName(context); - if (component == null) { - c.markDeleted("Discarding SearchWidget without packagename "); - continue; - } - } else { - component = ComponentName.unflattenFromString(savedProvider); - } - final boolean isIdValid = !c.hasRestoreFlag( - LauncherAppWidgetInfo.FLAG_ID_NOT_VALID); - final boolean wasProviderReady = !c.hasRestoreFlag( - LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY); - - ComponentKey providerKey = new ComponentKey(component, c.user); - if (!mWidgetProvidersMap.containsKey(providerKey)) { - mWidgetProvidersMap.put(providerKey, - widgetHelper.findProvider(component, c.user)); - } - final AppWidgetProviderInfo provider = - mWidgetProvidersMap.get(providerKey); - - final boolean isProviderReady = isValidProvider(provider); - if (!isSafeMode && !customWidget && - wasProviderReady && !isProviderReady) { - c.markDeleted( - "Deleting widget that isn't installed anymore: " - + provider); - } else { - if (isProviderReady) { - appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, - provider.provider); - - // The provider is available. So the widget is either - // available or not available. We do not need to track - // any future restore updates. - int status = c.restoreFlag & - ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED & - ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; - if (!wasProviderReady) { - // If provider was not previously ready, update the - // status and UI flag. - - // Id would be valid only if the widget restore broadcast was received. - if (isIdValid) { - status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY; - } - } - appWidgetInfo.restoreStatus = status; - } else { - Log.v(TAG, "Widget restore pending id=" + c.id - + " appWidgetId=" + appWidgetId - + " status =" + c.restoreFlag); - appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, - component); - appWidgetInfo.restoreStatus = c.restoreFlag; - - tempPackageKey.update(component.getPackageName(), c.user); - SessionInfo si = - installingPkgs.get(tempPackageKey); - Integer installProgress = si == null - ? null - : (int) (si.getProgress() * 100); - - if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) { - // Restore has started once. - } else if (installProgress != null) { - // App restore has started. Update the flag - appWidgetInfo.restoreStatus |= - LauncherAppWidgetInfo.FLAG_RESTORE_STARTED; - } else if (!isSafeMode) { - c.markDeleted("Unrestored widget removed: " + component); - continue; - } - - appWidgetInfo.installProgress = - installProgress == null ? 0 : installProgress; - } - if (appWidgetInfo.hasRestoreFlag( - LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) { - appWidgetInfo.bindOptions = c.parseIntent(); - } - - c.applyCommonProperties(appWidgetInfo); - appWidgetInfo.spanX = c.getInt(spanXIndex); - appWidgetInfo.spanY = c.getInt(spanYIndex); - appWidgetInfo.options = c.getInt(optionsIndex); - appWidgetInfo.user = c.user; - appWidgetInfo.sourceContainer = c.getInt(sourceContainerIndex); - - if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) { - c.markDeleted("Widget has invalid size: " - + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY); - continue; - } - widgetProviderInfo = - widgetHelper.getLauncherAppWidgetInfo(appWidgetId); - if (widgetProviderInfo != null - && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX - || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) { - FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent() - + " minSizes not meet: span=" + appWidgetInfo.spanX - + "x" + appWidgetInfo.spanY + " minSpan=" - + widgetProviderInfo.minSpanX + "x" - + widgetProviderInfo.minSpanY); - logWidgetInfo(mApp.getInvariantDeviceProfile(), - widgetProviderInfo); - } - if (!c.isOnWorkspaceOrHotseat()) { - c.markDeleted("Widget found where container != " + - "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!"); - continue; - } - - if (!customWidget) { - String providerName = - appWidgetInfo.providerName.flattenToString(); - if (!providerName.equals(savedProvider) || - (appWidgetInfo.restoreStatus != c.restoreFlag)) { - c.updater() - .put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, - providerName) - .put(LauncherSettings.Favorites.RESTORED, - appWidgetInfo.restoreStatus) - .commit(); - } - } - - if (appWidgetInfo.restoreStatus != - LauncherAppWidgetInfo.RESTORE_COMPLETED) { - appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo( - mApp.getContext(), - appWidgetInfo.providerName, - appWidgetInfo.user); - mIconCache.getTitleAndIconForApp( - appWidgetInfo.pendingItemInfo, false); - } - - c.checkAndAddItem(appWidgetInfo, mBgDataModel); - } - break; - } - } catch (Exception e) { - Log.e(TAG, "Desktop items loading interrupted", e); - } - } - if (FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()) { - Trace.beginSection("LoadWorkspaceIconsInBulk"); - try { - mIconCache.getTitlesAndIconsInBulk(iconRequestInfos); - for (IconRequestInfo iconRequestInfo : - iconRequestInfos) { - WorkspaceItemInfo wai = iconRequestInfo.itemInfo; - if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) { - iconRequestInfo.loadWorkspaceIcon(mApp.getContext()); - } - } - } finally { - Trace.endSection(); - } + processWorkspaceItem(c, memoryLogger, installingPkgs, isSdCardReady, + tempPackageKey, widgetHelper, pmHelper, shortcutKeyToPinnedShortcuts, + iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts); } + maybeLoadWorkspaceIconsInBulk(iconRequestInfos); } finally { IOUtils.closeSilently(c); } // Load delegate items - mModelDelegate.loadItems(mUserManagerState, shortcutKeyToPinnedShortcuts); + mModelDelegate.loadHotseatItems(mUserManagerState, shortcutKeyToPinnedShortcuts); + mModelDelegate.loadAllAppsItems(mUserManagerState, shortcutKeyToPinnedShortcuts); + mModelDelegate.loadWidgetsRecommendationItems(); + mModelDelegate.markActive(); // Load string cache mModelDelegate.loadStringCache(mBgDataModel.stringCache); @@ -885,7 +456,7 @@ public class LoaderTask implements Runnable { info.rank = rank; if (info.usingLowResIcon() - && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION + && info.itemType == Favorites.ITEM_TYPE_APPLICATION && verifier.isItemInPreview(info.rank)) { mIconCache.getTitleAndIcon(info, false); } @@ -896,6 +467,418 @@ public class LoaderTask implements Runnable { } } + private void processWorkspaceItem(LoaderCursor c, + LoaderMemoryLogger memoryLogger, + HashMap installingPkgs, + boolean isSdCardReady, + PackageUserKey tempPackageKey, + WidgetManagerHelper widgetHelper, + PackageManagerHelper pmHelper, + Map shortcutKeyToPinnedShortcuts, + List> iconRequestInfos, + LongSparseArray unlockedUsers, + boolean isSafeMode, + List allDeepShortcuts) { + + try { + if (c.user == null) { + // User has been deleted, remove the item. + c.markDeleted("User has been deleted"); + return; + } + + boolean allowMissingTarget = false; + switch (c.itemType) { + case Favorites.ITEM_TYPE_SHORTCUT: + case Favorites.ITEM_TYPE_APPLICATION: + case Favorites.ITEM_TYPE_DEEP_SHORTCUT: + Intent intent = c.parseIntent(); + if (intent == null) { + c.markDeleted("Invalid or null intent"); + return; + } + + int disabledState = mUserManagerState.isUserQuiet(c.serialNumber) + ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0; + ComponentName cn = intent.getComponent(); + String targetPkg = cn == null ? intent.getPackage() : cn.getPackageName(); + + if (TextUtils.isEmpty(targetPkg) + && c.itemType != Favorites.ITEM_TYPE_SHORTCUT) { + c.markDeleted("Only legacy shortcuts can have null package"); + return; + } + + // If there is no target package, it's an implicit intent + // (legacy shortcut) which is always valid + boolean validTarget = TextUtils.isEmpty(targetPkg) + || mLauncherApps.isPackageEnabled(targetPkg, c.user); + + // If it's a deep shortcut, we'll use pinned shortcuts to restore it + if (cn != null && validTarget && c.itemType + != Favorites.ITEM_TYPE_DEEP_SHORTCUT) { + // If the apk is present and the shortcut points to a specific component. + + // If the component is already present + if (mLauncherApps.isActivityEnabled(cn, c.user)) { + // no special handling necessary for this item + c.markRestored(); + } else { + // Gracefully try to find a fallback activity. + intent = pmHelper.getAppLaunchIntent(targetPkg, c.user); + if (intent != null) { + c.restoreFlag = 0; + c.updater().put( + Favorites.INTENT, + intent.toUri(0)).commit(); + cn = intent.getComponent(); + } else { + c.markDeleted("Unable to find a launch target"); + return; + } + } + } + // else if cn == null => can't infer much, leave it + // else if !validPkg => could be restored icon or missing sd-card + + if (!TextUtils.isEmpty(targetPkg) && !validTarget) { + // Points to a valid app (superset of cn != null) but the apk + // is not available. + + if (c.restoreFlag != 0) { + // Package is not yet available but might be + // installed later. + FileLog.d(TAG, "package not yet restored: " + targetPkg); + + tempPackageKey.update(targetPkg, c.user); + if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) { + // Restore has started once. + } else if (installingPkgs.containsKey(tempPackageKey)) { + // App restore has started. Update the flag + c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED; + c.updater().put(Favorites.RESTORED, + c.restoreFlag).commit(); + } else { + c.markDeleted("Unrestored app removed: " + targetPkg); + return; + } + } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) { + // Package is present but not available. + disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE; + // Add the icon on the workspace anyway. + allowMissingTarget = true; + } else if (!isSdCardReady) { + // SdCard is not ready yet. Package might get available, + // once it is ready. + Log.d(TAG, "Missing pkg, will check later: " + targetPkg); + mPendingPackages.add(new PackageUserKey(targetPkg, c.user)); + // Add the icon on the workspace anyway. + allowMissingTarget = true; + } else { + // Do not wait for external media load anymore. + c.markDeleted("Invalid package removed: " + targetPkg); + return; + } + } + + if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) { + validTarget = false; + } + + if (validTarget) { + // The shortcut points to a valid target (either no target + // or something which is ready to be used) + c.markRestored(); + } + + boolean useLowResIcon = !c.isOnWorkspaceOrHotseat(); + + WorkspaceItemInfo info; + if (c.restoreFlag != 0) { + // Already verified above that user is same as default user + info = c.getRestoredItemInfo(intent); + } else if (c.itemType == Favorites.ITEM_TYPE_APPLICATION) { + info = c.getAppShortcutInfo(intent, allowMissingTarget, useLowResIcon, + !FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()); + } else if (c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) { + ShortcutKey key = ShortcutKey.fromIntent(intent, c.user); + if (unlockedUsers.get(c.serialNumber)) { + ShortcutInfo pinnedShortcut = shortcutKeyToPinnedShortcuts.get(key); + if (pinnedShortcut == null) { + // The shortcut is no longer valid. + c.markDeleted("Pinned shortcut not found"); + return; + } + info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext()); + // If the pinned deep shortcut is no longer published, + // use the last saved icon instead of the default. + mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon); + + if (pmHelper.isAppSuspended( + pinnedShortcut.getPackage(), info.user)) { + info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED; + } + intent = info.getIntent(); + allDeepShortcuts.add(pinnedShortcut); + } else { + // Create a shortcut info in disabled mode for now. + info = c.loadSimpleWorkspaceItem(); + info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER; + } + } else { // item type == ITEM_TYPE_SHORTCUT + info = c.loadSimpleWorkspaceItem(); + + // Shortcuts are only available on the primary profile + if (!TextUtils.isEmpty(targetPkg) + && pmHelper.isAppSuspended(targetPkg, c.user)) { + disabledState |= FLAG_DISABLED_SUSPENDED; + } + info.options = c.getOptions(); + + // App shortcuts that used to be automatically added to Launcher + // didn't always have the correct intent flags set, so do that here + if (intent.getAction() != null + && intent.getCategories() != null + && intent.getAction().equals(Intent.ACTION_MAIN) + && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + } + } + + if (info != null) { + if (info.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT) { + // Skip deep shortcuts; their title and icons have already been + // loaded above. + iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon)); + } + + c.applyCommonProperties(info); + + info.intent = intent; + info.rank = c.getRank(); + info.spanX = 1; + info.spanY = 1; + info.runtimeStatusFlags |= disabledState; + if (isSafeMode && !isSystemApp(mApp.getContext(), intent)) { + info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE; + } + LauncherActivityInfo activityInfo = c.getLauncherActivityInfo(); + if (activityInfo != null) { + info.setProgressLevel( + PackageManagerHelper.getLoadingProgress(activityInfo), + PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING); + } + + if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) { + tempPackageKey.update(targetPkg, c.user); + SessionInfo si = installingPkgs.get(tempPackageKey); + if (si == null) { + info.runtimeStatusFlags + &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; + } else if (activityInfo == null) { + int installProgress = (int) (si.getProgress() * 100); + + info.setProgressLevel(installProgress, + PackageInstallInfo.STATUS_INSTALLING); + } + } + + c.checkAndAddItem(info, mBgDataModel, memoryLogger); + } else { + throw new RuntimeException("Unexpected null WorkspaceItemInfo"); + } + break; + + case Favorites.ITEM_TYPE_FOLDER: + FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id); + c.applyCommonProperties(folderInfo); + + // Do not trim the folder label, as is was set by the user. + folderInfo.title = c.getString(c.mTitleIndex); + folderInfo.spanX = 1; + folderInfo.spanY = 1; + folderInfo.options = c.getOptions(); + + // no special handling required for restored folders + c.markRestored(); + + c.checkAndAddItem(folderInfo, mBgDataModel, memoryLogger); + break; + + case Favorites.ITEM_TYPE_APPWIDGET: + if (WidgetsModel.GO_DISABLE_WIDGETS) { + c.markDeleted("Only legacy shortcuts can have null package"); + return; + } + // Follow through + case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: + // Read all Launcher-specific widget details + boolean customWidget = c.itemType + == Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; + + int appWidgetId = c.getAppWidgetId(); + String savedProvider = c.getAppWidgetProvider(); + final ComponentName component; + + if ((c.getOptions() & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0) { + component = QsbContainerView.getSearchComponentName(mApp.getContext()); + if (component == null) { + c.markDeleted("Discarding SearchWidget without packagename "); + return; + } + } else { + component = ComponentName.unflattenFromString(savedProvider); + } + final boolean isIdValid = + !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID); + final boolean wasProviderReady = + !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY); + + ComponentKey providerKey = new ComponentKey(component, c.user); + if (!mWidgetProvidersMap.containsKey(providerKey)) { + mWidgetProvidersMap.put(providerKey, + widgetHelper.findProvider(component, c.user)); + } + final AppWidgetProviderInfo provider = mWidgetProvidersMap.get(providerKey); + + final boolean isProviderReady = isValidProvider(provider); + if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) { + c.markDeleted("Deleting widget that isn't installed anymore: " + provider); + } else { + LauncherAppWidgetInfo appWidgetInfo; + if (isProviderReady) { + appWidgetInfo = + new LauncherAppWidgetInfo(appWidgetId, provider.provider); + + // The provider is available. So the widget is either + // available or not available. We do not need to track + // any future restore updates. + int status = c.restoreFlag + & ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED + & ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; + 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 |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY; + } + } + appWidgetInfo.restoreStatus = status; + } else { + Log.v(TAG, "Widget restore pending id=" + c.id + + " appWidgetId=" + appWidgetId + + " status =" + c.restoreFlag); + appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, component); + appWidgetInfo.restoreStatus = c.restoreFlag; + + tempPackageKey.update(component.getPackageName(), c.user); + SessionInfo si = installingPkgs.get(tempPackageKey); + Integer installProgress = si == null + ? null + : (int) (si.getProgress() * 100); + + if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) { + // Restore has started once. + } else if (installProgress != null) { + // App restore has started. Update the flag + appWidgetInfo.restoreStatus + |= LauncherAppWidgetInfo.FLAG_RESTORE_STARTED; + } else if (!isSafeMode) { + c.markDeleted("Unrestored widget removed: " + component); + return; + } + + appWidgetInfo.installProgress = + installProgress == null ? 0 : installProgress; + } + if (appWidgetInfo.hasRestoreFlag( + LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) { + appWidgetInfo.bindOptions = c.parseIntent(); + } + + c.applyCommonProperties(appWidgetInfo); + appWidgetInfo.spanX = c.getSpanX(); + appWidgetInfo.spanY = c.getSpanY(); + appWidgetInfo.options = c.getOptions(); + appWidgetInfo.user = c.user; + appWidgetInfo.sourceContainer = c.getAppWidgetSource(); + + if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) { + c.markDeleted("Widget has invalid size: " + + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY); + return; + } + LauncherAppWidgetProviderInfo widgetProviderInfo = + widgetHelper.getLauncherAppWidgetInfo(appWidgetId); + if (widgetProviderInfo != null + && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX + || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) { + FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent() + + " minSizes not meet: span=" + appWidgetInfo.spanX + + "x" + appWidgetInfo.spanY + " minSpan=" + + widgetProviderInfo.minSpanX + "x" + + widgetProviderInfo.minSpanY); + logWidgetInfo(mApp.getInvariantDeviceProfile(), + widgetProviderInfo); + } + if (!c.isOnWorkspaceOrHotseat()) { + c.markDeleted("Widget found where container != CONTAINER_DESKTOP" + + "nor CONTAINER_HOTSEAT - ignoring!"); + return; + } + + if (!customWidget) { + String providerName = appWidgetInfo.providerName.flattenToString(); + if (!providerName.equals(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( + mApp.getContext(), + appWidgetInfo.providerName, + appWidgetInfo.user); + mIconCache.getTitleAndIconForApp( + appWidgetInfo.pendingItemInfo, false); + } + + c.checkAndAddItem(appWidgetInfo, mBgDataModel); + } + break; + } + } catch (Exception e) { + Log.e(TAG, "Desktop items loading interrupted", e); + } + } + + private void maybeLoadWorkspaceIconsInBulk( + List> iconRequestInfos) { + if (FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()) { + Trace.beginSection("LoadWorkspaceIconsInBulk"); + try { + mIconCache.getTitlesAndIconsInBulk(iconRequestInfos); + for (IconRequestInfo iconRequestInfo : iconRequestInfos) { + WorkspaceItemInfo wai = iconRequestInfo.itemInfo; + if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) { + iconRequestInfo.loadWorkspaceIcon(mApp.getContext()); + } + } + } finally { + Trace.endSection(); + } + } + } + private void setIgnorePackages(IconCacheUpdateHandler updateHandler) { // Ignore packages which have a promise icon. synchronized (mBgDataModel) { @@ -917,15 +900,12 @@ public class LoaderTask implements Runnable { } } - private void sanitizeData() { - Context context = mApp.getContext(); - ContentResolver contentResolver = context.getContentResolver(); - if (mItemsDeleted) { + private void sanitizeFolders(boolean itemsDeleted) { + if (itemsDeleted) { // Remove any empty folder - int[] deletedFolderIds = LauncherSettings.Settings - .call(contentResolver, - LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS) - .getIntArray(LauncherSettings.Settings.EXTRA_VALUE); + int[] deletedFolderIds = Settings.call(mApp.getContext().getContentResolver(), + Settings.METHOD_DELETE_EMPTY_FOLDERS) + .getIntArray(Settings.EXTRA_VALUE); synchronized (mBgDataModel) { for (int folderId : deletedFolderIds) { mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId)); @@ -933,11 +913,16 @@ public class LoaderTask implements Runnable { mBgDataModel.itemsIdMap.remove(folderId); } } - } + } + + private void sanitizeWidgetsShortcutsAndPackages() { + Context context = mApp.getContext(); + ContentResolver contentResolver = context.getContentResolver(); + // Remove any ghost widgets - LauncherSettings.Settings.call(contentResolver, - LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS); + Settings.call(contentResolver, + Settings.METHOD_REMOVE_GHOST_WIDGETS); // Update pinned state of model shortcuts mBgDataModel.updateShortcutPinnedState(context); @@ -1107,10 +1092,12 @@ public class LoaderTask implements Runnable { FileLog.d(TAG, widgetDimension.toString()); } - private static void logASplit(final TimingLogger logger, final String label) { - logger.addSplit(label); - if (DEBUG) { - Log.d(TAG, label); + private static void logASplit(@Nullable TimingLogger timingLogger, String label) { + if (timingLogger != null) { + timingLogger.addSplit(label); + if (DEBUG) { + Log.d(TAG, label); + } } } } diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java index 3bd9470566..0639a6cbe2 100644 --- a/src/com/android/launcher3/model/ModelDelegate.java +++ b/src/com/android/launcher3/model/ModelDelegate.java @@ -80,10 +80,29 @@ public class ModelDelegate implements ResourceBasedOverride { } /** - * Load delegate items if any in the data model + * Load hot seat items if any in the data model */ @WorkerThread - public void loadItems(UserManagerState ums, Map pinnedShortcuts) { } + public void loadHotseatItems(UserManagerState ums, + Map pinnedShortcuts) { } + + /** + * Load all apps items if any in the data model + */ + @WorkerThread + public void loadAllAppsItems(UserManagerState ums, + Map pinnedShortcuts) { } + + /** + * Load widget recommendation items if any in the data model + */ + @WorkerThread + public void loadWidgetsRecommendationItems() { } + + /** + * Marks the ModelDelegate as active + */ + public void markActive() { } /** * Load String cache diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index 6444ef6927..7ab86ad4fa 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -18,6 +18,9 @@ package com.android.launcher3.model; import static androidx.test.InstrumentationRegistry.getContext; +import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_ID; +import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_PROVIDER; +import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_SOURCE; import static com.android.launcher3.LauncherSettings.Favorites.CELLX; import static com.android.launcher3.LauncherSettings.Favorites.CELLY; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER; @@ -30,9 +33,13 @@ import static com.android.launcher3.LauncherSettings.Favorites.INTENT; 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_SHORTCUT; +import static com.android.launcher3.LauncherSettings.Favorites.OPTIONS; import static com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID; +import static com.android.launcher3.LauncherSettings.Favorites.RANK; import static com.android.launcher3.LauncherSettings.Favorites.RESTORED; import static com.android.launcher3.LauncherSettings.Favorites.SCREEN; +import static com.android.launcher3.LauncherSettings.Favorites.SPANX; +import static com.android.launcher3.LauncherSettings.Favorites.SPANY; import static com.android.launcher3.LauncherSettings.Favorites.TITLE; import static com.android.launcher3.LauncherSettings.Favorites._ID; import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY; @@ -92,7 +99,9 @@ public class LoaderCursorTest { mCursor = new MatrixCursor(new String[] { ICON, ICON_PACKAGE, ICON_RESOURCE, TITLE, _ID, CONTAINER, ITEM_TYPE, PROFILE_ID, - SCREEN, CELLX, CELLY, RESTORED, INTENT + SCREEN, CELLX, CELLY, RESTORED, INTENT, + APPWIDGET_ID, APPWIDGET_PROVIDER, SPANX, + SPANY, RANK, OPTIONS, APPWIDGET_SOURCE }); UserManagerState ums = new UserManagerState();