diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 62aaa8be6a..13a39a3a30 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -92,7 +92,7 @@ import com.android.launcher.R; public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { static final String TAG = "Launcher"; - static final boolean LOGD = true; + static final boolean LOGD = false; static final boolean PROFILE_STARTUP = false; static final boolean DEBUG_WIDGETS = false; @@ -247,11 +247,6 @@ public final class Launcher extends Activity android.os.Debug.stopMethodTracing(); } - // We have a new AllAppsView, we need to re-bind everything, and it could have - // changed in our absence. - mModel.setAllAppsDirty(); - mModel.setWorkspaceDirty(); - if (!mRestoring) { mModel.startLoader(this, true); } @@ -1856,7 +1851,6 @@ public final class Launcher extends Activity if (mWorkspaceLoading) { lockAllApps(); - mModel.setWorkspaceDirty(); mModel.startLoader(Launcher.this, false); } else { final FolderIcon folderIcon = (FolderIcon) @@ -1866,7 +1860,6 @@ public final class Launcher extends Activity getWorkspace().requestLayout(); } else { lockAllApps(); - mModel.setWorkspaceDirty(); mWorkspaceLoading = true; mModel.startLoader(Launcher.this, false); } diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java index be448a8910..eda92d999c 100644 --- a/src/com/android/launcher2/LauncherApplication.java +++ b/src/com/android/launcher2/LauncherApplication.java @@ -73,8 +73,6 @@ public class LauncherApplication extends Application { private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { - // TODO: lockAllApps(); - mModel.setWorkspaceDirty(); mModel.startLoader(LauncherApplication.this, false); } }; diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index 96ceb747fd..ce26f37a25 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -71,6 +71,12 @@ public class LauncherModel extends BroadcastReceiver { private DeferredHandler mHandler = new DeferredHandler(); private Loader mLoader = new Loader(); + // We start off with everything not loaded. After that, we assume that + // our monitoring of the package manager provides all updates and we never + // need to do a requery. These are only ever touched from the loader thread. + private boolean mWorkspaceLoaded; + private boolean mAllAppsLoaded; + private boolean mBeforeFirstLoad = true; // only access this from main thread private WeakReference mCallbacks; @@ -286,17 +292,6 @@ public class LauncherModel extends BroadcastReceiver { mLoader.stopLoader(); } - /** - * We pick up most of the changes to all apps. - */ - public void setAllAppsDirty() { - mLoader.setAllAppsDirty(); - } - - public void setWorkspaceDirty() { - mLoader.setWorkspaceDirty(); - } - /** * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and * ACTION_PACKAGE_CHANGED. @@ -398,8 +393,9 @@ public class LauncherModel extends BroadcastReceiver { if (packages == null || packages.length == 0) { return; } - setAllAppsDirty(); - setWorkspaceDirty(); + synchronized (this) { + mAllAppsLoaded = mWorkspaceLoaded = false; + } startLoader(context, false); } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { String packages[] = intent.getStringArrayExtra( @@ -407,8 +403,9 @@ public class LauncherModel extends BroadcastReceiver { if (packages == null || packages.length == 0) { return; } - setAllAppsDirty(); - setWorkspaceDirty(); + synchronized (this) { + mAllAppsLoaded = mWorkspaceLoaded = false; + } startLoader(context, false); } } @@ -420,12 +417,6 @@ public class LauncherModel extends BroadcastReceiver { private LoaderThread mLoaderThread; - private int mLastWorkspaceSeq = 0; - private int mWorkspaceSeq = 1; - - private int mLastAllAppsSeq = 0; - private int mAllAppsSeq = 1; - final ArrayList mItems = new ArrayList(); final ArrayList mAppWidgets = new ArrayList(); final HashMap mFolders = new HashMap(); @@ -466,18 +457,6 @@ public class LauncherModel extends BroadcastReceiver { } } - public void setWorkspaceDirty() { - synchronized (mLock) { - mWorkspaceSeq++; - } - } - - public void setAllAppsDirty() { - synchronized (mLock) { - mAllAppsSeq++; - } - } - /** * Runnable for the thread that loads the contents of the launcher: * - workspace icons @@ -524,60 +503,33 @@ public class LauncherModel extends BroadcastReceiver { } private void loadAndBindWorkspace() { - // Load the workspace only if it's dirty. - int workspaceSeq; - boolean workspaceDirty; - synchronized (mLock) { - workspaceSeq = mWorkspaceSeq; - workspaceDirty = mWorkspaceSeq != mLastWorkspaceSeq; - } - if (workspaceDirty) { - loadWorkspace(); - } - synchronized (mLock) { - // If we're not stopped, and nobody has incremented mWorkspaceSeq. - if (mStopped) { - if (PROFILE_LOADERS) { - android.os.Debug.stopMethodTracing(); - } + // Load the workspace + // Other other threads can unset mWorkspaceLoaded, so atomically set it, + // and then if they unset it, or we unset it because of mStopped, it will + // be unset. + boolean loaded; + synchronized (this) { + loaded = mWorkspaceLoaded; + mWorkspaceLoaded = true; + } + + // For now, just always reload the workspace. It's ~100 ms vs. the + // binding which takes many hundreds of ms. + // We can reconsider. + if (DEBUG_LOADERS) Log.d(TAG, "loadAndBindWorkspace loaded=" + loaded); + if (true || !loaded) { + loadWorkspace(); + if (mStopped) { + mWorkspaceLoaded = false; return; } - if (workspaceSeq == mWorkspaceSeq) { - mLastWorkspaceSeq = mWorkspaceSeq; - } } // Bind the workspace bindWorkspace(); } - private void loadAndBindAllAppsIfDirty() { - // Load all apps if they're dirty - int allAppsSeq; - boolean allAppsDirty; - synchronized (mLock) { - allAppsSeq = mAllAppsSeq; - allAppsDirty = mAllAppsSeq != mLastAllAppsSeq; - if (DEBUG_LOADERS) { - Log.d(TAG, "mAllAppsSeq=" + mAllAppsSeq - + " mLastAllAppsSeq=" + mLastAllAppsSeq + " allAppsDirty"); - } - } - if (allAppsDirty) { - loadAndBindAllApps(); - } - synchronized (mLock) { - // If we're not stopped, and nobody has incremented mAllAppsSeq. - if (mStopped) { - return; - } - if (allAppsSeq == mAllAppsSeq) { - mLastAllAppsSeq = mAllAppsSeq; - } - } - } - private void waitForIdle() { // Wait until the either we're stopped or the other threads are done. // This way we don't start loading all apps until the workspace has settled @@ -637,7 +589,7 @@ public class LauncherModel extends BroadcastReceiver { loadAndBindWorkspace(); } else { if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps"); - loadAndBindAllAppsIfDirty(); + loadAndBindAllApps(); } // Whew! Hard work done. @@ -650,7 +602,7 @@ public class LauncherModel extends BroadcastReceiver { // second step if (loadWorkspaceFirst) { if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps"); - loadAndBindAllAppsIfDirty(); + loadAndBindAllApps(); } else { if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace"); loadAndBindWorkspace(); @@ -671,7 +623,7 @@ public class LauncherModel extends BroadcastReceiver { } // Trigger a gc to try to clean up after the stuff is done, since the - // renderscript allocations aren't charge to the java heap. + // renderscript allocations aren't charged to the java heap. mHandler.post(new Runnable() { public void run() { System.gc(); @@ -1133,6 +1085,55 @@ public class LauncherModel extends BroadcastReceiver { } private void loadAndBindAllApps() { + // Other other threads can unset mAllAppsLoaded, so atomically set it, + // and then if they unset it, or we unset it because of mStopped, it will + // be unset. + boolean loaded; + synchronized (this) { + loaded = mAllAppsLoaded; + mAllAppsLoaded = true; + } + + if (DEBUG_LOADERS) Log.d(TAG, "loadAndBindAllApps loaded=" + loaded); + if (!loaded) { + loadAllAppsByBatch(); + if (mStopped) { + mAllAppsLoaded = false; + return; + } + } else { + onlyBindAllApps(); + } + } + + private void onlyBindAllApps() { + final Callbacks oldCallbacks = mCallbacks.get(); + if (oldCallbacks == null) { + // This launcher has exited and nobody bothered to tell us. Just bail. + Log.w(TAG, "LoaderThread running with no launcher (onlyBindAllApps)"); + return; + } + + // shallow copy + final ArrayList list + = (ArrayList)mAllAppsList.data.clone(); + mHandler.post(new Runnable() { + public void run() { + final long t = SystemClock.uptimeMillis(); + final Callbacks callbacks = tryGetCallbacks(oldCallbacks); + if (callbacks != null) { + callbacks.bindAllApplications(list); + } + if (DEBUG_LOADERS) { + Log.d(TAG, "bound all " + list.size() + " apps from cache in " + + (SystemClock.uptimeMillis()-t) + "ms"); + } + } + }); + + } + + private void loadAllAppsByBatch() { final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; // Don't use these two variables in any of the callback runnables. @@ -1140,7 +1141,7 @@ public class LauncherModel extends BroadcastReceiver { final Callbacks oldCallbacks = mCallbacks.get(); if (oldCallbacks == null) { // This launcher has exited and nobody bothered to tell us. Just bail. - Log.w(TAG, "LoaderThread running with no launcher (loadAndBindAllApps)"); + Log.w(TAG, "LoaderThread running with no launcher (loadAllAppsByBatch)"); return; } @@ -1262,10 +1263,6 @@ public class LauncherModel extends BroadcastReceiver { } public void dumpState() { - Log.d(TAG, "mLoader.mLastWorkspaceSeq=" + mLoader.mLastWorkspaceSeq); - Log.d(TAG, "mLoader.mWorkspaceSeq=" + mLoader.mWorkspaceSeq); - Log.d(TAG, "mLoader.mLastAllAppsSeq=" + mLoader.mLastAllAppsSeq); - Log.d(TAG, "mLoader.mAllAppsSeq=" + mLoader.mAllAppsSeq); Log.d(TAG, "mLoader.mItems size=" + mLoader.mItems.size()); if (mLoaderThread != null) { mLoaderThread.dumpState();