am 68925c53: Merge "Make the loader thread a Looper and move the package manager updates into that thread as well." into gingerbread
Merge commit '68925c535932b7cbb8aafb4f981f23ef2887a1c4' * commit '68925c535932b7cbb8aafb4f981f23ef2887a1c4': Make the loader thread a Looper and move the package manager
This commit is contained in:
commit
ff68ed0595
|
@ -2281,9 +2281,11 @@ public final class Launcher extends Activity
|
|||
*
|
||||
* Implementation of the method from LauncherModel.Callbacks.
|
||||
*/
|
||||
public void bindAppsRemoved(ArrayList<ApplicationInfo> apps) {
|
||||
public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent) {
|
||||
removeDialog(DIALOG_CREATE_SHORTCUT);
|
||||
if (permanent) {
|
||||
mWorkspace.removeItems(apps);
|
||||
}
|
||||
mAllAppsGrid.removeApps(apps);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ import android.database.Cursor;
|
|||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
@ -60,16 +62,18 @@ import com.android.launcher.R;
|
|||
*/
|
||||
public class LauncherModel extends BroadcastReceiver {
|
||||
static final boolean DEBUG_LOADERS = false;
|
||||
static final boolean PROFILE_LOADERS = false;
|
||||
static final String TAG = "Launcher.Model";
|
||||
|
||||
private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
|
||||
private int mBatchSize; // 0 is all apps at once
|
||||
private int mAllAppsLoadDelay; // milliseconds between batches
|
||||
|
||||
private final LauncherApplication mApp;
|
||||
private final Object mLock = new Object();
|
||||
private DeferredHandler mHandler = new DeferredHandler();
|
||||
private Loader mLoader = new Loader();
|
||||
private HandlerThread mWorkerThread;
|
||||
private Handler mWorker;
|
||||
private LoaderTask mLoaderTask;
|
||||
|
||||
// We start off with everything not loaded. After that, we assume that
|
||||
// our monitoring of the package manager provides all updates and we never
|
||||
|
@ -77,12 +81,13 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
private boolean mWorkspaceLoaded;
|
||||
private boolean mAllAppsLoaded;
|
||||
|
||||
private boolean mBeforeFirstLoad = true; // only access this from main thread
|
||||
private WeakReference<Callbacks> mCallbacks;
|
||||
|
||||
private final Object mAllAppsListLock = new Object();
|
||||
private AllAppsList mAllAppsList;
|
||||
private AllAppsList mAllAppsList; // only access in worker thread
|
||||
private IconCache mIconCache;
|
||||
final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
|
||||
final ArrayList<LauncherAppWidgetInfo> mAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
|
||||
final HashMap<Long, FolderInfo> mFolders = new HashMap<Long, FolderInfo>();
|
||||
|
||||
private Bitmap mDefaultIcon;
|
||||
|
||||
|
@ -96,7 +101,7 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
public void bindAllApplications(ArrayList<ApplicationInfo> apps);
|
||||
public void bindAppsAdded(ArrayList<ApplicationInfo> apps);
|
||||
public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);
|
||||
public void bindAppsRemoved(ArrayList<ApplicationInfo> apps);
|
||||
public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent);
|
||||
public boolean isAllAppsVisible();
|
||||
}
|
||||
|
||||
|
@ -111,6 +116,10 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
mAllAppsLoadDelay = app.getResources().getInteger(R.integer.config_allAppsBatchLoadDelay);
|
||||
|
||||
mBatchSize = app.getResources().getInteger(R.integer.config_allAppsBatchSize);
|
||||
|
||||
mWorkerThread = new HandlerThread("launcher-loader");
|
||||
mWorkerThread.start();
|
||||
mWorker = new Handler(mWorkerThread.getLooper());
|
||||
}
|
||||
|
||||
public Bitmap getFallbackIcon() {
|
||||
|
@ -284,33 +293,13 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
}
|
||||
}
|
||||
|
||||
public void startLoader(Context context, boolean isLaunching) {
|
||||
mLoader.startLoader(context, isLaunching);
|
||||
}
|
||||
|
||||
public void stopLoader() {
|
||||
mLoader.stopLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
|
||||
* ACTION_PACKAGE_CHANGED.
|
||||
*/
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// Use the app as the context.
|
||||
context = mApp;
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);
|
||||
|
||||
ArrayList<ApplicationInfo> added = null;
|
||||
ArrayList<ApplicationInfo> removed = null;
|
||||
ArrayList<ApplicationInfo> modified = null;
|
||||
|
||||
if (mBeforeFirstLoad) {
|
||||
// If we haven't even loaded yet, don't bother, since we'll just pick
|
||||
// up the changes.
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mAllAppsListLock) {
|
||||
final String action = intent.getAction();
|
||||
|
||||
if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
|
||||
|
@ -319,112 +308,43 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
final String packageName = intent.getData().getSchemeSpecificPart();
|
||||
final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
|
||||
|
||||
int op = PackageUpdatedTask.OP_NONE;
|
||||
|
||||
if (packageName == null || packageName.length() == 0) {
|
||||
// they sent us a bad intent
|
||||
return;
|
||||
}
|
||||
|
||||
if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
|
||||
mAllAppsList.updatePackage(context, packageName);
|
||||
op = PackageUpdatedTask.OP_UPDATE;
|
||||
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
|
||||
if (!replacing) {
|
||||
mAllAppsList.removePackage(packageName);
|
||||
op = PackageUpdatedTask.OP_REMOVE;
|
||||
}
|
||||
// else, we are replacing the package, so a PACKAGE_ADDED will be sent
|
||||
// later, we will update the package at this time
|
||||
} else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
|
||||
if (!replacing) {
|
||||
mAllAppsList.addPackage(context, packageName);
|
||||
op = PackageUpdatedTask.OP_ADD;
|
||||
} else {
|
||||
mAllAppsList.updatePackage(context, packageName);
|
||||
op = PackageUpdatedTask.OP_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (mAllAppsList.added.size() > 0) {
|
||||
added = mAllAppsList.added;
|
||||
mAllAppsList.added = new ArrayList<ApplicationInfo>();
|
||||
}
|
||||
if (mAllAppsList.removed.size() > 0) {
|
||||
removed = mAllAppsList.removed;
|
||||
mAllAppsList.removed = new ArrayList<ApplicationInfo>();
|
||||
for (ApplicationInfo info: removed) {
|
||||
mIconCache.remove(info.intent.getComponent());
|
||||
}
|
||||
}
|
||||
if (mAllAppsList.modified.size() > 0) {
|
||||
modified = mAllAppsList.modified;
|
||||
mAllAppsList.modified = new ArrayList<ApplicationInfo>();
|
||||
if (op != PackageUpdatedTask.OP_NONE) {
|
||||
enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }));
|
||||
}
|
||||
|
||||
final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
|
||||
if (callbacks == null) {
|
||||
Log.w(TAG, "Nobody to tell about the new app. Launcher is probably loading.");
|
||||
return;
|
||||
}
|
||||
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
|
||||
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
||||
enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));
|
||||
|
||||
if (added != null) {
|
||||
final ArrayList<ApplicationInfo> addedFinal = added;
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
callbacks.bindAppsAdded(addedFinal);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (modified != null) {
|
||||
final ArrayList<ApplicationInfo> modifiedFinal = modified;
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
callbacks.bindAppsUpdated(modifiedFinal);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (removed != null) {
|
||||
final ArrayList<ApplicationInfo> removedFinal = removed;
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
callbacks.bindAppsRemoved(removedFinal);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
|
||||
String packages[] = intent.getStringArrayExtra(
|
||||
Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
||||
if (packages == null || packages.length == 0) {
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
mAllAppsLoaded = mWorkspaceLoaded = false;
|
||||
}
|
||||
startLoader(context, false);
|
||||
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
|
||||
String packages[] = intent.getStringArrayExtra(
|
||||
Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
||||
if (packages == null || packages.length == 0) {
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
mAllAppsLoaded = mWorkspaceLoaded = false;
|
||||
}
|
||||
startLoader(context, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
|
||||
enqueuePackageUpdated(new PackageUpdatedTask(
|
||||
PackageUpdatedTask.OP_UNAVAILABLE, packages));
|
||||
|
||||
public class Loader {
|
||||
private static final int ITEMS_CHUNK = 6;
|
||||
|
||||
private LoaderThread mLoaderThread;
|
||||
|
||||
final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
|
||||
final ArrayList<LauncherAppWidgetInfo> mAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
|
||||
final HashMap<Long, FolderInfo> mFolders = new HashMap<Long, FolderInfo>();
|
||||
|
||||
/**
|
||||
* Call this from the ui thread so the handler is initialized on the correct thread.
|
||||
*/
|
||||
public Loader() {
|
||||
}
|
||||
}
|
||||
|
||||
public void startLoader(Context context, boolean isLaunching) {
|
||||
|
@ -435,24 +355,25 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
|
||||
// Don't bother to start the thread if we know it's not going to do anything
|
||||
if (mCallbacks != null && mCallbacks.get() != null) {
|
||||
LoaderThread oldThread = mLoaderThread;
|
||||
if (oldThread != null) {
|
||||
if (oldThread.isLaunching()) {
|
||||
// If there is already one running, tell it to stop.
|
||||
LoaderTask oldTask = mLoaderTask;
|
||||
if (oldTask != null) {
|
||||
if (oldTask.isLaunching()) {
|
||||
// don't downgrade isLaunching if we're already running
|
||||
isLaunching = true;
|
||||
}
|
||||
oldThread.stopLocked();
|
||||
oldTask.stopLocked();
|
||||
}
|
||||
mLoaderThread = new LoaderThread(context, oldThread, isLaunching);
|
||||
mLoaderThread.start();
|
||||
mLoaderTask = new LoaderTask(context, isLaunching);
|
||||
mWorker.post(mLoaderTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopLoader() {
|
||||
synchronized (mLock) {
|
||||
if (mLoaderThread != null) {
|
||||
mLoaderThread.stopLocked();
|
||||
if (mLoaderTask != null) {
|
||||
mLoaderTask.stopLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -463,16 +384,15 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
* - widgets
|
||||
* - all apps icons
|
||||
*/
|
||||
private class LoaderThread extends Thread {
|
||||
private class LoaderTask implements Runnable {
|
||||
private Context mContext;
|
||||
private Thread mWaitThread;
|
||||
private boolean mIsLaunching;
|
||||
private boolean mStopped;
|
||||
private boolean mLoadAndBindStepFinished;
|
||||
|
||||
LoaderThread(Context context, Thread waitThread, boolean isLaunching) {
|
||||
LoaderTask(Context context, boolean isLaunching) {
|
||||
mContext = context;
|
||||
mWaitThread = waitThread;
|
||||
mIsLaunching = isLaunching;
|
||||
}
|
||||
|
||||
|
@ -480,50 +400,21 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
return mIsLaunching;
|
||||
}
|
||||
|
||||
/**
|
||||
* If another LoaderThread was supplied, we need to wait for that to finish before
|
||||
* we start our processing. This keeps the ordering of the setting and clearing
|
||||
* of the dirty flags correct by making sure we don't start processing stuff until
|
||||
* they've had a chance to re-set them. We do this waiting the worker thread, not
|
||||
* the ui thread to avoid ANRs.
|
||||
*/
|
||||
private void waitForOtherThread() {
|
||||
if (mWaitThread != null) {
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
try {
|
||||
mWaitThread.join();
|
||||
done = true;
|
||||
} catch (InterruptedException ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
mWaitThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadAndBindWorkspace() {
|
||||
// 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) {
|
||||
if (DEBUG_LOADERS) {
|
||||
Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);
|
||||
}
|
||||
if (true || !mWorkspaceLoaded) {
|
||||
loadWorkspace();
|
||||
if (mStopped) {
|
||||
mWorkspaceLoaded = false;
|
||||
return;
|
||||
}
|
||||
mWorkspaceLoaded = true;
|
||||
}
|
||||
|
||||
// Bind the workspace
|
||||
|
@ -534,17 +425,17 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
// 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
|
||||
// down.
|
||||
synchronized (LoaderThread.this) {
|
||||
synchronized (LoaderTask.this) {
|
||||
final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
|
||||
|
||||
mHandler.postIdle(new Runnable() {
|
||||
public void run() {
|
||||
synchronized (LoaderThread.this) {
|
||||
synchronized (LoaderTask.this) {
|
||||
mLoadAndBindStepFinished = true;
|
||||
if (DEBUG_LOADERS) {
|
||||
Log.d(TAG, "done with previous binding step");
|
||||
}
|
||||
LoaderThread.this.notify();
|
||||
LoaderTask.this.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -565,14 +456,13 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
}
|
||||
|
||||
public void run() {
|
||||
waitForOtherThread();
|
||||
|
||||
// Optimize for end-user experience: if the Launcher is up and // running with the
|
||||
// All Apps interface in the foreground, load All Apps first. Otherwise, load the
|
||||
// workspace first (default).
|
||||
final Callbacks cbk = mCallbacks.get();
|
||||
final boolean loadWorkspaceFirst = cbk != null ? (!cbk.isAllAppsVisible()) : true;
|
||||
|
||||
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) {
|
||||
|
@ -580,10 +470,6 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
|
||||
}
|
||||
|
||||
if (PROFILE_LOADERS) {
|
||||
android.os.Debug.startMethodTracing("/sdcard/launcher-loaders");
|
||||
}
|
||||
|
||||
if (loadWorkspaceFirst) {
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
|
||||
loadAndBindWorkspace();
|
||||
|
@ -592,12 +478,18 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
loadAndBindAllApps();
|
||||
}
|
||||
|
||||
// Whew! Hard work done.
|
||||
if (mStopped) {
|
||||
break keep_running;
|
||||
}
|
||||
|
||||
// Whew! Hard work done. Slow us down, and wait until the UI thread has
|
||||
// settled down.
|
||||
synchronized (mLock) {
|
||||
if (mIsLaunching) {
|
||||
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
}
|
||||
}
|
||||
waitForIdle();
|
||||
|
||||
// second step
|
||||
if (loadWorkspaceFirst) {
|
||||
|
@ -607,32 +499,38 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace");
|
||||
loadAndBindWorkspace();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear out this reference, otherwise we end up holding it until all of the
|
||||
// callback runnables are done.
|
||||
mContext = null;
|
||||
|
||||
synchronized (mLock) {
|
||||
// Setting the reference is atomic, but we can't do it inside the other critical
|
||||
// sections.
|
||||
mLoaderThread = null;
|
||||
// If we are still the last one to be scheduled, remove ourselves.
|
||||
if (mLoaderTask == this) {
|
||||
mLoaderTask = null;
|
||||
}
|
||||
|
||||
if (PROFILE_LOADERS) {
|
||||
android.os.Debug.stopMethodTracing();
|
||||
}
|
||||
|
||||
// Trigger a gc to try to clean up after the stuff is done, since the
|
||||
// renderscript allocations aren't charged to the java heap.
|
||||
if (mStopped) {
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
System.gc();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mHandler.postIdle(new Runnable() {
|
||||
public void run() {
|
||||
System.gc();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void stopLocked() {
|
||||
synchronized (LoaderThread.this) {
|
||||
synchronized (LoaderTask.this) {
|
||||
mStopped = true;
|
||||
this.notify();
|
||||
}
|
||||
|
@ -989,7 +887,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");
|
||||
Log.w(TAG, "LoaderTask running with no launcher");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1089,22 +987,15 @@ 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 mAllAppsLoaded=" + mAllAppsLoaded);
|
||||
}
|
||||
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "loadAndBindAllApps loaded=" + loaded);
|
||||
if (!loaded) {
|
||||
if (!mAllAppsLoaded) {
|
||||
loadAllAppsByBatch();
|
||||
if (mStopped) {
|
||||
mAllAppsLoaded = false;
|
||||
return;
|
||||
}
|
||||
mAllAppsLoaded = true;
|
||||
} else {
|
||||
onlyBindAllApps();
|
||||
}
|
||||
|
@ -1114,7 +1005,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 (onlyBindAllApps)");
|
||||
Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1145,7 +1036,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 (loadAllAppsByBatch)");
|
||||
Log.w(TAG, "LoaderTask running with no launcher (loadAllAppsByBatch)");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1161,12 +1052,7 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
int i=0;
|
||||
int batchSize = -1;
|
||||
while (i < N && !mStopped) {
|
||||
synchronized (mAllAppsListLock) {
|
||||
if (i == 0) {
|
||||
// This needs to happen inside the same lock block as when we
|
||||
// prepare the first batch for bindAllApplications. Otherwise
|
||||
// the package changed receiver can come in and double-add
|
||||
// (or miss one?).
|
||||
mAllAppsList.clear();
|
||||
final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
|
||||
apps = packageManager.queryIntentActivities(mainIntent, 0);
|
||||
|
@ -1219,7 +1105,6 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
final long t = SystemClock.uptimeMillis();
|
||||
if (callbacks != null) {
|
||||
if (first) {
|
||||
mBeforeFirstLoad = false;
|
||||
callbacks.bindAllApplications(added);
|
||||
} else {
|
||||
callbacks.bindAppsAdded(added);
|
||||
|
@ -1238,7 +1123,6 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
Log.d(TAG, "batch of " + (i-startIndex) + " icons processed in "
|
||||
+ (SystemClock.uptimeMillis()-t2) + "ms");
|
||||
}
|
||||
}
|
||||
|
||||
if (mAllAppsLoadDelay > 0 && i < N) {
|
||||
try {
|
||||
|
@ -1258,20 +1142,117 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
}
|
||||
|
||||
public void dumpState() {
|
||||
Log.d(TAG, "mLoader.mLoaderThread.mContext=" + mContext);
|
||||
Log.d(TAG, "mLoader.mLoaderThread.mWaitThread=" + mWaitThread);
|
||||
Log.d(TAG, "mLoader.mLoaderThread.mIsLaunching=" + mIsLaunching);
|
||||
Log.d(TAG, "mLoader.mLoaderThread.mStopped=" + mStopped);
|
||||
Log.d(TAG, "mLoader.mLoaderThread.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
|
||||
Log.d(TAG, "mLoaderTask.mContext=" + mContext);
|
||||
Log.d(TAG, "mLoaderTask.mWaitThread=" + mWaitThread);
|
||||
Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);
|
||||
Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
|
||||
Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpState() {
|
||||
Log.d(TAG, "mLoader.mItems size=" + mLoader.mItems.size());
|
||||
if (mLoaderThread != null) {
|
||||
mLoaderThread.dumpState();
|
||||
} else {
|
||||
Log.d(TAG, "mLoader.mLoaderThread=null");
|
||||
void enqueuePackageUpdated(PackageUpdatedTask task) {
|
||||
mWorker.post(task);
|
||||
}
|
||||
|
||||
private class PackageUpdatedTask implements Runnable {
|
||||
int mOp;
|
||||
String[] mPackages;
|
||||
|
||||
public static final int OP_NONE = 0;
|
||||
public static final int OP_ADD = 1;
|
||||
public static final int OP_UPDATE = 2;
|
||||
public static final int OP_REMOVE = 3; // uninstlled
|
||||
public static final int OP_UNAVAILABLE = 4; // external media unmounted
|
||||
|
||||
|
||||
public PackageUpdatedTask(int op, String[] packages) {
|
||||
mOp = op;
|
||||
mPackages = packages;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
final Context context = mApp;
|
||||
|
||||
final String[] packages = mPackages;
|
||||
final int N = packages.length;
|
||||
switch (mOp) {
|
||||
case OP_ADD:
|
||||
for (int i=0; i<N; i++) {
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
|
||||
mAllAppsList.addPackage(context, packages[i]);
|
||||
}
|
||||
break;
|
||||
case OP_UPDATE:
|
||||
for (int i=0; i<N; i++) {
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
|
||||
mAllAppsList.updatePackage(context, packages[i]);
|
||||
}
|
||||
break;
|
||||
case OP_REMOVE:
|
||||
case OP_UNAVAILABLE:
|
||||
for (int i=0; i<N; i++) {
|
||||
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
|
||||
mAllAppsList.removePackage(packages[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ArrayList<ApplicationInfo> added = null;
|
||||
ArrayList<ApplicationInfo> removed = null;
|
||||
ArrayList<ApplicationInfo> modified = null;
|
||||
|
||||
if (mAllAppsList.added.size() > 0) {
|
||||
added = mAllAppsList.added;
|
||||
mAllAppsList.added = new ArrayList<ApplicationInfo>();
|
||||
}
|
||||
if (mAllAppsList.removed.size() > 0) {
|
||||
removed = mAllAppsList.removed;
|
||||
mAllAppsList.removed = new ArrayList<ApplicationInfo>();
|
||||
for (ApplicationInfo info: removed) {
|
||||
mIconCache.remove(info.intent.getComponent());
|
||||
}
|
||||
}
|
||||
if (mAllAppsList.modified.size() > 0) {
|
||||
modified = mAllAppsList.modified;
|
||||
mAllAppsList.modified = new ArrayList<ApplicationInfo>();
|
||||
}
|
||||
|
||||
final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
|
||||
if (callbacks == null) {
|
||||
Log.w(TAG, "Nobody to tell about the new app. Launcher is probably loading.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (added != null) {
|
||||
final ArrayList<ApplicationInfo> addedFinal = added;
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
if (callbacks == mCallbacks.get()) {
|
||||
callbacks.bindAppsAdded(addedFinal);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (modified != null) {
|
||||
final ArrayList<ApplicationInfo> modifiedFinal = modified;
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
if (callbacks == mCallbacks.get()) {
|
||||
callbacks.bindAppsUpdated(modifiedFinal);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (removed != null) {
|
||||
final boolean permanent = mOp != OP_UNAVAILABLE;
|
||||
final ArrayList<ApplicationInfo> removedFinal = removed;
|
||||
mHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
if (callbacks == mCallbacks.get()) {
|
||||
callbacks.bindAppsRemoved(removedFinal, permanent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1583,12 +1564,16 @@ public class LauncherModel extends BroadcastReceiver {
|
|||
};
|
||||
|
||||
public void dumpState() {
|
||||
Log.d(TAG, "mBeforeFirstLoad=" + mBeforeFirstLoad);
|
||||
Log.d(TAG, "mCallbacks=" + mCallbacks);
|
||||
ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mAllAppsList.data);
|
||||
ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mAllAppsList.added);
|
||||
ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mAllAppsList.removed);
|
||||
ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mAllAppsList.modified);
|
||||
mLoader.dumpState();
|
||||
Log.d(TAG, "mItems size=" + mItems.size());
|
||||
if (mLoaderTask != null) {
|
||||
mLoaderTask.dumpState();
|
||||
} else {
|
||||
Log.d(TAG, "mLoaderTask=null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue