Refactoring to ensure item deletion always removes from the DB.
- Routing the various places where we call through to delete from
LauncherModel through Launcher, which will delegate the removal
of the icon from the workspace, and properly handle the removal
of all items and their contents from the db.
Bug: 23944119
Change-Id: I022fe2b3e79da16b5af87505c4362490b8422686
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 9c8659c..163ffb6 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -70,40 +70,9 @@
* @return true if the item was removed.
*/
public static boolean removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view) {
- if (item instanceof ShortcutInfo) {
- LauncherModel.deleteItemFromDatabase(launcher, item);
- } else if (item instanceof FolderInfo) {
- FolderInfo folder = (FolderInfo) item;
- launcher.removeFolder(folder);
- LauncherModel.deleteFolderContentsFromDatabase(launcher, folder);
- } else if (item instanceof LauncherAppWidgetInfo) {
- final LauncherAppWidgetInfo widget = (LauncherAppWidgetInfo) item;
-
- // Remove the widget from the workspace
- launcher.removeAppWidget(widget);
- LauncherModel.deleteItemFromDatabase(launcher, widget);
-
- final LauncherAppWidgetHost appWidgetHost = launcher.getAppWidgetHost();
-
- if (appWidgetHost != null && !widget.isCustomWidget()
- && widget.isWidgetIdValid()) {
- // Deleting an app widget ID is a void call but writes to disk before returning
- // to the caller...
- new AsyncTask<Void, Void, Void>() {
- public Void doInBackground(Void ... args) {
- appWidgetHost.deleteAppWidgetId(widget.appWidgetId);
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- } else {
- return false;
- }
-
- if (view != null) {
- launcher.getWorkspace().removeWorkspaceItem(view);
- launcher.getWorkspace().stripEmptyScreens();
- }
+ // Remove the item from launcher and the db
+ launcher.removeItem(view, item, true /* deleteFromDb */);
+ launcher.getWorkspace().stripEmptyScreens();
return true;
}
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index 57aec32..eca5eec 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -185,7 +185,8 @@
return consume;
}
- DeviceProfile profile = ((Launcher) v.getContext()).getDeviceProfile();
+ final Launcher launcher = (Launcher) v.getContext();
+ final DeviceProfile profile = launcher.getDeviceProfile();
if (DEBUG) {
Log.v(TAG, String.format(
@@ -196,7 +197,6 @@
// Initialize the variables.
final ShortcutAndWidgetContainer hotseatParent = (ShortcutAndWidgetContainer) v.getParent();
final CellLayout hotseatLayout = (CellLayout) hotseatParent.getParent();
- Hotseat hotseat = (Hotseat) hotseatLayout.getParent();
Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace);
int pageIndex = workspace.getNextPage();
@@ -240,7 +240,10 @@
} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
profile.isVerticalBarLayout()) {
keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
- }else {
+ } else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
+ ItemInfo info = (ItemInfo) v.getTag();
+ launcher.removeItem(v, info, true /* deleteFromDb */);
+ } else {
// For other KEYCODE_DPAD_LEFT and KEYCODE_DPAD_RIGHT navigation, do not use the
// matrix extended with hotseat.
matrix = FocusLogic.createSparseMatrix(hotseatLayout);
@@ -326,7 +329,8 @@
!hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */);
countX = countX + 1;
} else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
- workspace.removeWorkspaceItem(v);
+ ItemInfo info = (ItemInfo) v.getTag();
+ launcher.removeItem(v, info, true /* deleteFromDb */);
return consume;
} else {
matrix = FocusLogic.createSparseMatrix(iconLayout);
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index c1aa356..f59c87e 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -1122,16 +1122,10 @@
mInfo.screenId, mInfo.cellX, mInfo.cellY);
}
if (getItemCount() <= 1) {
- // Remove the folder
- LauncherModel.deleteItemFromDatabase(mLauncher, mInfo);
- if (cellLayout != null) {
- // b/12446428 -- sometimes the cell layout has already gone away?
- cellLayout.removeView(mFolderIcon);
- }
+ mLauncher.removeItem(mFolderIcon, mInfo, true /* deleteFromDb */);
if (mFolderIcon instanceof DropTarget) {
mDragController.removeDropTarget((DropTarget) mFolderIcon);
}
- mLauncher.removeFolder(mInfo);
}
// We add the child after removing the folder to prevent both from existing at
// the same time in the CellLayout. We need to add the new item with addInScreenFromBind()
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c017dc0..65aa68a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1787,7 +1787,7 @@
}
});
- void addWidgetToAutoAdvanceIfNeeded(View hostView, AppWidgetProviderInfo appWidgetInfo) {
+ private void addWidgetToAutoAdvanceIfNeeded(View hostView, AppWidgetProviderInfo appWidgetInfo) {
if (appWidgetInfo == null || appWidgetInfo.autoAdvanceViewId == -1) return;
View v = hostView.findViewById(appWidgetInfo.autoAdvanceViewId);
if (v instanceof Advanceable) {
@@ -1797,18 +1797,13 @@
}
}
- void removeWidgetToAutoAdvance(View hostView) {
+ private void removeWidgetToAutoAdvance(View hostView) {
if (mWidgetsToAdvance.containsKey(hostView)) {
mWidgetsToAdvance.remove(hostView);
updateAutoAdvanceState();
}
}
- public void removeAppWidget(LauncherAppWidgetInfo launcherInfo) {
- removeWidgetToAutoAdvance(launcherInfo.hostView);
- launcherInfo.hostView = null;
- }
-
public void showOutOfSpaceMessage(boolean isHotseatLayout) {
int strId = (isHotseatLayout ? R.string.hotseat_out_of_space : R.string.out_of_space);
Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show();
@@ -2394,10 +2389,63 @@
return newFolder;
}
- void removeFolder(FolderInfo folder) {
+ /**
+ * Unbinds the view for the specified item, and removes the item and all its children items
+ * from the database. For folders, this incl udes the folder contents. AppWidgets will also
+ * have their widget ids deleted.
+ */
+ public boolean removeItem(View v, ItemInfo itemInfo, boolean deleteFromDb) {
+ if (itemInfo instanceof ShortcutInfo) {
+ mWorkspace.removeWorkspaceItem(v);
+ if (deleteFromDb) {
+ LauncherModel.deleteItemFromDatabase(this, itemInfo);
+ }
+ } else if (itemInfo instanceof FolderInfo) {
+ final FolderInfo folderInfo = (FolderInfo) itemInfo;
+ unbindFolder(folderInfo);
+ mWorkspace.removeWorkspaceItem(v);
+ if (deleteFromDb) {
+ LauncherModel.deleteFolderAndContentsFromDatabase(this, folderInfo);
+ }
+ } else if (itemInfo instanceof LauncherAppWidgetInfo) {
+ final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo;
+ unbindAppWidget(widgetInfo, deleteFromDb);
+ if (deleteFromDb) {
+ LauncherModel.deleteItemFromDatabase(this, widgetInfo);
+ }
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Unbinds any launcher references to the folder.
+ */
+ private void unbindFolder(FolderInfo folder) {
sFolders.remove(folder.id);
}
+ /**
+ * Unbinds any launcher references to the widget and deletes the app widget id.
+ */
+ private void unbindAppWidget(final LauncherAppWidgetInfo widgetInfo, boolean deleteAppWidgetId) {
+ final LauncherAppWidgetHost appWidgetHost = getAppWidgetHost();
+ if (deleteAppWidgetId && appWidgetHost != null &&
+ !widgetInfo.isCustomWidget() && widgetInfo.isWidgetIdValid()) {
+ // Deleting an app widget ID is a void call but writes to disk before returning
+ // to the caller...
+ new AsyncTask<Void, Void, Void>() {
+ public Void doInBackground(Void ... args) {
+ appWidgetHost.deleteAppWidgetId(widgetInfo.appWidgetId);
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ removeWidgetToAutoAdvance(widgetInfo.hostView);
+ widgetInfo.hostView = null;
+ }
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index b5922c6..ee5f9ca 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -1068,8 +1068,6 @@
/**
* Removes the specified item from the database
- * @param context
- * @param item
*/
public static void deleteItemFromDatabase(Context context, final ItemInfo item) {
ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
@@ -1079,8 +1077,6 @@
/**
* Removes the specified items from the database
- * @param context
- * @param item
*/
static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {
final ContentResolver cr = context.getContentResolver();
@@ -1171,9 +1167,9 @@
}
/**
- * Remove the contents of the specified folder from the database
+ * Remove the specified folder and all its contents from the database.
*/
- public static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {
+ public static void deleteFolderAndContentsFromDatabase(Context context, final FolderInfo info) {
final ContentResolver cr = context.getContentResolver();
Runnable r = new Runnable() {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 856e3b8..dc73635 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1118,9 +1118,9 @@
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;
if (lahv != null && lahv.isReinflateRequired()) {
- mLauncher.removeAppWidget(info);
- // Remove the current widget which is inflated with the wrong orientation
- cl.removeView(lahv);
+ // Remove and rebind the current widget (which was inflated in the wrong
+ // orientation), but don't delete it from the database
+ mLauncher.removeItem(lahv, info, false /* deleteFromDb */);
mLauncher.bindAppWidget(info);
}
}
@@ -4519,12 +4519,9 @@
for (LauncherAppWidgetInfo info : mInfos) {
if (info.hostView instanceof PendingAppWidgetHostView) {
+ // Remove and rebind the current widget, but don't delete it from the database
PendingAppWidgetHostView view = (PendingAppWidgetHostView) info.hostView;
- mLauncher.removeAppWidget(info);
-
- CellLayout cl = (CellLayout) view.getParent().getParent();
- // Remove the current widget
- cl.removeView(view);
+ mLauncher.removeItem(view, info, false /* deleteFromDb */);
mLauncher.bindAppWidget(info);
}
}