merge in ics-release history after reset to master
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3934237..a516424 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -83,10 +83,10 @@
     <dimen name="dragViewOffsetY">-8dp</dimen>
 
     <!-- Padding applied to AppWidgets -->
-    <dimen name="app_widget_padding_left">0dp</dimen>
-    <dimen name="app_widget_padding_right">0dp</dimen>
-    <dimen name="app_widget_padding_top">0dp</dimen>
-    <dimen name="app_widget_padding_bottom">0dp</dimen>
+    <dimen name="app_widget_padding_left">3dp</dimen>
+    <dimen name="app_widget_padding_right">3dp</dimen>
+    <dimen name="app_widget_padding_top">1dp</dimen>
+    <dimen name="app_widget_padding_bottom">1dp</dimen>
 
 <!-- Folders -->
     <!-- The size of the image which sits behind the preview of the folder contents -->
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 8158624..949d872 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -164,6 +164,10 @@
     private final LayoutInflater mLayoutInflater;
     private final PackageManager mPackageManager;
 
+    // Save and Restore
+    private int mSaveInstanceStateItemIndex = -1;
+    private int mRestorePage = -1;
+
     // Content
     private ContentType mContentType;
     private ArrayList<ApplicationInfo> mApps;
@@ -253,6 +257,58 @@
         }
     }
 
+    /** Returns the item index of the center item on this page so that we can restore to this
+     *  item index when we rotate. */
+    private int getMiddleComponentIndexOnCurrentPage() {
+        int i = -1;
+        if (getPageCount() > 0) {
+            int currentPage = getCurrentPage();
+            switch (mContentType) {
+            case Applications: {
+                PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(currentPage);
+                PagedViewCellLayoutChildren childrenLayout = layout.getChildrenLayout();
+                int numItemsPerPage = mCellCountX * mCellCountY;
+                int childCount = childrenLayout.getChildCount();
+                if (childCount > 0) {
+                    i = (currentPage * numItemsPerPage) + (childCount / 2);
+                }}
+                break;
+            case Widgets: {
+                PagedViewGridLayout layout = (PagedViewGridLayout) getChildAt(currentPage);
+                int numItemsPerPage = mWidgetCountX * mWidgetCountY;
+                int childCount = layout.getChildCount();
+                if (childCount > 0) {
+                    i = (currentPage * numItemsPerPage) + (childCount / 2);
+                }}
+                break;
+            }
+        }
+        return i;
+    }
+
+    /** Get the index of the item to restore to if we need to restore the current page. */
+    int getSaveInstanceStateIndex() {
+        if (mSaveInstanceStateItemIndex == -1) {
+            mSaveInstanceStateItemIndex = getMiddleComponentIndexOnCurrentPage();
+        }
+        return mSaveInstanceStateItemIndex;
+    }
+
+    /** Returns the page in the current orientation which is expected to contain the specified
+     *  item index. */
+    int getPageForComponent(int index) {
+        switch (mContentType) {
+        case Applications: {
+            int numItemsPerPage = mCellCountX * mCellCountY;
+            return (index / numItemsPerPage);
+        }
+        case Widgets: {
+            int numItemsPerPage = mWidgetCountX * mWidgetCountY;
+            return (index / numItemsPerPage);
+        }}
+        return -1;
+    }
+
     /**
      * This differs from isDataReady as this is the test done if isDataReady is not set.
      */
@@ -262,6 +318,20 @@
         return !mApps.isEmpty();
     }
 
+    /** Restores the page for an item at the specified index */
+    void restorePageForIndex(int index) {
+        if (index < 0) return;
+
+        int page = getPageForComponent(index);
+        if (page > -1) {
+            if (getChildCount() > 0) {
+                invalidatePageData(page);
+            } else {
+                mRestorePage = page;
+            }
+        }
+    }
+
     protected void onDataReady(int width, int height) {
         // Note that we transpose the counts in portrait so that we get a similar layout
         boolean isLandscape = getResources().getConfiguration().orientation ==
@@ -289,7 +359,8 @@
         int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
         mWidgetSpacingLayout.measure(widthSpec, heightSpec);
         mContentWidth = mWidgetSpacingLayout.getContentWidth();
-        invalidatePageData();
+        invalidatePageData(Math.max(0, mRestorePage));
+        mRestorePage = -1;
     }
 
     @Override
@@ -1076,6 +1147,10 @@
         setChildrenDrawnWithCacheEnabled(false);
         */
         super.onPageEndMoving();
+
+        // We reset the save index when we change pages so that it will be recalculated on next
+        // rotation
+        mSaveInstanceStateItemIndex = -1;
     }
 
     /*
diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java
index b2ebe2a..7f3ae86 100644
--- a/src/com/android/launcher2/IconCache.java
+++ b/src/com/android/launcher2/IconCache.java
@@ -160,13 +160,14 @@
         }
     }
 
-    public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo) {
+    public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo,
+            HashMap<Object, CharSequence> labelCache) {
         synchronized (mCache) {
             if (resolveInfo == null || component == null) {
                 return null;
             }
 
-            CacheEntry entry = cacheLocked(component, resolveInfo, null);
+            CacheEntry entry = cacheLocked(component, resolveInfo, labelCache);
             return entry.icon;
         }
     }
@@ -183,12 +184,13 @@
 
             mCache.put(componentName, entry);
 
-            if (labelCache != null && labelCache.containsKey(info)) {
-                entry.title = labelCache.get(info).toString();
+            ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info);
+            if (labelCache != null && labelCache.containsKey(key)) {
+                entry.title = labelCache.get(key).toString();
             } else {
                 entry.title = info.loadLabel(mPackageManager).toString();
                 if (labelCache != null) {
-                    labelCache.put(info, entry.title);
+                    labelCache.put(key, entry.title);
                 }
             }
             if (entry.title == null) {
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index dc0120b..a0601e0 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -673,8 +673,8 @@
                         mAppsCustomizeContent.getCurrentPage());
             }
 
-            // Note: currently we do not restore the page for the AppsCustomize pane because the
-            // change in layout can drastically affect the saved page index
+            int currentIndex = savedState.getInt("apps_customize_currentIndex");
+            mAppsCustomizeContent.restorePageForIndex(currentIndex);
         }
     }
 
@@ -1145,6 +1145,8 @@
             if (currentTabTag != null) {
                 outState.putString("apps_customize_currentTab", currentTabTag);
             }
+            int currentIndex = mAppsCustomizeContent.getSaveInstanceStateIndex();
+            outState.putInt("apps_customize_currentIndex", currentIndex);
         }
     }
 
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index c46e175..f14140c 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -661,11 +661,13 @@
         private boolean mStopped;
         private boolean mLoadAndBindStepFinished;
         private HashMap<Object, CharSequence> mLabelCache;
+        private HashMap<Object, byte[]> mDbIconCache;
 
         LoaderTask(Context context, boolean isLaunching) {
             mContext = context;
             mIsLaunching = isLaunching;
             mLabelCache = new HashMap<Object, CharSequence>();
+            mDbIconCache = new HashMap<Object, byte[]>();
         }
 
         boolean isLaunching() {
@@ -731,10 +733,15 @@
             final Callbacks cbk = mCallbacks.get();
             final boolean loadWorkspaceFirst = cbk != null ? (!cbk.isAllAppsVisible()) : true;
 
+            // We update the icons in the database afterwards in case they have changed
+            mDbIconCache.clear();
+
             keep_running: {
                 // Elevate priority when Home launches for the first time to avoid
                 // starving at boot time. Staring at a blank home is not cool.
                 synchronized (mLock) {
+                    if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +
+                            (mIsLaunching ? "DEFAULT" : "BACKGROUND"));
                     android.os.Process.setThreadPriority(mIsLaunching
                             ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
                 }
@@ -754,6 +761,7 @@
                 // settled down.
                 synchronized (mLock) {
                     if (mIsLaunching) {
+                        if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");
                         android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                     }
                 }
@@ -769,6 +777,14 @@
                 }
             }
 
+
+            // Update the saved icons if necessary
+            if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");
+            for (Object key : mDbIconCache.keySet()) {
+                updateSavedIcon(mContext, (ShortcutInfo) key, mDbIconCache.get(key));
+            }
+            mDbIconCache.clear();
+
             // Clear out this reference, otherwise we end up holding it until all of the
             // callback runnables are done.
             mContext = null;
@@ -970,7 +986,7 @@
 
                                 // now that we've loaded everthing re-save it with the
                                 // icon in case it disappears somehow.
-                                updateSavedIcon(context, info, c, iconIndex);
+                                queueIconToBeChecked(mDbIconCache, info, c, iconIndex);
                             } else {
                                 // Failed to load the shortcut, probably because the
                                 // activity manager couldn't resolve it (maybe the app
@@ -1522,7 +1538,7 @@
         // have icons anyway.
         final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0);
         if (resolveInfo != null) {
-            icon = mIconCache.getIcon(componentName, resolveInfo);
+            icon = mIconCache.getIcon(componentName, resolveInfo, labelCache);
         }
         // the db
         if (icon == null) {
@@ -1539,12 +1555,13 @@
 
         // from the resource
         if (resolveInfo != null) {
-            if (labelCache != null && labelCache.containsKey(resolveInfo)) {
-                info.title = labelCache.get(resolveInfo);
+            ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo);
+            if (labelCache != null && labelCache.containsKey(key)) {
+                info.title = labelCache.get(key);
             } else {
                 info.title = resolveInfo.activityInfo.loadLabel(manager);
                 if (labelCache != null) {
-                    labelCache.put(resolveInfo, info.title);
+                    labelCache.put(key, info.title);
                 }
             }
         }
@@ -1749,10 +1766,11 @@
         return info;
     }
 
-    void updateSavedIcon(Context context, ShortcutInfo info, Cursor c, int iconIndex) {
+    boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,
+            int iconIndex) {
         // If apps can't be on SD, don't even bother.
         if (!mAppsCanBeOnExternalStorage) {
-            return;
+            return false;
         }
         // If this icon doesn't have a custom icon, check to see
         // what's stored in the DB, and if it doesn't match what
@@ -1761,25 +1779,29 @@
         // package manager can't find an icon (for example because
         // the app is on SD) then we can use that instead.
         if (!info.customIcon && !info.usingFallbackIcon) {
-            boolean needSave;
-            byte[] data = c.getBlob(iconIndex);
-            try {
-                if (data != null) {
-                    Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);
-                    Bitmap loaded = info.getIcon(mIconCache);
-                    needSave = !saved.sameAs(loaded);
-                } else {
-                    needSave = true;
-                }
-            } catch (Exception e) {
+            cache.put(info, c.getBlob(iconIndex));
+            return true;
+        }
+        return false;
+    }
+    void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {
+        boolean needSave = false;
+        try {
+            if (data != null) {
+                Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);
+                Bitmap loaded = info.getIcon(mIconCache);
+                needSave = !saved.sameAs(loaded);
+            } else {
                 needSave = true;
             }
-            if (needSave) {
-                Log.d(TAG, "going to save icon bitmap for info=" + info);
-                // This is slower than is ideal, but this only happens once
-                // or when the app is updated with a new icon.
-                updateItemInDatabase(context, info);
-            }
+        } catch (Exception e) {
+            needSave = true;
+        }
+        if (needSave) {
+            Log.d(TAG, "going to save icon bitmap for info=" + info);
+            // This is slower than is ideal, but this only happens once
+            // or when the app is updated with a new icon.
+            updateItemInDatabase(context, info);
         }
     }
 
@@ -1823,6 +1845,13 @@
             return sCollator.compare(a.label.toString(), b.label.toString());
         }
     };
+    static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {
+        if (info.activityInfo != null) {
+            return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
+        } else {
+            return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
+        }
+    }
     public static class ShortcutNameComparator implements Comparator<ResolveInfo> {
         private PackageManager mPackageManager;
         private HashMap<Object, CharSequence> mLabelCache;
@@ -1836,19 +1865,21 @@
         }
         public final int compare(ResolveInfo a, ResolveInfo b) {
             CharSequence labelA, labelB;
-            if (mLabelCache.containsKey(a)) {
-                labelA = mLabelCache.get(a);
+            ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a);
+            ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b);
+            if (mLabelCache.containsKey(keyA)) {
+                labelA = mLabelCache.get(keyA);
             } else {
                 labelA = a.loadLabel(mPackageManager).toString();
 
-                mLabelCache.put(a, labelA);
+                mLabelCache.put(keyA, labelA);
             }
-            if (mLabelCache.containsKey(b)) {
-                labelB = mLabelCache.get(b);
+            if (mLabelCache.containsKey(keyB)) {
+                labelB = mLabelCache.get(keyB);
             } else {
                 labelB = b.loadLabel(mPackageManager).toString();
 
-                mLabelCache.put(b, labelB);
+                mLabelCache.put(keyB, labelB);
             }
             return sCollator.compare(labelA, labelB);
         }
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 6e26363..40e2328 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -1649,7 +1649,7 @@
 
             // Set a new page as the current page if necessary
             if (currentPage > -1) {
-                setCurrentPage(currentPage);
+                setCurrentPage(Math.min(getPageCount() - 1, currentPage));
             }
 
             // Mark each of the pages as dirty
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
index 63cf9e8..803e700 100644
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -192,6 +192,10 @@
         return mChildren.getChildCount();
     }
 
+    public PagedViewCellLayoutChildren getChildrenLayout() {
+        return mChildren;
+    }
+
     @Override
     public View getChildOnPageAt(int i) {
         return mChildren.getChildAt(i);