diff options
Diffstat (limited to 'src/com/android/launcher3/model/ModelWriter.java')
-rw-r--r-- | src/com/android/launcher3/model/ModelWriter.java | 74 |
1 files changed, 69 insertions, 5 deletions
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java index eba751524..9f6e4f85d 100644 --- a/src/com/android/launcher3/model/ModelWriter.java +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -28,6 +28,8 @@ import android.util.Log; import com.android.launcher3.FolderInfo; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetHost; +import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherModel.Callbacks; import com.android.launcher3.LauncherProvider; @@ -35,13 +37,14 @@ 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.logging.FileLog; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.LooperExecutor; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.concurrent.Executor; /** @@ -60,6 +63,10 @@ public class ModelWriter { private final boolean mHasVerticalHotseat; private final boolean mVerifyChanges; + // Keep track of delete operations that occur when an Undo option is present; we may not commit. + private final List<Runnable> mDeleteRunnables = new ArrayList<>(); + private boolean mPreparingToUndo; + public ModelWriter(Context context, LauncherModel model, BgDataModel dataModel, boolean hasVerticalHotseat, boolean verifyChanges) { mContext = context; @@ -152,7 +159,7 @@ public class ModelWriter { .put(Favorites.RANK, item.rank) .put(Favorites.SCREEN, item.screenId); - mWorkerExecutor.execute(new UpdateItemRunnable(item, writer)); + enqueueDeleteRunnable(new UpdateItemRunnable(item, writer)); } /** @@ -176,7 +183,7 @@ public class ModelWriter { contentValues.add(values); } - mWorkerExecutor.execute(new UpdateItemsRunnable(items, contentValues)); + enqueueDeleteRunnable(new UpdateItemsRunnable(items, contentValues)); } /** @@ -258,7 +265,7 @@ public class ModelWriter { public void deleteItemsFromDatabase(final Iterable<? extends ItemInfo> items) { ModelVerifier verifier = new ModelVerifier(); - mWorkerExecutor.execute(() -> { + enqueueDeleteRunnable(() -> { for (ItemInfo item : items) { final Uri uri = Favorites.getContentUri(item.id); mContext.getContentResolver().delete(uri, null, null); @@ -275,7 +282,7 @@ public class ModelWriter { public void deleteFolderAndContentsFromDatabase(final FolderInfo info) { ModelVerifier verifier = new ModelVerifier(); - mWorkerExecutor.execute(() -> { + enqueueDeleteRunnable(() -> { ContentResolver cr = mContext.getContentResolver(); cr.delete(LauncherSettings.Favorites.CONTENT_URI, LauncherSettings.Favorites.CONTAINER + "=" + info.id, null); @@ -288,6 +295,63 @@ public class ModelWriter { }); } + /** + * Deletes the widget info and the widget id. + */ + public void deleteWidgetInfo(final LauncherAppWidgetInfo info, LauncherAppWidgetHost host) { + if (host != null && !info.isCustomWidget() && info.isWidgetIdAllocated()) { + // Deleting an app widget ID is a void call but writes to disk before returning + // to the caller... + enqueueDeleteRunnable(() -> host.deleteAppWidgetId(info.appWidgetId)); + } + deleteItemFromDatabase(info); + } + + /** + * Delete operations tracked using {@link #enqueueDeleteRunnable} will only be called + * if {@link #commitDelete} is called. Note that one of {@link #commitDelete()} or + * {@link #abortDelete()} MUST be called after this method, or else all delete + * operations will remain uncommitted indefinitely. + */ + public void prepareToUndoDelete() { + if (!mPreparingToUndo) { + if (!mDeleteRunnables.isEmpty() && FeatureFlags.IS_DOGFOOD_BUILD) { + throw new IllegalStateException("There are still uncommitted delete operations!"); + } + mDeleteRunnables.clear(); + mPreparingToUndo = true; + } + } + + /** + * If {@link #prepareToUndoDelete} has been called, we store the Runnable to be run when + * {@link #commitDelete()} is called (or abandoned if {@link #abortDelete()} is called). + * Otherwise, we run the Runnable immediately. + */ + public void enqueueDeleteRunnable(Runnable r) { + if (mPreparingToUndo) { + mDeleteRunnables.add(r); + } else { + mWorkerExecutor.execute(r); + } + } + + public void commitDelete() { + mPreparingToUndo = false; + for (Runnable runnable : mDeleteRunnables) { + mWorkerExecutor.execute(runnable); + } + mDeleteRunnables.clear(); + } + + public void abortDelete() { + mPreparingToUndo = false; + mDeleteRunnables.clear(); + // We do a full reload here instead of just a rebind because Folders change their internal + // state when dragging an item out, which clobbers the rebind unless we load from the DB. + mModel.forceReload(); + } + private class UpdateItemRunnable extends UpdateItemBaseRunnable { private final ItemInfo mItem; private final ContentWriter mWriter; |