update placeholder on package install or restore

Bug: 10778992
Change-Id: I3293d8bab8ae0ef49fc5554531bba5bd6f70932c
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index d5a7769..da222f1 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -64,6 +64,10 @@
         return intent;
     }
 
+    protected Intent getRestoredIntent() {
+        return null;
+    }
+
     /**
      * Must not hold the Context.
      */
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 36ba6c1..3dc92c9 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -122,6 +122,10 @@
         throw new RuntimeException("Unexpected Intent");
     }
 
+    protected Intent getRestoredIntent() {
+        throw new RuntimeException("Unexpected Intent");
+    }
+
     /**
      * Write the fields of this item to the DB
      * 
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 094d4b7..ff8a356 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -302,6 +302,15 @@
             return;
         }
 
+        final ArrayList<AppInfo> restoredAppsFinal = new ArrayList<AppInfo>();
+        Iterator<AppInfo> iter = allAppsApps.iterator();
+        while (iter.hasNext()) {
+            ItemInfo a = iter.next();
+            if (LauncherModel.appWasRestored(ctx, a.getIntent())) {
+                restoredAppsFinal.add((AppInfo) a);
+            }
+        }
+
         // Process the newly added applications and add them to the database first
         Runnable r = new Runnable() {
             public void run() {
@@ -310,6 +319,9 @@
                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
                         if (callbacks == cb && cb != null) {
                             callbacks.bindAppsAdded(null, null, null, allAppsApps);
+                            if (!restoredAppsFinal.isEmpty()) {
+                                callbacks.bindAppsUpdated(restoredAppsFinal);
+                            }
                         }
                     }
                 });
@@ -333,6 +345,7 @@
             public void run() {
                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();
                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();
+                final ArrayList<AppInfo> restoredAppsFinal = new ArrayList<AppInfo>();
 
                 // Get the list of workspace screens.  We need to append to this list and
                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been
@@ -353,6 +366,11 @@
 
                         // Short-circuit this logic if the icon exists somewhere on the workspace
                         if (LauncherModel.shortcutExists(context, name, launchIntent)) {
+                            // Only InstallShortcutReceiver sends us shortcutInfos, ignore them
+                            if (a instanceof AppInfo &&
+                                    LauncherModel.appWasRestored(context, launchIntent)) {
+                                restoredAppsFinal.add((AppInfo) a);
+                            }
                             continue;
                         }
 
@@ -428,6 +446,9 @@
                                 }
                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,
                                         addNotAnimated, addAnimated, null);
+                                if (!restoredAppsFinal.isEmpty()) {
+                                    callbacks.bindAppsUpdated(restoredAppsFinal);
+                                }
                             }
                         }
                     });
@@ -793,6 +814,30 @@
     }
 
     /**
+     * Returns true if the shortcuts already exists in the database.
+     * we identify a shortcut by the component name of the intent.
+     */
+    static boolean appWasRestored(Context context, Intent intent) {
+        final ContentResolver cr = context.getContentResolver();
+        final ComponentName component = intent.getComponent();
+        if (component == null) {
+            return false;
+        }
+        String componentName = component.flattenToString();
+        final String where = "intent glob \"*component=" + componentName + "*\" and restored = 1";
+        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
+                new String[]{"intent", "restored"}, where, null, null);
+        boolean result = false;
+        try {
+            result = c.moveToFirst();
+        } finally {
+            c.close();
+        }
+        Log.d(TAG, "shortcutWasRestored is " + result + " for " + componentName);
+        return result;
+    }
+
+    /**
      * Returns an ItemInfo array containing all the items in the LauncherModel.
      * The ItemInfo.id is not set through this function.
      */
@@ -1839,7 +1884,7 @@
                                     Launcher.addDumpLog(TAG,
                                             "constructing info for partially restored package",
                                             true);
-                                    info = getRestoredItemInfo(c, titleIndex);
+                                    info = getRestoredItemInfo(c, titleIndex, intent);
                                     intent = getRestoredItemIntent(c, context, intent);
                                 } else if (itemType ==
                                         LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
@@ -2810,7 +2855,7 @@
      * Make an ShortcutInfo object for a restored application or shortcut item that points
      * to a package that is not yet installed on the system.
      */
-    public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex) {
+    public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) {
         final ShortcutInfo info = new ShortcutInfo();
         info.usingFallbackIcon = true;
         info.setIcon(getFallbackIcon());
@@ -2820,6 +2865,7 @@
             info.title = "";
         }
         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+        info.restoredIntent = intent;
         return info;
     }
 
@@ -2828,6 +2874,7 @@
      * to the market page for the item.
      */
     private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {
+        final boolean debug = false;
         ComponentName componentName = intent.getComponent();
         Intent marketIntent = new Intent(Intent.ACTION_VIEW);
         Uri marketUri = new Uri.Builder()
@@ -2835,7 +2882,7 @@
                 .authority("details")
                 .appendQueryParameter("id", componentName.getPackageName())
                 .build();
-        Log.d(TAG, "manufactured intent uri: " + marketUri.toString());
+        if (debug) Log.d(TAG, "manufactured intent uri: " + marketUri.toString());
         marketIntent.setData(marketUri);
         return marketIntent;
     }
@@ -3001,6 +3048,10 @@
                     Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
                 return true;
             }
+            // placeholder shortcuts get special treatment, let them through too.
+            if (info.getRestoredIntent() != null) {
+                return true;
+            }
         }
         return false;
     }
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 660f32c..79d114c 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -64,6 +64,12 @@
     long firstInstallTime;
     int flags = 0;
 
+    /**
+     * If this shortcut is a placeholder, then intent will be a market intent for the package, and
+     * this will hold the original intent from the database.  Otherwise, null.
+     */
+    Intent restoredIntent;
+
     ShortcutInfo() {
         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
     }
@@ -72,6 +78,21 @@
         return intent;
     }
 
+    protected Intent getRestoredIntent() {
+        return restoredIntent;
+    }
+
+    /**
+     * Overwrite placeholder data with restored data, or do nothing if this is not a placeholder.
+     */
+    public void restore() {
+        if (restoredIntent != null) {
+            intent = restoredIntent;
+            restoredIntent = null;
+        }
+    }
+
+
     ShortcutInfo(Intent intent, CharSequence title, Bitmap icon) {
         this();
         this.intent = intent;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 751b4c6..0a7088d 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -4612,11 +4612,15 @@
     private void updateShortcut(HashMap<ComponentName, AppInfo> appsMap, ItemInfo info,
                                 View child) {
         ComponentName cn = info.getIntent().getComponent();
+        if (info.getRestoredIntent() != null) {
+            cn = info.getRestoredIntent().getComponent();
+        }
         if (cn != null) {
-            AppInfo appInfo = appsMap.get(info.getIntent().getComponent());
+            AppInfo appInfo = appsMap.get(cn);
             if ((appInfo != null) && LauncherModel.isShortcutInfoUpdateable(info)) {
                 ShortcutInfo shortcutInfo = (ShortcutInfo) info;
                 BubbleTextView shortcut = (BubbleTextView) child;
+                shortcutInfo.restore();
                 shortcutInfo.updateIcon(mIconCache);
                 shortcutInfo.title = appInfo.title.toString();
                 shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache);