Merge branch 'froyo' into froyo-release
diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java
index 90c87fb..eb7cd83 100644
--- a/src/com/android/launcher2/AllApps2D.java
+++ b/src/com/android/launcher2/AllApps2D.java
@@ -50,6 +50,8 @@
 
     private static final String TAG = "Launcher.AllApps2D";
 
+    private static final int BATCH_SIZE = 6; // give us a few apps at a time
+
     private Launcher mLauncher;
     private DragController mDragController;
 
@@ -300,6 +302,10 @@
         return -1;
     }
 
+    public int getAppBatchSize() {
+        return BATCH_SIZE;
+    }
+
     public void dumpState() {
         ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList", mAllAppsList);
     }
diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java
index 35e4cfc..64c8c4c 100644
--- a/src/com/android/launcher2/AllApps3D.java
+++ b/src/com/android/launcher2/AllApps3D.java
@@ -73,6 +73,8 @@
     private static final int SELECTION_ICONS = 1;
     private static final int SELECTION_HOME = 2;
 
+    private static final int BATCH_SIZE = 0; // give us all the apps at once
+
     private Launcher mLauncher;
     private DragController mDragController;
 
@@ -1593,6 +1595,10 @@
         }
     }
 
+    public int getAppBatchSize() {
+        return BATCH_SIZE;
+    }
+
     public void dumpState() {
         Log.d(TAG, "sRS=" + sRS);
         Log.d(TAG, "sRollo=" + sRollo);
diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java
index 9d4c5b0..96d9369 100644
--- a/src/com/android/launcher2/AllAppsList.java
+++ b/src/com/android/launcher2/AllAppsList.java
@@ -24,6 +24,7 @@
 import android.content.pm.ResolveInfo;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 
@@ -56,10 +57,17 @@
     /**
      * Add the supplied ApplicationInfo objects to the list, and enqueue it into the
      * list to broadcast when notify() is called.
+     *
+     * Postcondition: data and added are sorted in order of LauncherModel.APP_NAME_COMPARATOR.
      */
     public void add(ApplicationInfo info) {
-        data.add(info);
-        added.add(info);
+        int pos = Collections.binarySearch(data, info, LauncherModel.APP_NAME_COMPARATOR);
+        if (pos < 0) pos = -1 - pos;
+        data.add(pos, info);
+        
+        pos = Collections.binarySearch(added, info, LauncherModel.APP_NAME_COMPARATOR);
+        if (pos < 0) pos = -1 - pos;
+        added.add(pos, info);
     }
     
     public void clear() {
@@ -86,9 +94,7 @@
 
         if (matches.size() > 0) {
             for (ResolveInfo info : matches) {
-                ApplicationInfo item = new ApplicationInfo(info, mIconCache);
-                data.add(item);
-                added.add(item);
+                add(new ApplicationInfo(info, mIconCache));
             }
         }
     }
@@ -139,9 +145,7 @@
                         info.activityInfo.applicationInfo.packageName,
                         info.activityInfo.name);
                 if (applicationInfo == null) {
-                    applicationInfo = new ApplicationInfo(info, mIconCache);
-                    data.add(applicationInfo);
-                    added.add(applicationInfo);
+                    add(new ApplicationInfo(info, mIconCache));
                 } else {
                     mIconCache.remove(applicationInfo.componentName);
                     mIconCache.getTitleAndIcon(applicationInfo, info);
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
index ed39a32..8888737 100644
--- a/src/com/android/launcher2/AllAppsView.java
+++ b/src/com/android/launcher2/AllAppsView.java
@@ -40,8 +40,10 @@
     public void removeApps(ArrayList<ApplicationInfo> list);
 
     public void updateApps(ArrayList<ApplicationInfo> list);
+    
+    public int  getAppBatchSize();
 
     public void dumpState();
-    
+
     public void surrender();
 }
diff --git a/src/com/android/launcher2/DeferredHandler.java b/src/com/android/launcher2/DeferredHandler.java
index ce60352..7801642 100644
--- a/src/com/android/launcher2/DeferredHandler.java
+++ b/src/com/android/launcher2/DeferredHandler.java
@@ -87,6 +87,12 @@
         post(new IdleRunnable(runnable));
     }
 
+    public void cancelRunnable(Runnable runnable) {
+        synchronized (mQueue) {
+            while (mQueue.remove(runnable)) { }
+        }
+    }
+
     public void cancel() {
         synchronized (mQueue) {
             mQueue.clear();
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index b5f20e4..b82e0cf 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -2086,6 +2086,15 @@
     }
 
     /**
+     * Find out how many apps we should send to the grid at a time.
+     *
+     * Implementation of the method from LauncherModel.Callbacks.
+     */
+    public int getAppBatchSize() {
+        return mAllAppsGrid.getAppBatchSize();
+    }
+
+    /**
      * Prints out out state for debugging.
      */
     public void dumpState() {
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 5e1abe6..9766831 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -62,6 +62,8 @@
     static final boolean DEBUG_LOADERS = false;
     static final String TAG = "Launcher.Model";
 
+    final int ALL_APPS_LOAD_DELAY = 150; // ms
+
     private final LauncherApplication mApp;
     private final Object mLock = new Object();
     private DeferredHandler mHandler = new DeferredHandler();
@@ -86,6 +88,7 @@
         public void bindAppsAdded(ArrayList<ApplicationInfo> apps);
         public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);
         public void bindAppsRemoved(ArrayList<ApplicationInfo> apps);
+        public int  getAppBatchSize();
     }
 
     LauncherModel(LauncherApplication app, IconCache iconCache) {
@@ -575,6 +578,13 @@
                     }
                 }
 
+                // Whew! Hard work done.
+                synchronized (mLock) {
+                    if (mIsLaunching) {
+                        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+                    }
+                }
+
                 // Load all apps if they're dirty
                 int allAppsSeq;
                 boolean allAppsDirty;
@@ -587,7 +597,7 @@
                     }
                 }
                 if (allAppsDirty) {
-                    loadAllApps();
+                    loadAndBindAllApps();
                 }
                 synchronized (mLock) {
                     // If we're not stopped, and nobody has incremented mAllAppsSeq.
@@ -599,11 +609,6 @@
                     }
                 }
 
-                // Bind all apps
-                if (allAppsDirty) {
-                    bindAllApps();
-                }
-
                 // Clear out this reference, otherwise we end up holding it until all of the
                 // callback runnables are done.
                 mContext = null;
@@ -1014,7 +1019,9 @@
                 });
             }
 
-            private void loadAllApps() {
+            private void loadAndBindAllApps() {
+                final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+
                 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
                 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
 
@@ -1026,53 +1033,79 @@
                 final PackageManager packageManager = mContext.getPackageManager();
                 final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
 
+                int N;
+                int batchSize = callbacks.getAppBatchSize();
+
                 synchronized (mLock) {
                     mBeforeFirstLoad = false;
-
                     mAllAppsList.clear();
-                    if (apps != null) {
-                        long t = SystemClock.uptimeMillis();
+                    if (apps == null) return;
+                    N = apps.size();
+                    if (batchSize <= 0)
+                        batchSize = N;
+                }
 
-                        int N = apps.size();
-                        for (int i=0; i<N && !mStopped; i++) {
+                int i=0;
+                while (i < N && !mStopped) {
+                    synchronized (mLock) {
+                        final long t2 = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+
+                        for (int j=0; i<N && j<batchSize; j++) {
                             // This builds the icon bitmaps.
                             mAllAppsList.add(new ApplicationInfo(apps.get(i), mIconCache));
+                            i++;
                         }
+                        // re-sort before binding this batch to the grid
                         Collections.sort(mAllAppsList.data, APP_NAME_COMPARATOR);
                         Collections.sort(mAllAppsList.added, APP_NAME_COMPARATOR);
                         if (DEBUG_LOADERS) {
-                            Log.d(TAG, "cached app icons in "
-                                    + (SystemClock.uptimeMillis()-t) + "ms");
+                            Log.d(TAG, "batch of " + batchSize + " icons processed in "
+                                    + (SystemClock.uptimeMillis()-t2) + "ms");
                         }
                     }
+
+                    mHandler.post(bindAllAppsTask);
+
+                    if (ALL_APPS_LOAD_DELAY > 0) {
+                        try {
+                            Thread.sleep(ALL_APPS_LOAD_DELAY);
+                        } catch (InterruptedException exc) { }
+                    }
+                }
+
+                if (DEBUG_LOADERS) {
+                    Log.d(TAG, "cached all " + N + " apps in "
+                            + (SystemClock.uptimeMillis()-t) + "ms");
                 }
             }
 
-            private void bindAllApps() {
-                synchronized (mLock) {
-                    final ArrayList<ApplicationInfo> results
-                            = (ArrayList<ApplicationInfo>) mAllAppsList.data.clone();
-                    // We're adding this now, so clear out this so we don't re-send them.
-                    mAllAppsList.added = new ArrayList<ApplicationInfo>();
-                    final Callbacks old = mCallbacks.get();
-                    mHandler.post(new Runnable() {
-                        public void run() {
-                            final long t = SystemClock.uptimeMillis();
-                            final int count = results.size();
+            final Runnable bindAllAppsTask = new Runnable() {
+                public void run() {
+                    final long t = SystemClock.uptimeMillis();
+                    int count = 0;
+                    Callbacks callbacks = null;
+                    ArrayList<ApplicationInfo> results = null;
+                    synchronized (mLock) {
+                        mHandler.cancelRunnable(this);
 
-                            Callbacks callbacks = tryGetCallbacks(old);
-                            if (callbacks != null) {
-                                callbacks.bindAllApplications(results);
-                            }
+                        results = (ArrayList<ApplicationInfo>) mAllAppsList.data.clone();
+                        // We're adding this now, so clear out this so we don't re-send them.
+                        mAllAppsList.added = new ArrayList<ApplicationInfo>();
+                        count = results.size();
 
-                            if (DEBUG_LOADERS) {
-                                Log.d(TAG, "bound app " + count + " icons in "
-                                    + (SystemClock.uptimeMillis() - t) + "ms");
-                            }
-                        }
-                    });
+                        callbacks = tryGetCallbacks(mCallbacks.get());
+                    }
+
+                    if (callbacks != null && count > 0) {
+                        callbacks.bindAllApplications(results);
+                    }
+
+                    if (DEBUG_LOADERS) {
+                        Log.d(TAG, "bound " + count + " apps in "
+                            + (SystemClock.uptimeMillis() - t) + "ms");
+                    }
                 }
-            }
+            };
 
             public void dumpState() {
                 Log.d(TAG, "mLoader.mLoaderThread.mContext=" + mContext);