From 43bf11d9c95f76c2dfeb625b23cb458df81252b3 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 2 Feb 2017 13:52:53 -0800 Subject: Separating methods for updating the model to a sepatate class. Removing static access to model update methods, to allow for better access control and testing Change-Id: I9afe004dbf1b2fe50df422fd28bceea9230a4704 --- src/com/android/launcher3/CellLayout.java | 2 +- src/com/android/launcher3/FolderInfo.java | 10 +- src/com/android/launcher3/Launcher.java | 30 +- src/com/android/launcher3/LauncherModel.java | 317 +---------------- src/com/android/launcher3/Workspace.java | 8 +- .../LauncherAccessibilityDelegate.java | 6 +- .../ShortcutMenuAccessibilityDelegate.java | 2 +- src/com/android/launcher3/folder/Folder.java | 26 +- .../android/launcher3/folder/FolderPagedView.java | 2 +- .../launcher3/model/AddWorkspaceItemsTask.java | 9 +- src/com/android/launcher3/model/ModelWriter.java | 374 +++++++++++++++++++++ .../launcher3/model/PackageUpdatedTask.java | 14 +- .../launcher3/model/ShortcutsChangedTask.java | 2 +- .../launcher3/model/UserLockStateChangedTask.java | 2 +- .../launcher3/util/ManagedProfileHeuristic.java | 2 +- 15 files changed, 442 insertions(+), 364 deletions(-) create mode 100644 src/com/android/launcher3/model/ModelWriter.java (limited to 'src/com/android') diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index da12e67de..121b9fbed 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -2144,7 +2144,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { info.spanY = lp.cellVSpan; if (requiresDbUpdate) { - LauncherModel.modifyItemInDatabase(getContext(), info, container, screenId, + mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId, info.cellX, info.cellY, info.spanX, info.spanY); } } diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java index 5fff2e76b..2c69d0a69 100644 --- a/src/com/android/launcher3/FolderInfo.java +++ b/src/com/android/launcher3/FolderInfo.java @@ -16,9 +16,9 @@ package com.android.launcher3; -import android.content.Context; import android.os.Process; +import com.android.launcher3.model.ModelWriter; import com.android.launcher3.util.ContentWriter; import java.util.ArrayList; @@ -128,17 +128,17 @@ public class FolderInfo extends ItemInfo { /** * @param option flag to set or clear * @param isEnabled whether to set or clear the flag - * @param context if not null, save changes to the db. + * @param writer if not null, save changes to the db. */ - public void setOption(int option, boolean isEnabled, Context context) { + public void setOption(int option, boolean isEnabled, ModelWriter writer) { int oldOptions = options; if (isEnabled) { options |= option; } else { options &= ~option; } - if (context != null && oldOptions != options) { - LauncherModel.updateItemInDatabase(context, this); + if (writer != null && oldOptions != options) { + writer.updateItemInDatabase(this); } } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 11db9a0eb..1c077c2e5 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -85,6 +85,7 @@ import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.DefaultAppSearchController; import com.android.launcher3.anim.AnimationLayerSet; +import com.android.launcher3.model.ModelWriter; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.popup.PopupDataProvider; import com.android.launcher3.compat.AppWidgetManagerCompat; @@ -256,6 +257,7 @@ public class Launcher extends BaseActivity private ViewOnDrawExecutor mPendingExecutor; private LauncherModel mModel; + private ModelWriter mModelWriter; private IconCache mIconCache; private ExtractedColors mExtractedColors; private LauncherAccessibilityDelegate mAccessibilityDelegate; @@ -373,6 +375,7 @@ public class Launcher extends BaseActivity mSharedPrefs = Utilities.getPrefs(this); mIsSafeModeEnabled = getPackageManager().isSafeMode(); mModel = app.setLauncher(this); + mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout()); mIconCache = app.getIconCache(); mAccessibilityDelegate = new LauncherAccessibilityDelegate(this); @@ -1500,7 +1503,7 @@ public class Launcher extends BaseActivity return; } - LauncherModel.addItemToDatabase(this, info, container, screenId, cellXY[0], cellXY[1]); + getModelWriter().addItemToDatabase(info, container, screenId, cellXY[0], cellXY[1]); mWorkspace.addInScreen(view, info); } @@ -1528,7 +1531,7 @@ public class Launcher extends BaseActivity launcherInfo.minSpanY = itemInfo.minSpanY; launcherInfo.user = appWidgetInfo.getUser(); - LauncherModel.addItemToDatabase(this, launcherInfo, + getModelWriter().addItemToDatabase(launcherInfo, itemInfo.container, itemInfo.screenId, itemInfo.cellX, itemInfo.cellY); if (hostView == null) { @@ -1688,6 +1691,10 @@ public class Launcher extends BaseActivity return mModel; } + public ModelWriter getModelWriter() { + return mModelWriter; + } + public SharedPreferences getSharedPrefs() { return mSharedPrefs; } @@ -2129,8 +2136,7 @@ public class Launcher extends BaseActivity folderInfo.title = getText(R.string.folder_name); // Update the model - LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screenId, - cellX, cellY); + getModelWriter().addItemToDatabase(folderInfo, container, screenId, cellX, cellY); // Create the view FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, layout, folderInfo); @@ -2158,7 +2164,7 @@ public class Launcher extends BaseActivity mWorkspace.removeWorkspaceItem(v); } if (deleteFromDb) { - LauncherModel.deleteItemFromDatabase(this, itemInfo); + getModelWriter().deleteItemFromDatabase(itemInfo); } } else if (itemInfo instanceof FolderInfo) { final FolderInfo folderInfo = (FolderInfo) itemInfo; @@ -2167,7 +2173,7 @@ public class Launcher extends BaseActivity } mWorkspace.removeWorkspaceItem(v); if (deleteFromDb) { - LauncherModel.deleteFolderAndContentsFromDatabase(this, folderInfo); + getModelWriter().deleteFolderAndContentsFromDatabase(folderInfo); } } else if (itemInfo instanceof LauncherAppWidgetInfo) { final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo; @@ -2196,7 +2202,7 @@ public class Launcher extends BaseActivity } }.executeOnExecutor(Utilities.THREAD_POOL_EXECUTOR); } - LauncherModel.deleteItemFromDatabase(this, widgetInfo); + getModelWriter().deleteItemFromDatabase(widgetInfo); } @Override @@ -3389,7 +3395,7 @@ public class Launcher extends BaseActivity throw (new RuntimeException(desc)); } else { Log.d(TAG, desc); - LauncherModel.deleteItemFromDatabase(this, item); + getModelWriter().deleteItemFromDatabase(item); continue; } } @@ -3486,7 +3492,7 @@ public class Launcher extends BaseActivity + " belongs to component " + item.providerName + ", as the provider is null"); } - LauncherModel.deleteItemFromDatabase(this, item); + getModelWriter().deleteItemFromDatabase(item); return; } @@ -3533,14 +3539,14 @@ public class Launcher extends BaseActivity : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; } - LauncherModel.updateItemInDatabase(this, item); + getModelWriter().updateItemInDatabase(item); } } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) && (appWidgetInfo.configure == null)) { // The widget was marked as UI not ready, but there is no configure activity to // update the UI. item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED; - LauncherModel.updateItemInDatabase(this, item); + getModelWriter().updateItemInDatabase(item); } } @@ -3590,7 +3596,7 @@ public class Launcher extends BaseActivity info.restoreStatus = finalRestoreFlag; mWorkspace.reinflateWidgetsIfNecessary(); - LauncherModel.updateItemInDatabase(this, info); + getModelWriter().updateItemInDatabase(info); return info; } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 79f9792ac..7540dac46 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -57,6 +57,7 @@ import com.android.launcher3.model.CacheDataUpdatedTask; import com.android.launcher3.model.ExtendedModelTask; import com.android.launcher3.model.GridSizeMigrationTask; import com.android.launcher3.model.LoaderCursor; +import com.android.launcher3.model.ModelWriter; import com.android.launcher3.model.PackageInstallStateChangedTask; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.model.PackageUpdatedTask; @@ -264,19 +265,8 @@ public class LauncherModel extends BroadcastReceiver enqueueModelUpdateTask(new AddWorkspaceItemsTask(appsProvider)); } - /** - * Adds an item to the DB if it was not created previously, or move it to a new - * - */ - public static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container, - long screenId, int cellX, int cellY) { - if (item.container == ItemInfo.NO_ID) { - // From all apps - addItemToDatabase(context, item, container, screenId, cellX, cellY); - } else { - // From somewhere else - moveItemInDatabase(context, item, container, screenId, cellX, cellY); - } + public ModelWriter getWriter(boolean hasVerticalHotseat) { + return new ModelWriter(mApp.getContext(), sBgDataModel, hasVerticalHotseat); } static void checkItemInfoLocked( @@ -330,281 +320,6 @@ public class LauncherModel extends BroadcastReceiver runOnWorkerThread(r); } - static void updateItemInDatabaseHelper(Context context, final ContentWriter writer, - final ItemInfo item, final String callingFunction) { - final long itemId = item.id; - final Uri uri = LauncherSettings.Favorites.getContentUri(itemId); - final ContentResolver cr = context.getContentResolver(); - - final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); - final Context appContext = context.getApplicationContext(); - Runnable r = new Runnable() { - public void run() { - cr.update(uri, writer.getValues(appContext), null, null); - updateItemArrays(item, itemId, stackTrace); - } - }; - runOnWorkerThread(r); - } - - static void updateItemsInDatabaseHelper(Context context, final ArrayList valuesList, - final ArrayList items, final String callingFunction) { - final ContentResolver cr = context.getContentResolver(); - - final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); - Runnable r = new Runnable() { - public void run() { - ArrayList ops = - new ArrayList(); - int count = items.size(); - for (int i = 0; i < count; i++) { - ItemInfo item = items.get(i); - final long itemId = item.id; - final Uri uri = LauncherSettings.Favorites.getContentUri(itemId); - ContentValues values = valuesList.get(i); - - ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build()); - updateItemArrays(item, itemId, stackTrace); - - } - try { - cr.applyBatch(LauncherProvider.AUTHORITY, ops); - } catch (Exception e) { - e.printStackTrace(); - } - } - }; - runOnWorkerThread(r); - } - - static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) { - // Lock on mBgLock *after* the db operation - synchronized (sBgDataModel) { - checkItemInfoLocked(itemId, item, stackTrace); - - if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP && - item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - // Item is in a folder, make sure this folder exists - if (!sBgDataModel.folders.containsKey(item.container)) { - // An items container is being set to a that of an item which is not in - // the list of Folders. - String msg = "item: " + item + " container being set to: " + - item.container + ", not in the list of folders"; - Log.e(TAG, msg); - } - } - - // Items are added/removed from the corresponding FolderInfo elsewhere, such - // as in Workspace.onDrop. Here, we just add/remove them from the list of items - // that are on the desktop, as appropriate - ItemInfo modelItem = sBgDataModel.itemsIdMap.get(itemId); - if (modelItem != null && - (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP || - modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) { - switch (modelItem.itemType) { - case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: - case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: - case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: - case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: - if (!sBgDataModel.workspaceItems.contains(modelItem)) { - sBgDataModel.workspaceItems.add(modelItem); - } - break; - default: - break; - } - } else { - sBgDataModel.workspaceItems.remove(modelItem); - } - } - } - - /** - * Move an item in the DB to a new - */ - public static void moveItemInDatabase(Context context, final ItemInfo item, final long container, - final long screenId, final int cellX, final int cellY) { - item.container = container; - item.cellX = cellX; - item.cellY = cellY; - - // We store hotseat items in canonical form which is this orientation invariant position - // in the hotseat - if (context instanceof Launcher && screenId < 0 && - container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screenId = Launcher.getLauncher(context).getHotseat() - .getOrderInHotseat(cellX, cellY); - } else { - item.screenId = screenId; - } - - final ContentWriter writer = new ContentWriter(context) - .put(LauncherSettings.Favorites.CONTAINER, item.container) - .put(LauncherSettings.Favorites.CELLX, item.cellX) - .put(LauncherSettings.Favorites.CELLY, item.cellY) - .put(LauncherSettings.Favorites.RANK, item.rank) - .put(LauncherSettings.Favorites.SCREEN, item.screenId); - - updateItemInDatabaseHelper(context, writer, item, "moveItemInDatabase"); - } - - /** - * Move items in the DB to a new . We assume that the - * cellX, cellY have already been updated on the ItemInfos. - */ - public static void moveItemsInDatabase(Context context, final ArrayList items, - final long container, final int screen) { - - ArrayList contentValues = new ArrayList(); - int count = items.size(); - - for (int i = 0; i < count; i++) { - ItemInfo item = items.get(i); - item.container = container; - - // We store hotseat items in canonical form which is this orientation invariant position - // in the hotseat - if (context instanceof Launcher && screen < 0 && - container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screenId = Launcher.getLauncher(context).getHotseat().getOrderInHotseat(item.cellX, - item.cellY); - } else { - item.screenId = screen; - } - - final ContentValues values = new ContentValues(); - values.put(LauncherSettings.Favorites.CONTAINER, item.container); - values.put(LauncherSettings.Favorites.CELLX, item.cellX); - values.put(LauncherSettings.Favorites.CELLY, item.cellY); - values.put(LauncherSettings.Favorites.RANK, item.rank); - values.put(LauncherSettings.Favorites.SCREEN, item.screenId); - - contentValues.add(values); - } - updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase"); - } - - /** - * Move and/or resize item in the DB to a new - */ - static void modifyItemInDatabase(Context context, final ItemInfo item, final long container, - final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) { - item.container = container; - item.cellX = cellX; - item.cellY = cellY; - item.spanX = spanX; - item.spanY = spanY; - - // We store hotseat items in canonical form which is this orientation invariant position - // in the hotseat - if (context instanceof Launcher && screenId < 0 && - container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screenId = Launcher.getLauncher(context).getHotseat() - .getOrderInHotseat(cellX, cellY); - } else { - item.screenId = screenId; - } - - final ContentWriter writer = new ContentWriter(context) - .put(LauncherSettings.Favorites.CONTAINER, item.container) - .put(LauncherSettings.Favorites.CELLX, item.cellX) - .put(LauncherSettings.Favorites.CELLY, item.cellY) - .put(LauncherSettings.Favorites.RANK, item.rank) - .put(LauncherSettings.Favorites.SPANX, item.spanX) - .put(LauncherSettings.Favorites.SPANY, item.spanY) - .put(LauncherSettings.Favorites.SCREEN, item.screenId); - - updateItemInDatabaseHelper(context, writer, item, "modifyItemInDatabase"); - } - - /** - * Update an item to the database in a specified container. - */ - public static void updateItemInDatabase(Context context, final ItemInfo item) { - ContentWriter writer = new ContentWriter(context); - item.onAddToDatabase(writer); - updateItemInDatabaseHelper(context, writer, item, "updateItemInDatabase"); - } - - /** - * Add an item to the database in a specified container. Sets the container, screen, cellX and - * cellY fields of the item. Also assigns an ID to the item. - */ - public static void addItemToDatabase(Context context, final ItemInfo item, final long container, - final long screenId, final int cellX, final int cellY) { - item.container = container; - item.cellX = cellX; - item.cellY = cellY; - // We store hotseat items in canonical form which is this orientation invariant position - // in the hotseat - if (context instanceof Launcher && screenId < 0 && - container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screenId = Launcher.getLauncher(context).getHotseat() - .getOrderInHotseat(cellX, cellY); - } else { - item.screenId = screenId; - } - - final ContentWriter writer = new ContentWriter(context); - final ContentResolver cr = context.getContentResolver(); - item.onAddToDatabase(writer); - - item.id = LauncherSettings.Settings.call(cr, LauncherSettings.Settings.METHOD_NEW_ITEM_ID) - .getLong(LauncherSettings.Settings.EXTRA_VALUE); - - writer.put(LauncherSettings.Favorites._ID, item.id); - - final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); - final Context appContext = context.getApplicationContext(); - Runnable r = new Runnable() { - public void run() { - cr.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues(appContext)); - - synchronized (sBgDataModel) { - checkItemInfoLocked(item.id, item, stackTrace); - sBgDataModel.addItem(appContext, item, true); - } - } - }; - runOnWorkerThread(r); - } - - /** - * Removes the specified item from the database - */ - public static void deleteItemFromDatabase(Context context, final ItemInfo item) { - ArrayList items = new ArrayList<>(); - items.add(item); - deleteItemsFromDatabase(context, items); - } - - /** - * Removes all the items from the database matching {@param matcher}. - */ - public static void deleteItemsFromDatabase(Context context, ItemInfoMatcher matcher) { - deleteItemsFromDatabase(context, matcher.filterItemInfos(sBgDataModel.itemsIdMap)); - } - - /** - * Removes the specified items from the database - */ - public static void deleteItemsFromDatabase(Context context, - final Iterable items) { - final ContentResolver cr = context.getContentResolver(); - final Context appContext = context.getApplicationContext(); - Runnable r = new Runnable() { - public void run() { - for (ItemInfo item : items) { - final Uri uri = LauncherSettings.Favorites.getContentUri(item.id); - cr.delete(uri, null, null); - - sBgDataModel.removeItem(appContext, item); - } - } - }; - runOnWorkerThread(r); - } - /** * Update the order of the workspace screens in the database. The array list contains * a list of screen ids in the order that they should appear. @@ -653,27 +368,6 @@ public class LauncherModel extends BroadcastReceiver runOnWorkerThread(r); } - /** - * Remove the specified folder and all its contents from the database. - */ - public static void deleteFolderAndContentsFromDatabase(Context context, final FolderInfo info) { - final ContentResolver cr = context.getContentResolver(); - final Context appContext = context.getApplicationContext(); - - Runnable r = new Runnable() { - public void run() { - cr.delete(LauncherSettings.Favorites.CONTENT_URI, - LauncherSettings.Favorites.CONTAINER + "=" + info.id, null); - sBgDataModel.removeItem(appContext, info.contents); - info.contents.clear(); - - cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null); - sBgDataModel.removeItem(appContext, info); - } - }; - runOnWorkerThread(r); - } - /** * Set this as the current Launcher activity object for the loader. */ @@ -2203,6 +1897,11 @@ public class LauncherModel extends BroadcastReceiver } }); } + + public ModelWriter getModelWriter() { + // Updates from model task, do not deal with icon position in hotseat. + return mModel.getWriter(false /* hasVerticalHotseat */); + } } public void updateAndBindShortcutInfo(final ShortcutInfo si, final ShortcutInfoCompat info) { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index d2008a6a6..fd0bc0ce7 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2652,8 +2652,8 @@ public class Workspace extends PagedView } } - LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, lp.cellX, - lp.cellY, item.spanX, item.spanY); + mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId, + lp.cellX, lp.cellY, item.spanX, item.spanY); } else { if (!returnToOriginalCellToPreventShuffling) { onNoCellFound(dropTargetLayout); @@ -3385,7 +3385,7 @@ public class Workspace extends PagedView } // Add the item to DB before adding to screen ensures that the container and other // values of the info is properly updated. - LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, + mLauncher.getModelWriter().addOrMoveItemInDatabase(info, container, screenId, mTargetCell[0], mTargetCell[1]); addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], @@ -4003,7 +4003,7 @@ public class Workspace extends PagedView HashSet packages = new HashSet<>(1); packages.add(packageName); ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packages, user); - LauncherModel.deleteItemsFromDatabase(mLauncher, matcher); + mLauncher.getModelWriter().deleteItemsFromDatabase(matcher); removeItemsByMatcher(matcher); } diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index b77493bef..a476650c9 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -168,7 +168,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme public void run() { if (item instanceof AppInfo) { ShortcutInfo info = ((AppInfo) item).makeShortcut(); - LauncherModel.addItemToDatabase(mLauncher, info, + mLauncher.getModelWriter().addItemToDatabase(info, LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0], coordinates[1]); @@ -194,7 +194,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme final int[] coordinates = new int[2]; final long screenId = findSpaceOnWorkspace(item, coordinates); - LauncherModel.moveItemInDatabase(mLauncher, info, + mLauncher.getModelWriter().moveItemInDatabase(info, LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0], coordinates[1]); @@ -304,7 +304,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme ((LauncherAppWidgetHostView) host).updateAppWidgetSize(null, sizeRange.left, sizeRange.top, sizeRange.right, sizeRange.bottom); host.requestLayout(); - LauncherModel.updateItemInDatabase(mLauncher, info); + mLauncher.getModelWriter().updateItemInDatabase(info); announceConfirmation(mLauncher.getString(R.string.widget_resized, info.spanX, info.spanY)); } diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java index f7ca7034d..b784fe7f8 100644 --- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java @@ -59,7 +59,7 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele Runnable onComplete = new Runnable() { @Override public void run() { - LauncherModel.addItemToDatabase(mLauncher, info, + mLauncher.getModelWriter().addItemToDatabase(info, LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0], coordinates[1]); ArrayList itemList = new ArrayList<>(); diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index 876c3c4de..bd12e16ec 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -354,7 +354,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC // gets saved. String newTitle = mFolderName.getText().toString(); mInfo.setTitle(newTitle); - LauncherModel.updateItemInDatabase(mLauncher, mInfo); + mLauncher.getModelWriter().updateItemInDatabase(mInfo); Utilities.sendCustomAccessibilityEvent( this, AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, @@ -444,7 +444,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC // TODO: Remove this, as with multi-page folders, there will never be any overflow for (ShortcutInfo item: overflow) { mInfo.remove(item, false); - LauncherModel.deleteItemFromDatabase(mLauncher, item); + mLauncher.getModelWriter().deleteItemFromDatabase(item); } DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams(); @@ -646,7 +646,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC mPageIndicator.playEntryAnimation(); if (updateAnimationFlag) { - mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher); + mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, + mLauncher.getModelWriter()); } } }); @@ -972,7 +973,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC // been refreshed yet. if (getItemCount() <= mContent.itemsPerPage()) { // Show the animation, next time something is added to the folder. - mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, false, mLauncher); + mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, false, + mLauncher.getModelWriter()); } if (!isFlingToDelete) { @@ -1021,7 +1023,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC items.add(info); } - LauncherModel.moveItemsInDatabase(mLauncher, items, mInfo.id, 0); + mLauncher.getModelWriter().moveItemsInDatabase(items, mInfo.id, 0); } public void notifyDrop() { @@ -1188,8 +1190,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC mInfo.screenId); ShortcutInfo finalItem = mInfo.contents.remove(0); newIcon = mLauncher.createShortcut(cellLayout, finalItem); - LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container, - mInfo.screenId, mInfo.cellX, mInfo.cellY); + mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem, + mInfo.container, mInfo.screenId, mInfo.cellX, mInfo.cellY); } // Remove the folder @@ -1300,8 +1302,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC currentDragView = mContent.createAndAddViewForRank(si, mEmptyCellRank); // Actually move the item in the database if it was an external drag. Call this // before creating the view, so that ShortcutInfo is updated appropriately. - LauncherModel.addOrMoveItemInDatabase( - mLauncher, si, mInfo.id, 0, si.cellX, si.cellY); + mLauncher.getModelWriter().addOrMoveItemInDatabase( + si, mInfo.id, 0, si.cellX, si.cellY); // We only need to update the locations if it doesn't get handled in #onDropCompleted. if (d.dragSource != this) { @@ -1341,7 +1343,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC if (mContent.getPageCount() > 1) { // The animation has already been shown while opening the folder. - mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher); + mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher.getModelWriter()); } if (d.stateAnnouncer != null) { @@ -1365,8 +1367,8 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC public void onAdd(ShortcutInfo item) { mContent.createAndAddViewForRank(item, mContent.allocateRankForNewItem()); mItemsInvalidated = true; - LauncherModel.addOrMoveItemInDatabase( - mLauncher, item, mInfo.id, 0, item.cellX, item.cellY); + mLauncher.getModelWriter().addOrMoveItemInDatabase( + item, mInfo.id, 0, item.cellX, item.cellY); } public void onRemove(ShortcutInfo item) { diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java index 4a2a7350b..9dfdfdc19 100644 --- a/src/com/android/launcher3/folder/FolderPagedView.java +++ b/src/com/android/launcher3/folder/FolderPagedView.java @@ -336,7 +336,7 @@ public class FolderPagedView extends PagedView { info.cellY = newY; info.rank = rank; if (saveChanges) { - LauncherModel.addOrMoveItemInDatabase(getContext(), info, + mFolder.mLauncher.getModelWriter().addOrMoveItemInDatabase(info, mFolder.mInfo.id, 0, info.cellX, info.cellY); } } diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index c97b3b5cf..969605483 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -95,7 +95,9 @@ public class AddWorkspaceItemsTask extends ExtendedModelTask { } // Add the shortcut to the db - addItemToDatabase(context, itemInfo, screenId, cordinates); + getModelWriter().addItemToDatabase(itemInfo, + LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, + cordinates[0], cordinates[1]); // Save the ShortcutInfo for binding in the workspace addedItemsFinal.add(itemInfo); @@ -129,11 +131,6 @@ public class AddWorkspaceItemsTask extends ExtendedModelTask { } } - protected void addItemToDatabase(Context context, ItemInfo item, long screenId, int[] pos) { - LauncherModel.addItemToDatabase(context, item, - LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, pos[0], pos[1]); - } - protected void updateScreens(Context context, ArrayList workspaceScreens) { LauncherModel.updateWorkspaceScreenOrder(context, workspaceScreens); } diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java new file mode 100644 index 000000000..4931dca14 --- /dev/null +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.model; + +import android.content.ContentProviderOperation; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +import com.android.launcher3.FolderInfo; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; +import com.android.launcher3.LauncherProvider; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.LauncherSettings.Settings; +import com.android.launcher3.ShortcutInfo; +import com.android.launcher3.util.ContentWriter; +import com.android.launcher3.util.ItemInfoMatcher; +import com.android.launcher3.util.LooperExecuter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.concurrent.Executor; + +/** + * Class for handling model updates. + */ +public class ModelWriter { + + private static final String TAG = "ModelWriter"; + + private final Context mContext; + private final BgDataModel mBgDataModel; + private final Executor mWorkerExecutor; + private final boolean mHasVerticalHotseat; + + public ModelWriter(Context context, BgDataModel dataModel, boolean hasVerticalHotseat) { + mContext = context; + mBgDataModel = dataModel; + mWorkerExecutor = new LooperExecuter(LauncherModel.getWorkerLooper()); + mHasVerticalHotseat = hasVerticalHotseat; + } + + private void updateItemInfoProps( + ItemInfo item, long container, long screenId, int cellX, int cellY) { + item.container = container; + item.cellX = cellX; + item.cellY = cellY; + // We store hotseat items in canonical form which is this orientation invariant position + // in the hotseat + if (container == Favorites.CONTAINER_HOTSEAT) { + item.screenId = mHasVerticalHotseat + ? LauncherAppState.getIDP(mContext).numHotseatIcons - cellY - 1 : cellX; + } else { + item.screenId = screenId; + } + } + + /** + * Adds an item to the DB if it was not created previously, or move it to a new + * + */ + public void addOrMoveItemInDatabase(ItemInfo item, + long container, long screenId, int cellX, int cellY) { + if (item.container == ItemInfo.NO_ID) { + // From all apps + addItemToDatabase(item, container, screenId, cellX, cellY); + } else { + // From somewhere else + moveItemInDatabase(item, container, screenId, cellX, cellY); + } + } + + private void checkItemInfoLocked(long itemId, ItemInfo item, StackTraceElement[] stackTrace) { + ItemInfo modelItem = mBgDataModel.itemsIdMap.get(itemId); + if (modelItem != null && item != modelItem) { + // check all the data is consistent + if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) { + ShortcutInfo modelShortcut = (ShortcutInfo) modelItem; + ShortcutInfo shortcut = (ShortcutInfo) item; + if (modelShortcut.title.toString().equals(shortcut.title.toString()) && + modelShortcut.intent.filterEquals(shortcut.intent) && + modelShortcut.id == shortcut.id && + modelShortcut.itemType == shortcut.itemType && + modelShortcut.container == shortcut.container && + modelShortcut.screenId == shortcut.screenId && + modelShortcut.cellX == shortcut.cellX && + modelShortcut.cellY == shortcut.cellY && + modelShortcut.spanX == shortcut.spanX && + modelShortcut.spanY == shortcut.spanY) { + // For all intents and purposes, this is the same object + return; + } + } + + // the modelItem needs to match up perfectly with item if our model is + // to be consistent with the database-- for now, just require + // modelItem == item or the equality check above + String msg = "item: " + ((item != null) ? item.toString() : "null") + + "modelItem: " + + ((modelItem != null) ? modelItem.toString() : "null") + + "Error: ItemInfo passed to checkItemInfo doesn't match original"; + RuntimeException e = new RuntimeException(msg); + if (stackTrace != null) { + e.setStackTrace(stackTrace); + } + throw e; + } + } + + /** + * Move an item in the DB to a new + */ + public void moveItemInDatabase(final ItemInfo item, + long container, long screenId, int cellX, int cellY) { + updateItemInfoProps(item, container, screenId, cellX, cellY); + + final ContentWriter writer = new ContentWriter(mContext) + .put(Favorites.CONTAINER, item.container) + .put(Favorites.CELLX, item.cellX) + .put(Favorites.CELLY, item.cellY) + .put(Favorites.RANK, item.rank) + .put(Favorites.SCREEN, item.screenId); + + mWorkerExecutor.execute(new UpdateItemRunnable(item, writer)); + } + + /** + * Move items in the DB to a new . We assume that the + * cellX, cellY have already been updated on the ItemInfos. + */ + public void moveItemsInDatabase(final ArrayList items, long container, int screen) { + ArrayList contentValues = new ArrayList<>(); + int count = items.size(); + + for (int i = 0; i < count; i++) { + ItemInfo item = items.get(i); + updateItemInfoProps(item, container, screen, item.cellX, item.cellY); + + final ContentValues values = new ContentValues(); + values.put(Favorites.CONTAINER, item.container); + values.put(Favorites.CELLX, item.cellX); + values.put(Favorites.CELLY, item.cellY); + values.put(Favorites.RANK, item.rank); + values.put(Favorites.SCREEN, item.screenId); + + contentValues.add(values); + } + mWorkerExecutor.execute(new UpdateItemsRunnable(items, contentValues)); + } + + /** + * Move and/or resize item in the DB to a new + */ + public void modifyItemInDatabase(final ItemInfo item, + long container, long screenId, int cellX, int cellY, int spanX, int spanY) { + updateItemInfoProps(item, container, screenId, cellX, cellY); + item.spanX = spanX; + item.spanY = spanY; + + final ContentWriter writer = new ContentWriter(mContext) + .put(Favorites.CONTAINER, item.container) + .put(Favorites.CELLX, item.cellX) + .put(Favorites.CELLY, item.cellY) + .put(Favorites.RANK, item.rank) + .put(Favorites.SPANX, item.spanX) + .put(Favorites.SPANY, item.spanY) + .put(Favorites.SCREEN, item.screenId); + + mWorkerExecutor.execute(new UpdateItemRunnable(item, writer)); + } + + /** + * Update an item to the database in a specified container. + */ + public void updateItemInDatabase(ItemInfo item) { + ContentWriter writer = new ContentWriter(mContext); + item.onAddToDatabase(writer); + mWorkerExecutor.execute(new UpdateItemRunnable(item, writer)); + } + + /** + * Add an item to the database in a specified container. Sets the container, screen, cellX and + * cellY fields of the item. Also assigns an ID to the item. + */ + public void addItemToDatabase(final ItemInfo item, + long container, long screenId, int cellX, int cellY) { + updateItemInfoProps(item, container, screenId, cellX, cellY); + + final ContentWriter writer = new ContentWriter(mContext); + final ContentResolver cr = mContext.getContentResolver(); + item.onAddToDatabase(writer); + + item.id = Settings.call(cr, Settings.METHOD_NEW_ITEM_ID).getLong(Settings.EXTRA_VALUE); + writer.put(Favorites._ID, item.id); + + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); + mWorkerExecutor.execute(new Runnable() { + public void run() { + cr.insert(Favorites.CONTENT_URI, writer.getValues(mContext)); + + synchronized (mBgDataModel) { + checkItemInfoLocked(item.id, item, stackTrace); + mBgDataModel.addItem(mContext, item, true); + } + } + }); + } + + /** + * Removes the specified item from the database + */ + public void deleteItemFromDatabase(ItemInfo item) { + deleteItemsFromDatabase(Arrays.asList(item)); + } + + /** + * Removes all the items from the database matching {@param matcher}. + */ + public void deleteItemsFromDatabase(ItemInfoMatcher matcher) { + deleteItemsFromDatabase(matcher.filterItemInfos(mBgDataModel.itemsIdMap)); + } + + /** + * Removes the specified items from the database + */ + public void deleteItemsFromDatabase(final Iterable items) { + mWorkerExecutor.execute(new Runnable() { + public void run() { + for (ItemInfo item : items) { + final Uri uri = Favorites.getContentUri(item.id); + mContext.getContentResolver().delete(uri, null, null); + + mBgDataModel.removeItem(mContext, item); + } + } + }); + } + + /** + * Remove the specified folder and all its contents from the database. + */ + public void deleteFolderAndContentsFromDatabase(final FolderInfo info) { + mWorkerExecutor.execute(new Runnable() { + public void run() { + ContentResolver cr = mContext.getContentResolver(); + cr.delete(LauncherSettings.Favorites.CONTENT_URI, + LauncherSettings.Favorites.CONTAINER + "=" + info.id, null); + mBgDataModel.removeItem(mContext, info.contents); + info.contents.clear(); + + cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null); + mBgDataModel.removeItem(mContext, info); + } + }); + } + + private class UpdateItemRunnable extends UpdateItemBaseRunnable { + private final ItemInfo mItem; + private final ContentWriter mWriter; + private final long mItemId; + + UpdateItemRunnable(ItemInfo item, ContentWriter writer) { + mItem = item; + mWriter = writer; + mItemId = item.id; + } + + @Override + public void run() { + Uri uri = Favorites.getContentUri(mItemId); + mContext.getContentResolver().update(uri, mWriter.getValues(mContext), null, null); + updateItemArrays(mItem, mItemId); + } + } + + private class UpdateItemsRunnable extends UpdateItemBaseRunnable { + private final ArrayList mValues; + private final ArrayList mItems; + + UpdateItemsRunnable(ArrayList items, ArrayList values) { + mValues = values; + mItems = items; + } + + @Override + public void run() { + ArrayList ops = new ArrayList<>(); + int count = mItems.size(); + for (int i = 0; i < count; i++) { + ItemInfo item = mItems.get(i); + final long itemId = item.id; + final Uri uri = Favorites.getContentUri(itemId); + ContentValues values = mValues.get(i); + + ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build()); + updateItemArrays(item, itemId); + } + try { + mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, ops); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + private abstract class UpdateItemBaseRunnable implements Runnable { + private final StackTraceElement[] mStackTrace; + + UpdateItemBaseRunnable() { + mStackTrace = new Throwable().getStackTrace(); + } + + protected void updateItemArrays(ItemInfo item, long itemId) { + // Lock on mBgLock *after* the db operation + synchronized (mBgDataModel) { + checkItemInfoLocked(itemId, item, mStackTrace); + + if (item.container != Favorites.CONTAINER_DESKTOP && + item.container != Favorites.CONTAINER_HOTSEAT) { + // Item is in a folder, make sure this folder exists + if (!mBgDataModel.folders.containsKey(item.container)) { + // An items container is being set to a that of an item which is not in + // the list of Folders. + String msg = "item: " + item + " container being set to: " + + item.container + ", not in the list of folders"; + Log.e(TAG, msg); + } + } + + // Items are added/removed from the corresponding FolderInfo elsewhere, such + // as in Workspace.onDrop. Here, we just add/remove them from the list of items + // that are on the desktop, as appropriate + ItemInfo modelItem = mBgDataModel.itemsIdMap.get(itemId); + if (modelItem != null && + (modelItem.container == Favorites.CONTAINER_DESKTOP || + modelItem.container == Favorites.CONTAINER_HOTSEAT)) { + switch (modelItem.itemType) { + case Favorites.ITEM_TYPE_APPLICATION: + case Favorites.ITEM_TYPE_SHORTCUT: + case Favorites.ITEM_TYPE_DEEP_SHORTCUT: + case Favorites.ITEM_TYPE_FOLDER: + if (!mBgDataModel.workspaceItems.contains(modelItem)) { + mBgDataModel.workspaceItems.add(modelItem); + } + break; + default: + break; + } + } else { + mBgDataModel.workspaceItems.remove(modelItem); + } + } + } + } +} diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 211b9793f..ee7186aa4 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -270,7 +270,7 @@ public class PackageUpdatedTask extends ExtendedModelTask { updatedShortcuts.add(si); } if (infoUpdated) { - LauncherModel.updateItemInDatabase(context, si); + getModelWriter().updateItemInDatabase(si); } } else if (info instanceof LauncherAppWidgetInfo && mOp == OP_ADD) { LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info; @@ -287,7 +287,7 @@ public class PackageUpdatedTask extends ExtendedModelTask { widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY; widgets.add(widgetInfo); - LauncherModel.updateItemInDatabase(context, widgetInfo); + getModelWriter().updateItemInDatabase(widgetInfo); } } } @@ -295,7 +295,7 @@ public class PackageUpdatedTask extends ExtendedModelTask { bindUpdatedShortcuts(updatedShortcuts, removedShortcuts, mUser); if (!removedShortcuts.isEmpty()) { - LauncherModel.deleteItemsFromDatabase(context, removedShortcuts); + getModelWriter().deleteItemsFromDatabase(removedShortcuts); } if (!widgets.isEmpty()) { @@ -332,10 +332,10 @@ public class PackageUpdatedTask extends ExtendedModelTask { } if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) { - LauncherModel.deleteItemsFromDatabase( - context, ItemInfoMatcher.ofPackages(removedPackages, mUser)); - LauncherModel.deleteItemsFromDatabase( - context, ItemInfoMatcher.ofComponents(removedComponents, mUser)); + getModelWriter().deleteItemsFromDatabase( + ItemInfoMatcher.ofPackages(removedPackages, mUser)); + getModelWriter().deleteItemsFromDatabase( + ItemInfoMatcher.ofComponents(removedComponents, mUser)); // Remove any queued items from the install queue InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser); diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java index ba7112fd9..d8a429cba 100644 --- a/src/com/android/launcher3/model/ShortcutsChangedTask.java +++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java @@ -104,7 +104,7 @@ public class ShortcutsChangedTask extends ExtendedModelTask { bindUpdatedShortcuts(updatedShortcutInfos, removedShortcutInfos, mUser); if (!removedShortcutInfos.isEmpty()) { - LauncherModel.deleteItemsFromDatabase(context, removedShortcutInfos); + getModelWriter().deleteItemsFromDatabase(removedShortcutInfos); } if (mUpdateIdMap) { diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java index 25f2f9d50..363f1eeb1 100644 --- a/src/com/android/launcher3/model/UserLockStateChangedTask.java +++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java @@ -95,7 +95,7 @@ public class UserLockStateChangedTask extends ExtendedModelTask { } bindUpdatedShortcuts(updatedShortcutInfos, deletedShortcutInfos, mUser); if (!deletedShortcutInfos.isEmpty()) { - LauncherModel.deleteItemsFromDatabase(context, deletedShortcutInfos); + getModelWriter().deleteItemsFromDatabase(deletedShortcutInfos); } // Remove shortcut id map for that user diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java index af61554d0..577d19f8c 100644 --- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java +++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java @@ -203,7 +203,7 @@ public class ManagedProfileHeuristic { long workFolderId, int startingRank, ArrayList workFolderApps) { for (ItemInfo info : workFolderApps) { info.rank = startingRank++; - LauncherModel.addItemToDatabase(mContext, info, workFolderId, 0, 0, 0); + mModel.getWriter(false).addItemToDatabase(info, workFolderId, 0, 0, 0); } } -- cgit v1.2.3