From dca661236c73ecd819cfea964c6f8170e5cc40ae Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Tue, 13 Apr 2010 16:23:58 -0400 Subject: Batch loading of icons for AllApps. AllAppsList now maintains and in sorted order, to amortize the cost of sorting the apps list over multiple batches. Launcher boosts thread priority on first launch, but we now reduce thread priority to normal after the main workspace has been drawn but before all apps are loaded. Experimental feature: a short delay is introduced between batches to help free up the CPU (as well as to show that we are indeed batching apps). Bug: 2562420 Change-Id: I2035ec3e819b4e7993a80c6d03bfad3914c95a7a --- src/com/android/launcher2/AllApps2D.java | 6 ++ src/com/android/launcher2/AllApps3D.java | 6 ++ src/com/android/launcher2/AllAppsList.java | 20 +++-- src/com/android/launcher2/AllAppsView.java | 4 +- src/com/android/launcher2/DeferredHandler.java | 6 ++ src/com/android/launcher2/Launcher.java | 9 +++ src/com/android/launcher2/LauncherModel.java | 105 ++++++++++++++++--------- 7 files changed, 111 insertions(+), 45 deletions(-) (limited to 'src/com/android') diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java index 90c87fb18..eb7cd8333 100644 --- a/src/com/android/launcher2/AllApps2D.java +++ b/src/com/android/launcher2/AllApps2D.java @@ -50,6 +50,8 @@ public class AllApps2D 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 @@ public class AllApps2D 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 35e4cfc52..64c8c4c53 100644 --- a/src/com/android/launcher2/AllApps3D.java +++ b/src/com/android/launcher2/AllApps3D.java @@ -73,6 +73,8 @@ public class AllApps3D extends RSSurfaceView 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 class AllApps3D extends RSSurfaceView } } + 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 9d4c5b02a..96d936948 100644 --- a/src/com/android/launcher2/AllAppsList.java +++ b/src/com/android/launcher2/AllAppsList.java @@ -24,6 +24,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import java.util.ArrayList; +import java.util.Collections; import java.util.List; @@ -56,10 +57,17 @@ class AllAppsList { /** * 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 @@ class AllAppsList { 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 @@ class AllAppsList { 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 ed39a32d0..8888737d2 100644 --- a/src/com/android/launcher2/AllAppsView.java +++ b/src/com/android/launcher2/AllAppsView.java @@ -40,8 +40,10 @@ public interface AllAppsView { public void removeApps(ArrayList list); public void updateApps(ArrayList 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 ce60352c3..7801642d2 100644 --- a/src/com/android/launcher2/DeferredHandler.java +++ b/src/com/android/launcher2/DeferredHandler.java @@ -87,6 +87,12 @@ public class DeferredHandler { 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 b5f20e41d..b82e0cfbd 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -2085,6 +2085,15 @@ public final class Launcher extends Activity mAllAppsGrid.removeApps(apps); } + /** + * 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. */ diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index 5e1abe6c2..9766831bb 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -62,6 +62,8 @@ public class LauncherModel extends BroadcastReceiver { 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 class LauncherModel extends BroadcastReceiver { public void bindAppsAdded(ArrayList apps); public void bindAppsUpdated(ArrayList apps); public void bindAppsRemoved(ArrayList apps); + public int getAppBatchSize(); } LauncherModel(LauncherApplication app, IconCache iconCache) { @@ -575,6 +578,13 @@ public class LauncherModel extends BroadcastReceiver { } } + // 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 @@ public class LauncherModel extends BroadcastReceiver { } } if (allAppsDirty) { - loadAllApps(); + loadAndBindAllApps(); } synchronized (mLock) { // If we're not stopped, and nobody has incremented mAllAppsSeq. @@ -599,11 +609,6 @@ public class LauncherModel extends BroadcastReceiver { } } - // 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 @@ public class LauncherModel extends BroadcastReceiver { }); } - 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 @@ public class LauncherModel extends BroadcastReceiver { final PackageManager packageManager = mContext.getPackageManager(); final List 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 i=0; + while (i < N && !mStopped) { + synchronized (mLock) { + final long t2 = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - int N = apps.size(); - for (int i=0; i 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 results - = (ArrayList) mAllAppsList.data.clone(); - // We're adding this now, so clear out this so we don't re-send them. - mAllAppsList.added = new ArrayList(); - 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 results = null; + synchronized (mLock) { + mHandler.cancelRunnable(this); + + results = (ArrayList) mAllAppsList.data.clone(); + // We're adding this now, so clear out this so we don't re-send them. + mAllAppsList.added = new ArrayList(); + count = results.size(); + + callbacks = tryGetCallbacks(mCallbacks.get()); + } - Callbacks callbacks = tryGetCallbacks(old); - if (callbacks != null) { - callbacks.bindAllApplications(results); - } + if (callbacks != null && count > 0) { + callbacks.bindAllApplications(results); + } - if (DEBUG_LOADERS) { - Log.d(TAG, "bound app " + count + " icons in " - + (SystemClock.uptimeMillis() - t) + "ms"); - } - } - }); + if (DEBUG_LOADERS) { + Log.d(TAG, "bound " + count + " apps in " + + (SystemClock.uptimeMillis() - t) + "ms"); + } } - } + }; public void dumpState() { Log.d(TAG, "mLoader.mLoaderThread.mContext=" + mContext); -- cgit v1.2.3