Implement ability to uninstall shortcuts from workspace

Change-Id: I14ca94ea719825c4de19ab85d67537155098d50c
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index e74dc21..4d66eb3 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -166,7 +166,7 @@
     /**
      * Query the package manager for MAIN/LAUNCHER activities in the supplied package.
      */
-    private static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) {
+    static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) {
         final PackageManager packageManager = context.getPackageManager();
 
         final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
diff --git a/src/com/android/launcher3/ApplicationInfo.java b/src/com/android/launcher3/ApplicationInfo.java
index 53801d6..1bc147a 100644
--- a/src/com/android/launcher3/ApplicationInfo.java
+++ b/src/com/android/launcher3/ApplicationInfo.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageInfo;
 import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.util.Log;
@@ -72,15 +73,9 @@
                 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
 
         try {
-            int appFlags = pm.getApplicationInfo(packageName, 0).flags;
-            if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
-                flags |= DOWNLOADED_FLAG;
-
-                if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
-                    flags |= UPDATED_SYSTEM_APP_FLAG;
-                }
-            }
-            firstInstallTime = pm.getPackageInfo(packageName, 0).firstInstallTime;
+            PackageInfo pi = pm.getPackageInfo(packageName, 0);
+            flags = initFlags(pi);
+            firstInstallTime = initFirstInstallTime(pi);
         } catch (NameNotFoundException e) {
             Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName);
         }
@@ -88,6 +83,23 @@
         iconCache.getTitleAndIcon(this, info, labelCache);
     }
 
+    public static int initFlags(PackageInfo pi) {
+        int appFlags = pi.applicationInfo.flags;
+        int flags = 0;
+        if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
+            flags |= DOWNLOADED_FLAG;
+
+            if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+                flags |= UPDATED_SYSTEM_APP_FLAG;
+            }
+        }
+        return flags;
+    }
+
+    public static long initFirstInstallTime(PackageInfo pi) {
+        return pi.firstInstallTime;
+    }
+
     public ApplicationInfo(ApplicationInfo info) {
         super(info);
         componentName = info.componentName;
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 4be9b81..763ec3f 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -19,7 +19,11 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -27,6 +31,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.TransitionDrawable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
@@ -34,6 +39,8 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.LinearInterpolator;
 
+import java.util.List;
+
 public class DeleteDropTarget extends ButtonDropTarget {
     private static int DELETE_ANIMATION_DURATION = 285;
     private static int FLING_DELETE_ANIMATION_DURATION = 350;
@@ -136,6 +143,12 @@
                     item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
                 return true;
             }
+            if (AppsCustomizePagedView.DISABLE_ALL_APPS &&
+                item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
+                item instanceof ShortcutInfo) {
+                ShortcutInfo shortcutInfo = (ShortcutInfo) info;
+                return (shortcutInfo.flags & ApplicationInfo.DOWNLOADED_FLAG) != 0;
+            }
         }
         return false;
     }
@@ -198,20 +211,22 @@
     }
 
     private void animateToTrashAndCompleteDrop(final DragObject d) {
-        DragLayer dragLayer = mLauncher.getDragLayer();
-        Rect from = new Rect();
+        final DragLayer dragLayer = mLauncher.getDragLayer();
+        final Rect from = new Rect();
         dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-        Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
+        final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
                 mCurrentDrawable.getIntrinsicWidth(), mCurrentDrawable.getIntrinsicHeight());
-        float scale = (float) to.width() / from.width();
+        final float scale = (float) to.width() / from.width();
 
         mSearchDropTargetBar.deferOnDragEnd();
+        deferCompleteDropIfUninstalling(d);
+
         Runnable onAnimationEndRunnable = new Runnable() {
             @Override
             public void run() {
+                completeDrop(d);
                 mSearchDropTargetBar.onDragEnd();
                 mLauncher.exitSpringLoadedDragMode();
-                completeDrop(d);
             }
         };
         dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
@@ -220,12 +235,40 @@
                 DragLayer.ANIMATION_END_DISAPPEAR, null);
     }
 
-    private void completeDrop(DragObject d) {
-        ItemInfo item = (ItemInfo) d.dragInfo;
+    private void deferCompleteDropIfUninstalling(DragObject d) {
+        mWaitingForUninstall = false;
+        if (isUninstall(d)) {
+            if (d.dragSource instanceof Folder) {
+                ((Folder) d.dragSource).deferCompleteDropAfterUninstallActivity();
+            } else if (d.dragSource instanceof Workspace) {
+                ((Workspace) d.dragSource).deferCompleteDropAfterUninstallActivity();
+            }
+            mWaitingForUninstall = true;
+        }
+    }
 
+    private boolean isUninstall(DragObject d) {
+         return AppsCustomizePagedView.DISABLE_ALL_APPS && isWorkspaceOrFolderApplication(d);
+    }
+
+    private boolean mWaitingForUninstall = false;
+    private void completeDrop(final DragObject d) {
+        ItemInfo item = (ItemInfo) d.dragInfo;
+        boolean wasWaitingForUninstall = mWaitingForUninstall;
+        mWaitingForUninstall = false;
         if (isAllAppsApplication(d.dragSource, item)) {
             // Uninstall the application if it is being dragged from AppsCustomize
-            mLauncher.startApplicationUninstallActivity((ApplicationInfo) item);
+            ApplicationInfo appInfo = (ApplicationInfo) item;
+            mLauncher.startApplicationUninstallActivity(appInfo.componentName, appInfo.flags);
+        } else if (AppsCustomizePagedView.DISABLE_ALL_APPS && isWorkspaceOrFolderApplication(d)) {
+            ShortcutInfo shortcut = (ShortcutInfo) item;
+            if (shortcut.intent != null && shortcut.intent.getComponent() != null) {
+                ComponentName componentName = shortcut.intent.getComponent();
+                int flags = ApplicationInfo.initFlags(
+                    ShortcutInfo.getPackageInfo(getContext(), componentName.getPackageName()));
+                mWaitingForUninstall =
+                    mLauncher.startApplicationUninstallActivity(componentName, flags);
+            }
         } else if (isWorkspaceOrFolderApplication(d)) {
             LauncherModel.deleteItemFromDatabase(mLauncher, item);
         } else if (isWorkspaceFolder(d)) {
@@ -250,6 +293,37 @@
                 }.start();
             }
         }
+        if (wasWaitingForUninstall && !mWaitingForUninstall) {
+            if (d.dragSource instanceof Folder) {
+                ((Folder) d.dragSource).onUninstallActivityReturned(false);
+            } else if (d.dragSource instanceof Workspace) {
+                ((Workspace) d.dragSource).onUninstallActivityReturned(false);
+            }
+        }
+        if (mWaitingForUninstall) {
+            final Runnable checkIfUninstallWasSuccess = new Runnable() {
+                    @Override
+                        public void run() {
+                        mWaitingForUninstall = false;
+                        ShortcutInfo shortcut = (ShortcutInfo) d.dragInfo;
+                        if (shortcut.intent != null && shortcut.intent.getComponent() != null) {
+                            String packageName = shortcut.intent.getComponent().getPackageName();
+                            List<ResolveInfo> activities =
+                                AllAppsList.findActivitiesForPackage(getContext(), packageName);
+                            boolean uninstallSuccessful = activities.size() == 0;
+                              mLauncher.removeOnResumeCallback(this);
+                              if (d.dragSource instanceof Folder) {
+                                  ((Folder) d.dragSource).
+                                      onUninstallActivityReturned(uninstallSuccessful);
+                              } else if (d.dragSource instanceof Workspace) {
+                                  ((Workspace) d.dragSource).
+                                      onUninstallActivityReturned(uninstallSuccessful);
+                              }
+                        }
+                    }
+                };
+            mLauncher.addOnResumeCallback(checkIfUninstallWasSuccess);
+        }
     }
 
     public void onDrop(DragObject d) {
@@ -422,6 +496,8 @@
             updateCb = createFlingAlongVectorAnimatorListener(dragLayer, d, vel, startTime,
                     duration, config);
         }
+        deferCompleteDropIfUninstalling(d);
+
         Runnable onAnimationEndRunnable = new Runnable() {
             @Override
             public void run() {
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index c59f34c..d3973f6 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -379,9 +379,11 @@
     void onDeferredEndDrag(DragView dragView) {
         dragView.remove();
 
-        // If we skipped calling onDragEnd() before, do it now
-        for (DragListener listener : mListeners) {
-            listener.onDragEnd();
+        if (mDragObject.deferDragViewCleanupPostAnimation) {
+            // If we skipped calling onDragEnd() before, do it now
+            for (DragListener listener : mListeners) {
+                listener.onDragEnd();
+            }
         }
     }
 
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 4de9297..bb3993e 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -126,6 +126,10 @@
 
     private AutoScroller mAutoScroller;
 
+    private Runnable mDeferredAction;
+    private boolean mDeferDropAfterUninstall;
+    private boolean mUninstallSuccessful;
+
     /**
      * Used to inflate the Workspace from XML.
      *
@@ -743,9 +747,22 @@
         mDragMode = DRAG_MODE_NONE;
     }
 
-    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
-            boolean success) {
-        if (success) {
+    public void onDropCompleted(final View target, final DragObject d,
+            final boolean isFlingToDelete, final boolean success) {
+        if (mDeferDropAfterUninstall) {
+            mDeferredAction = new Runnable() {
+                    public void run() {
+                        onDropCompleted(target, d, isFlingToDelete, success);
+                        mDeferredAction = null;
+                    }
+                };
+            return;
+        }
+
+        boolean beingCalledAfterUninstall = mDeferredAction != null;
+        boolean successfulDrop =
+                success && (!beingCalledAfterUninstall || mUninstallSuccessful);
+        if (successfulDrop) {
             if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon) {
                 replaceFolderWithFinalItem();
             }
@@ -758,7 +775,7 @@
         if (target != this) {
             if (mOnExitAlarm.alarmPending()) {
                 mOnExitAlarm.cancelAlarm();
-                if (!success) {
+                if (successfulDrop) {
                     mSuppressFolderDeletion = true;
                 }
                 completeDragExit();
@@ -776,6 +793,18 @@
         updateItemLocationsInDatabaseBatch();
     }
 
+    public void deferCompleteDropAfterUninstallActivity() {
+        mDeferDropAfterUninstall = true;
+    }
+
+    public void onUninstallActivityReturned(boolean success) {
+        mDeferDropAfterUninstall = false;
+        mUninstallSuccessful = success;
+        if (mDeferredAction != null) {
+            mDeferredAction.run();
+        }
+    }
+
     @Override
     public boolean supportsFlingToDelete() {
         return true;
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 1d7ebba..7ab30a9 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -118,21 +118,6 @@
         LauncherModel.checkItemInfo(this);
     }
 
-    /** Returns the package name that the intent will resolve to, or an empty string if
-     *  none exists. */
-    static String getPackageName(Intent intent) {
-        if (intent != null) {
-            String packageName = intent.getPackage();
-            if (packageName == null && intent.getComponent() != null) {
-                packageName = intent.getComponent().getPackageName();
-            }
-            if (packageName != null) {
-                return packageName;
-            }
-        }
-        return "";
-    }
-
     /**
      * Write the fields of this item to the DB
      * 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index bf9773a..9a7d42e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -255,6 +255,7 @@
     private boolean mWaitingForResult;
     private boolean mOnResumeNeedsLoad;
 
+    private ArrayList<Runnable> mBindOnResumeCallbacks = new ArrayList<Runnable>();
     private ArrayList<Runnable> mOnResumeCallbacks = new ArrayList<Runnable>();
 
     // Keep track of whether the user has left launcher
@@ -770,7 +771,7 @@
             mRestoring = false;
             mOnResumeNeedsLoad = false;
         }
-        if (mOnResumeCallbacks.size() > 0) {
+        if (mBindOnResumeCallbacks.size() > 0) {
             // We might have postponed some bind calls until onResume (see waitUntilResume) --
             // execute them here
             long startTimeCallbacks = 0;
@@ -781,13 +782,13 @@
             if (mAppsCustomizeContent != null) {
                 mAppsCustomizeContent.setBulkBind(true);
             }
-            for (int i = 0; i < mOnResumeCallbacks.size(); i++) {
-                mOnResumeCallbacks.get(i).run();
+            for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) {
+                mBindOnResumeCallbacks.get(i).run();
             }
             if (mAppsCustomizeContent != null) {
                 mAppsCustomizeContent.setBulkBind(false);
             }
-            mOnResumeCallbacks.clear();
+            mBindOnResumeCallbacks.clear();
             if (DEBUG_RESUME_TIME) {
                 Log.d(TAG, "Time spent processing callbacks in onResume: " +
                     (System.currentTimeMillis() - startTimeCallbacks));
@@ -1101,7 +1102,7 @@
         final ShortcutInfo info = mModel.getShortcutInfo(getPackageManager(), data, this);
 
         if (info != null) {
-            info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |
+            info.setActivity(this, data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |
                     Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
             info.container = ItemInfo.NO_ID;
             mWorkspace.addApplicationShortcut(info, layout, container, screenId, cellXY[0], cellXY[1],
@@ -2160,20 +2161,23 @@
         startActivitySafely(null, intent, "startApplicationDetailsActivity");
     }
 
-    void startApplicationUninstallActivity(ApplicationInfo appInfo) {
-        if ((appInfo.flags & ApplicationInfo.DOWNLOADED_FLAG) == 0) {
+    // returns true if the activity was started
+    boolean startApplicationUninstallActivity(ComponentName componentName, int flags) {
+        if ((flags & ApplicationInfo.DOWNLOADED_FLAG) == 0) {
             // System applications cannot be installed. For now, show a toast explaining that.
             // We may give them the option of disabling apps this way.
             int messageId = R.string.uninstall_system_app_text;
             Toast.makeText(this, messageId, Toast.LENGTH_SHORT).show();
+            return false;
         } else {
-            String packageName = appInfo.componentName.getPackageName();
-            String className = appInfo.componentName.getClassName();
+            String packageName = componentName.getPackageName();
+            String className = componentName.getClassName();
             Intent intent = new Intent(
                     Intent.ACTION_DELETE, Uri.fromParts("package", packageName, className));
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                     Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
             startActivity(intent);
+            return true;
         }
     }
 
@@ -3370,10 +3374,10 @@
         if (mPaused) {
             Log.i(TAG, "Deferring update until onResume");
             if (deletePreviousRunnables) {
-                while (mOnResumeCallbacks.remove(run)) {
+                while (mBindOnResumeCallbacks.remove(run)) {
                 }
             }
-            mOnResumeCallbacks.add(run);
+            mBindOnResumeCallbacks.add(run);
             return true;
         } else {
             return false;
@@ -3384,6 +3388,14 @@
         return waitUntilResume(run, false);
     }
 
+    public void addOnResumeCallback(Runnable run) {
+        mBindOnResumeCallbacks.add(run);
+    }
+
+    public void removeOnResumeCallback(Runnable run) {
+        mBindOnResumeCallbacks.remove(run);
+    }
+
     /**
      * If the activity is currently paused, signal that we need to re-run the loader
      * in onResume.
@@ -3428,7 +3440,7 @@
         // If we're starting binding all over again, clear any bind calls we'd postponed in
         // the past (see waitUntilResume) -- we don't need them since we're starting binding
         // from scratch again
-        mOnResumeCallbacks.clear();
+        mBindOnResumeCallbacks.clear();
 
         final Workspace workspace = mWorkspace;
         mNewShortcutAnimateScreenId = -1;
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 07787cc..28530e6 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -2494,6 +2494,7 @@
                 // db and will not appear in the workspace.
                 return null;
             }
+            info.initFlagsAndFirstInstallTime(pi);
         } catch (NameNotFoundException e) {
             Log.d(TAG, "getPackInfo failed for package " + componentName.getPackageName());
         }
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 224b2fc..b6139b7 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -16,14 +16,18 @@
 
 package com.android.launcher3;
 
-import java.util.ArrayList;
-
 import android.content.ComponentName;
 import android.content.ContentValues;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageInfo;
 import android.graphics.Bitmap;
 import android.util.Log;
 
+import java.util.ArrayList;
+
 /**
  * Represents a launchable icon on the workspaces and in folders.
  */
@@ -57,11 +61,14 @@
      */
     private Bitmap mIcon;
 
+    long firstInstallTime;
+    int flags = 0;
+
     ShortcutInfo() {
         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
     }
     
-    public ShortcutInfo(ShortcutInfo info) {
+    public ShortcutInfo(Context context, ShortcutInfo info) {
         super(info);
         title = info.title.toString();
         intent = new Intent(info.intent);
@@ -72,6 +79,7 @@
         }
         mIcon = info.mIcon; // TODO: should make a copy here.  maybe we don't need this ctor at all
         customIcon = info.customIcon;
+        initFlagsAndFirstInstallTime(getPackageInfo(context, intent.getComponent().getPackageName()));
     }
 
     /** TODO: Remove this.  It's only called by ApplicationInfo.makeShortcut. */
@@ -80,6 +88,24 @@
         title = info.title.toString();
         intent = new Intent(info.intent);
         customIcon = false;
+        flags = info.flags;
+        firstInstallTime = info.firstInstallTime;
+    }
+
+    public static PackageInfo getPackageInfo(Context context, String packageName) {
+        PackageInfo pi = null;
+        try {
+            PackageManager pm = context.getPackageManager();
+            pi = pm.getPackageInfo(packageName, 0);
+        } catch (NameNotFoundException e) {
+            Log.d("ShortcutInfo", "PackageManager.getPackageInfo failed for " + packageName);
+        }
+        return pi;
+    }
+
+    void initFlagsAndFirstInstallTime(PackageInfo pi) {
+        flags = ApplicationInfo.initFlags(pi);
+        firstInstallTime = ApplicationInfo.initFirstInstallTime(pi);
     }
 
     public void setIcon(Bitmap b) {
@@ -105,12 +131,13 @@
      * @param className the class name of the component representing the intent
      * @param launchFlags the launch flags
      */
-    final void setActivity(ComponentName className, int launchFlags) {
+    final void setActivity(Context context, ComponentName className, int launchFlags) {
         intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(Intent.CATEGORY_LAUNCHER);
         intent.setComponent(className);
         intent.setFlags(launchFlags);
         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
+        initFlagsAndFirstInstallTime(getPackageInfo(context, intent.getComponent().getPackageName()));
     }
 
     @Override
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7129325..98c6fa3 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -250,6 +250,10 @@
     private int mLastChildCount = -1;
     private float mTransitionProgress;
 
+    private Runnable mDeferredAction;
+    private boolean mDeferDropAfterUninstall;
+    private boolean mUninstallSuccessful;
+
     private final Runnable mBindPages = new Runnable() {
         @Override
         public void run() {
@@ -2305,7 +2309,7 @@
             final View cell = mDragInfo.cell;
 
             Runnable resizeRunnable = null;
-            if (dropTargetLayout != null) {
+            if (dropTargetLayout != null && !d.cancelled) {
                 // Move internally
                 boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);
                 boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
@@ -3411,15 +3415,25 @@
     /**
      * Called at the end of a drag which originated on the workspace.
      */
-    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
-            boolean success) {
-        if (success) {
-            if (target != this) {
-                if (mDragInfo != null) {
-                    getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
-                    if (mDragInfo.cell instanceof DropTarget) {
-                        mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
+    public void onDropCompleted(final View target, final DragObject d,
+            final boolean isFlingToDelete, final boolean success) {
+        if (mDeferDropAfterUninstall) {
+            mDeferredAction = new Runnable() {
+                    public void run() {
+                        onDropCompleted(target, d, isFlingToDelete, success);
+                        mDeferredAction = null;
                     }
+                };
+            return;
+        }
+
+        boolean beingCalledAfterUninstall = mDeferredAction != null;
+
+        if (success && !(beingCalledAfterUninstall && !mUninstallSuccessful)) {
+            if (target != this && mDragInfo != null) {
+                getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
+                if (mDragInfo.cell instanceof DropTarget) {
+                    mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
                 }
                 // If we move the item to anything not on the Workspace, check if any empty
                 // screens need to be removed. If we dropped back on the workspace, this will
@@ -3435,13 +3449,27 @@
             }
             cellLayout.onDropChild(mDragInfo.cell);
         }
-        if (d.cancelled &&  mDragInfo.cell != null) {
-                mDragInfo.cell.setVisibility(VISIBLE);
+        if ((d.cancelled || (beingCalledAfterUninstall && !mUninstallSuccessful))
+                && mDragInfo.cell != null) {
+            mDragInfo.cell.setVisibility(VISIBLE);
         }
         mDragOutline = null;
         mDragInfo = null;
     }
 
+    public void deferCompleteDropAfterUninstallActivity() {
+        mDeferDropAfterUninstall = true;
+    }
+
+    /// maybe move this into a smaller part
+    public void onUninstallActivityReturned(boolean success) {
+        mDeferDropAfterUninstall = false;
+        mUninstallSuccessful = success;
+        if (mDeferredAction != null) {
+            mDeferredAction.run();
+        }
+    }
+
     void updateItemLocationsInDatabase(CellLayout cl) {
         int count = cl.getShortcutsAndWidgets().getChildCount();