From 64359a53dc827797917a8d9a0697a91996789801 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 8 Jul 2013 17:17:08 -0700 Subject: Ensuring that the db reflects all package added/removed/updated broadcasts. - Also ensuring that newly added pages are added before the empty page Change-Id: I97a01f791c438aa5c5b1fd770d3536b449a871bc --- res/values/config.xml | 4 - src/com/android/launcher3/ApplicationInfo.java | 5 +- .../android/launcher3/AppsCustomizePagedView.java | 6 +- src/com/android/launcher3/FolderInfo.java | 8 + src/com/android/launcher3/Hotseat.java | 3 +- src/com/android/launcher3/Launcher.java | 189 +++------- src/com/android/launcher3/LauncherModel.java | 400 ++++++++++++--------- src/com/android/launcher3/PagedView.java | 1 - src/com/android/launcher3/Workspace.java | 238 ++++++------ 9 files changed, 417 insertions(+), 437 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index e65818f15..6aaca1ad5 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -33,10 +33,6 @@ AppsCustomize (y / x * 100%) --> 150 - - 0 - 0 - true diff --git a/src/com/android/launcher3/ApplicationInfo.java b/src/com/android/launcher3/ApplicationInfo.java index 4659e7e85..53801d60c 100644 --- a/src/com/android/launcher3/ApplicationInfo.java +++ b/src/com/android/launcher3/ApplicationInfo.java @@ -114,7 +114,10 @@ class ApplicationInfo extends ItemInfo { @Override public String toString() { - return "ApplicationInfo(title=" + title.toString() + ")"; + return "ApplicationInfo(title=" + title.toString() + " id=" + this.id + + " type=" + this.itemType + " container=" + this.container + + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + dropPos + ")"; } public static void dumpApplicationInfoList(String tag, String label, diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java index aa2d531cf..dafa9b490 100644 --- a/src/com/android/launcher3/AppsCustomizePagedView.java +++ b/src/com/android/launcher3/AppsCustomizePagedView.java @@ -1592,8 +1592,10 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } public void removeApps(ArrayList appInfos) { - removeAppsWithoutInvalidate(appInfos); - updatePageCountsAndInvalidateData(); + if (!DISABLE_ALL_APPS) { + removeAppsWithoutInvalidate(appInfos); + updatePageCountsAndInvalidateData(); + } } public void updateApps(ArrayList list) { // We remove and re-add the updated applications list because it's properties may have diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java index 6d45e59ce..bb5ae8200 100644 --- a/src/com/android/launcher3/FolderInfo.java +++ b/src/com/android/launcher3/FolderInfo.java @@ -108,4 +108,12 @@ class FolderInfo extends ItemInfo { public void onTitleChanged(CharSequence title); public void onItemsChanged(); } + + @Override + public String toString() { + return "FolderInfo(id=" + this.id + " type=" + this.itemType + + " container=" + this.container + " screen=" + screenId + + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + + " spanY=" + spanY + " dropPos=" + dropPos + ")"; + } } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 93f39ff3b..054ef2fc1 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -24,6 +24,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.LayoutInflater; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; @@ -136,7 +137,7 @@ public class Hotseat extends FrameLayout { for (ApplicationInfo info: allApps) { ComponentName cn = info.intent.getComponent(); if (!onWorkspace.contains(cn)) { - System.out.println("Adding to all apps: " + info.intent); + Log.d(TAG, "Adding to all apps: " + info.intent); ShortcutInfo si = info.makeShortcut(); fi.add(si); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index b8fce6def..95aefe674 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -193,6 +193,7 @@ public class Launcher extends Activity // How long to wait before the new-shortcut animation automatically pans the workspace private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 10; + private static int NEW_APPS_ANIMATION_DELAY = 500; private final BroadcastReceiver mCloseSystemDialogsReceiver = new CloseSystemDialogsIntentReceiver(); @@ -407,11 +408,6 @@ public class Launcher extends Activity } } - if (!mModel.isAllAppsLoaded()) { - ViewGroup appsCustomizeContentParent = (ViewGroup) mAppsCustomizeContent.getParent(); - mInflater.inflate(R.layout.apps_customize_progressbar, appsCustomizeContentParent); - } - // For handling default keys mDefaultKeySsb = new SpannableStringBuilder(); Selection.setSelection(mDefaultKeySsb, 0); @@ -2479,17 +2475,10 @@ public class Launcher extends Activity return mWorkspace; } - // Now a part of LauncherModel.Callbacks. Used to reorder loading steps. - @Override public boolean isAllAppsVisible() { return (mState == State.APPS_CUSTOMIZE) || (mOnResumeState == State.APPS_CUSTOMIZE); } - @Override - public boolean isAllAppsButtonRank(int rank) { - return mHotseat.isAllAppsButtonRank(rank); - } - /** * Helper method for the cameraZoomIn/cameraZoomOut animations * @param view The view being animated @@ -3453,11 +3442,16 @@ public class Launcher extends Activity @Override public void bindScreens(ArrayList orderedScreenIds) { + bindAddScreens(orderedScreenIds); + mWorkspace.addExtraEmptyScreen(); + } + + @Override + public void bindAddScreens(ArrayList orderedScreenIds) { int count = orderedScreenIds.size(); for (int i = 0; i < count; i++) { - mWorkspace.insertNewWorkspaceScreenOnBind(orderedScreenIds.get(i)); + mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(orderedScreenIds.get(i), false); } - mWorkspace.addExtraEmptyScreen(); } /** @@ -3465,10 +3459,11 @@ public class Launcher extends Activity * * Implementation of the method from LauncherModel.Callbacks. */ - public void bindItems(final ArrayList shortcuts, final int start, final int end) { + public void bindItems(final ArrayList shortcuts, final int start, final int end, + final boolean forceAnimateIcons) { if (waitUntilResume(new Runnable() { public void run() { - bindItems(shortcuts, start, end); + bindItems(shortcuts, start, end, forceAnimateIcons); } })) { return; @@ -3478,6 +3473,8 @@ public class Launcher extends Activity Set newApps = new HashSet(); newApps = mSharedPrefs.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, newApps); + final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet(); + final Collection bounceAnims = new ArrayList(); Workspace workspace = mWorkspace; for (int i = start; i < end; i++) { final ItemInfo item = shortcuts.get(i); @@ -3495,6 +3492,14 @@ public class Launcher extends Activity String uri = info.intent.toUri(0).toString(); View shortcut = createShortcut(info); + /* + * TODO: FIX collision case + */ + CellLayout cl = mWorkspace.getScreenWithId(item.screenId); + if (cl != null && cl.isOccupied(item.cellX, item.cellY)) { + throw new RuntimeException("OCCUPIED"); + } + workspace.addInScreenFromBind(shortcut, item.container, item.screenId, item.cellX, item.cellY, 1, 1); boolean animateIconUp = false; @@ -3503,7 +3508,13 @@ public class Launcher extends Activity animateIconUp = newApps.remove(uri); } } - if (animateIconUp) { + if (forceAnimateIcons) { + // Animate all the applications up now + shortcut.setAlpha(0f); + shortcut.setScaleX(0f); + shortcut.setScaleY(0f); + bounceAnims.add(createNewAppBounceAnimation(shortcut, i)); + } else if (animateIconUp) { // Prepare the view to be animated up shortcut.setAlpha(0f); shortcut.setScaleX(0f); @@ -3524,6 +3535,16 @@ public class Launcher extends Activity } } + if (forceAnimateIcons) { + // We post the animation slightly delayed to prevent slowdowns when we are loading + // right after we return to launcher. + mWorkspace.postDelayed(new Runnable() { + public void run() { + anim.playTogether(bounceAnims); + anim.start(); + } + }, NEW_APPS_ANIMATION_DELAY); + } workspace.requestLayout(); } @@ -3595,7 +3616,6 @@ public class Launcher extends Activity * Implementation of the method from LauncherModel.Callbacks. */ public void finishBindingItems(final boolean upgradePath) { - if (waitUntilResume(new Runnable() { public void run() { finishBindingItems(upgradePath); @@ -3753,119 +3773,10 @@ public class Launcher extends Activity * Implementation of the method from LauncherModel.Callbacks. */ public void bindAllApplications(final ArrayList apps) { - Runnable setAllAppsRunnable = new Runnable() { - public void run() { - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.setApps(apps); - - if (mIntentsOnWorkspaceFromUpgradePath != null) { - getHotseat().addAllAppsFolder(mIconCache, apps, - mIntentsOnWorkspaceFromUpgradePath, Launcher.this); - mIntentsOnWorkspaceFromUpgradePath = null; - } - } - } - }; - - // Remove the progress bar entirely; we could also make it GONE - // but better to remove it since we know it's not going to be used - View progressBar = mAppsCustomizeTabHost. - findViewById(R.id.apps_customize_progress_bar); - if (progressBar != null) { - ((ViewGroup)progressBar.getParent()).removeView(progressBar); - - // We just post the call to setApps so the user sees the progress bar - // disappear-- otherwise, it just looks like the progress bar froze - // which doesn't look great - mAppsCustomizeTabHost.post(setAllAppsRunnable); - } else { - // If we did not initialize the spinner in onCreate, then we can directly set the - // list of applications without waiting for any progress bars views to be hidden. - setAllAppsRunnable.run(); - } - } - - /** - * A package was installed. - * - * Implementation of the method from LauncherModel.Callbacks. - */ - public void bindAppsAdded(final ArrayList apps) { - if (waitUntilResume(new Runnable() { - public void run() { - bindAppsAdded(apps); - } - })) { - return; - } - - final Launcher launcher = this; - final Context context = this; - final ArrayList appsCopy = new ArrayList(); - appsCopy.addAll(apps); - - // Process newly added apps - mWorkspace.post(new Runnable() { - @Override - public void run() { - // Process newly added apps - LauncherModel model = getModel(); - Iterator iter = appsCopy.iterator(); - ArrayList animatedShortcuts = new ArrayList(); - - while (iter.hasNext()) { - ApplicationInfo a = iter.next(); - Pair coords = LauncherModel.findNextAvailableIconSpace(context, - a.title.toString(), a.intent); - if (coords == null) { - // If we can't find a valid position, then just add a new screen. - // This takes time so we need to re-queue the add until the new - // page is added. - long screenId = LauncherAppState.getInstance().getLauncherProvider() - .generateNewScreenId(); - mWorkspace.insertNewWorkspaceScreen(screenId, false); - model.updateWorkspaceScreenOrder(launcher, mWorkspace.getScreenOrder(), - new Runnable() { - @Override - public void run() { - bindAppsAdded(appsCopy); - } - }); - return; - } else { - final ShortcutInfo shortcutInfo = a.makeShortcut(); - final View shortcut = createShortcut(shortcutInfo); - // Add the view to the screen - mWorkspace.addInScreenFromBind(shortcut, - LauncherSettings.Favorites.CONTAINER_DESKTOP, - coords.first, coords.second[0], coords.second[1], 1, 1); - // Add the shortcut to the db - model.addItemToDatabase(context, shortcutInfo, - LauncherSettings.Favorites.CONTAINER_DESKTOP, - coords.first, coords.second[0], coords.second[1], false); - // Animate the shortcut - animatedShortcuts.add(shortcut); - } - iter.remove(); - } - - // Animate all the applications up - AnimatorSet anim = LauncherAnimUtils.createAnimatorSet(); - Collection bounceAnims = new ArrayList(); - for (int i = 0; i < animatedShortcuts.size(); ++i) { - View shortcut = animatedShortcuts.get(i); - shortcut.setAlpha(0f); - shortcut.setScaleX(0f); - shortcut.setScaleY(0f); - bounceAnims.add(createNewAppBounceAnimation(shortcut, i)); - } - anim.playTogether(bounceAnims); - anim.start(); - } - }); - - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.addApps(apps); + if (mIntentsOnWorkspaceFromUpgradePath != null) { + getHotseat().addAllAppsFolder(mIconCache, apps, + mIntentsOnWorkspaceFromUpgradePath, Launcher.this); + mIntentsOnWorkspaceFromUpgradePath = null; } } @@ -3886,10 +3797,6 @@ public class Launcher extends Activity if (mWorkspace != null) { mWorkspace.updateShortcuts(apps); } - - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.updateApps(apps); - } } /** @@ -3903,25 +3810,21 @@ public class Launcher extends Activity */ public void bindComponentsRemoved(final ArrayList packageNames, final ArrayList appInfos, - final boolean matchPackageNamesOnly) { + final boolean packageRemoved) { if (waitUntilResume(new Runnable() { public void run() { - bindComponentsRemoved(packageNames, appInfos, matchPackageNamesOnly); + bindComponentsRemoved(packageNames, appInfos, packageRemoved); } })) { return; } - if (matchPackageNamesOnly) { + if (packageRemoved) { mWorkspace.removeItemsByPackageName(packageNames); } else { mWorkspace.removeItemsByApplicationInfo(appInfos); } - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.removeApps(appInfos); - } - // Notify the drag controller mDragController.onAppsRemoved(appInfos, this); } @@ -3929,7 +3832,6 @@ public class Launcher extends Activity /** * A number of packages were updated. */ - private ArrayList mWidgetsAndShortcuts; private Runnable mBindPackagesUpdatedRunnable = new Runnable() { public void run() { @@ -3944,6 +3846,7 @@ public class Launcher extends Activity return; } + // Update the widgets pane if (mAppsCustomizeContent != null) { mAppsCustomizeContent.onPackagesUpdated(widgetsAndShortcuts); } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index d09880542..0b69a09c9 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -48,6 +48,7 @@ import java.net.URISyntaxException; import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -68,8 +69,6 @@ public class LauncherModel extends BroadcastReceiver { private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons private final boolean mAppsCanBeOnExternalStorage; - private int mBatchSize; // 0 is all apps at once - private int mAllAppsLoadDelay; // milliseconds between batches private final LauncherAppState mApp; private final Object mLock = new Object(); @@ -149,24 +148,27 @@ public class LauncherModel extends BroadcastReceiver { public boolean setLoadOnResume(); public int getCurrentWorkspaceScreen(); public void startBinding(); - public void bindItems(ArrayList shortcuts, int start, int end); + public void bindItems(ArrayList shortcuts, int start, int end, + boolean forceAnimateIcons); public void bindScreens(ArrayList orderedScreenIds); + public void bindAddScreens(ArrayList orderedScreenIds); public void bindFolders(HashMap folders); public void finishBindingItems(boolean upgradePath); public void bindAppWidget(LauncherAppWidgetInfo info); public void bindAllApplications(ArrayList apps); - public void bindAppsAdded(ArrayList apps); public void bindAppsUpdated(ArrayList apps); public void bindComponentsRemoved(ArrayList packageNames, ArrayList appInfos, boolean matchPackageNamesOnly); public void bindPackagesUpdated(ArrayList widgetsAndShortcuts); - public boolean isAllAppsVisible(); - public boolean isAllAppsButtonRank(int rank); public void bindSearchablesChanged(); public void onPageBoundSynchronously(int page); } + public interface ItemInfoFilter { + public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn); + } + LauncherModel(LauncherAppState app, IconCache iconCache) { final Context context = app.getContext(); @@ -179,8 +181,6 @@ public class LauncherModel extends BroadcastReceiver { mIconCache.getFullResDefaultActivityIcon(), context); final Resources res = context.getResources(); - mAllAppsLoadDelay = res.getInteger(R.integer.config_allAppsBatchLoadDelay); - mBatchSize = res.getInteger(R.integer.config_allAppsBatchSize); Configuration config = res.getConfiguration(); mPreviousConfigMcc = config.mcc; } @@ -243,12 +243,13 @@ public class LauncherModel extends BroadcastReceiver { LauncherModel model = app.getModel(); boolean found = false; synchronized (app) { - // Flush the LauncherModel worker thread, so that if we just did another - // processInstallShortcut, we give it time for its shortcut to get added to the - // database (getItemsInLocalCoordinates reads the database) - model.flushWorkerThread(); + if (sWorkerThread.getThreadId() != Process.myTid()) { + // Flush the LauncherModel worker thread, so that if we just did another + // processInstallShortcut, we give it time for its shortcut to get added to the + // database (getItemsInLocalCoordinates reads the database) + model.flushWorkerThread(); + } final ArrayList items = LauncherModel.getItemsInLocalCoordinates(context); - final boolean shortcutExists = LauncherModel.shortcutExists(context, name, launchIntent); // Try adding to the workspace screens incrementally, starting at the default or center // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1)) @@ -265,6 +266,74 @@ public class LauncherModel extends BroadcastReceiver { return null; } + public void addAndBindAddedApps(final Context context, final ArrayList added, + final Callbacks callbacks) { + // Process the newly added applications and add them to the database first + Runnable r = new Runnable() { + public void run() { + final ArrayList addedShortcutsFinal = new ArrayList(); + final ArrayList addedWorkspaceScreensFinal = new ArrayList(); + + synchronized(sBgLock) { + Iterator iter = added.iterator(); + while (iter.hasNext()) { + ApplicationInfo a = iter.next(); + final String name = a.title.toString(); + final Intent launchIntent = a.intent; + + // Short-circuit this logic if the icon exists somewhere on the workspace + if (LauncherModel.shortcutExists(context, name, launchIntent)) { + continue; + } + + // Add this icon to the db, creating a new page if necessary + Pair coords = LauncherModel.findNextAvailableIconSpace(context, + name, launchIntent); + if (coords == null) { + // If we can't find a valid position, then just add a new screen. + // This takes time so we need to re-queue the add until the new + // page is added. + LauncherAppState appState = LauncherAppState.getInstance(); + LauncherProvider lp = appState.getLauncherProvider(); + long screenId = lp.generateNewScreenId(); + // Update the model + sBgWorkspaceScreens.add(screenId); + updateWorkspaceScreenOrder(context, sBgWorkspaceScreens); + // Save the screen id for binding in the workspace + addedWorkspaceScreensFinal.add(screenId); + // Find the coordinate again + coords = LauncherModel.findNextAvailableIconSpace(context, + a.title.toString(), a.intent); + } + if (coords == null) { + throw new RuntimeException("Coordinates should not be null"); + } + + final ShortcutInfo shortcutInfo = a.makeShortcut(); + // Add the shortcut to the db + addItemToDatabase(context, shortcutInfo, + LauncherSettings.Favorites.CONTAINER_DESKTOP, + coords.first, coords.second[0], coords.second[1], false); + // Save the ShortcutInfo for binding in the workspace + addedShortcutsFinal.add(shortcutInfo); + } + } + + runOnMainThread(new Runnable() { + public void run() { + Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks == cb && cb != null) { + callbacks.bindAddScreens(addedWorkspaceScreensFinal); + callbacks.bindItems(addedShortcutsFinal, 0, + addedShortcutsFinal.size(), true); + } + } + }); + } + }; + runOnWorkerThread(r); + } + public Bitmap getFallbackIcon() { return Bitmap.createBitmap(mDefaultIcon); } @@ -868,14 +937,12 @@ public class LauncherModel extends BroadcastReceiver { * a list of screen ids in the order that they should appear. */ void updateWorkspaceScreenOrder(Context context, final ArrayList screens) { - updateWorkspaceScreenOrder(context, screens, null); - } - void updateWorkspaceScreenOrder(Context context, final ArrayList screens, final Runnable mainThreadCb) { + final ArrayList screensCopy = new ArrayList(screens); final ContentResolver cr = context.getContentResolver(); final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI; // Remove any negative screen ids -- these aren't persisted - Iterator iter = screens.iterator(); + Iterator iter = screensCopy.iterator(); while (iter.hasNext()) { long id = iter.next(); if (id < 0) { @@ -886,8 +953,6 @@ public class LauncherModel extends BroadcastReceiver { Runnable r = new Runnable() { @Override public void run() { - final ArrayList screensCopy = new ArrayList(); - // Clear the table cr.delete(uri, null, null); int count = screens.size(); @@ -897,7 +962,6 @@ public class LauncherModel extends BroadcastReceiver { long screenId = screens.get(i); v.put(LauncherSettings.WorkspaceScreens._ID, screenId); v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); - screensCopy.add(screenId); values[i] = v; } cr.bulkInsert(uri, values); @@ -906,14 +970,6 @@ public class LauncherModel extends BroadcastReceiver { } }; runOnWorkerThread(r); - if (mainThreadCb != null) { - runOnWorkerThread(new Runnable() { - @Override - public void run() { - runOnMainThread(mainThreadCb); - } - }); - } } /** @@ -1279,8 +1335,6 @@ public class LauncherModel extends BroadcastReceiver { // 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. @@ -1290,13 +1344,8 @@ public class LauncherModel extends BroadcastReceiver { android.os.Process.setThreadPriority(mIsLaunching ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND); } - if (loadWorkspaceFirst) { - if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace"); - loadAndBindWorkspace(); - } else { - if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps"); - loadAndBindAllApps(); - } + if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace"); + loadAndBindWorkspace(); if (mStopped) { break keep_running; @@ -1313,13 +1362,8 @@ public class LauncherModel extends BroadcastReceiver { waitForIdle(); // second step - if (loadWorkspaceFirst) { - if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps"); - loadAndBindAllApps(); - } else { - if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace"); - loadAndBindWorkspace(); - } + if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps"); + loadAndBindAllApps(); // Restore the default thread priority after we are done loading items synchronized (mLock) { @@ -1952,7 +1996,8 @@ public class LauncherModel extends BroadcastReceiver { public void run() { Callbacks callbacks = tryGetCallbacks(oldCallbacks); if (callbacks != null) { - callbacks.bindItems(workspaceItems, start, start+chunkSize); + callbacks.bindItems(workspaceItems, start, start+chunkSize, + false); } } }; @@ -2119,7 +2164,7 @@ public class LauncherModel extends BroadcastReceiver { Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded); } if (!mAllAppsLoaded) { - loadAllAppsByBatch(); + loadAllApps(); synchronized (LoaderTask.this) { if (mStopped) { return; @@ -2157,124 +2202,84 @@ public class LauncherModel extends BroadcastReceiver { } }; boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid()); - if (oldCallbacks.isAllAppsVisible() && isRunningOnMainThread) { + if (isRunningOnMainThread) { r.run(); } else { mHandler.post(r); } } - private void loadAllAppsByBatch() { - final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; + private void loadAllApps() { + final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; // Don't use these two variables in any of the callback runnables. // Otherwise we hold a reference to them. final Callbacks oldCallbacks = mCallbacks.get(); if (oldCallbacks == null) { // This launcher has exited and nobody bothered to tell us. Just bail. - Log.w(TAG, "LoaderTask running with no launcher (loadAllAppsByBatch)"); + Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)"); return; } + final PackageManager packageManager = mContext.getPackageManager(); final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); - final PackageManager packageManager = mContext.getPackageManager(); - List apps = null; - - int N = Integer.MAX_VALUE; - - int startIndex; - int i=0; - int batchSize = -1; - while (i < N && !mStopped) { - if (i == 0) { - mBgAllAppsList.clear(); - final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - apps = packageManager.queryIntentActivities(mainIntent, 0); - if (DEBUG_LOADERS) { - Log.d(TAG, "queryIntentActivities took " - + (SystemClock.uptimeMillis()-qiaTime) + "ms"); - } - if (apps == null) { - return; - } - N = apps.size(); - if (DEBUG_LOADERS) { - Log.d(TAG, "queryIntentActivities got " + N + " apps"); - } - if (N == 0) { - // There are no apps?!? - return; - } - if (mBatchSize == 0) { - batchSize = N; - } else { - batchSize = mBatchSize; - } + // Clear the list of apps + mBgAllAppsList.clear(); - final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - Collections.sort(apps, - new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache)); - if (DEBUG_LOADERS) { - Log.d(TAG, "sort took " - + (SystemClock.uptimeMillis()-sortTime) + "ms"); - } - } - - final long t2 = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - - startIndex = i; - for (int j=0; i added = mBgAllAppsList.added; - mBgAllAppsList.added = new ArrayList(); + // Query for the set of apps + final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; + List apps = packageManager.queryIntentActivities(mainIntent, 0); + if (DEBUG_LOADERS) { + Log.d(TAG, "queryIntentActivities took " + + (SystemClock.uptimeMillis()-qiaTime) + "ms"); + Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps"); + } + // Fail if we don't have any apps + if (apps == null || apps.isEmpty()) { + return; + } + // Sort the applications by name + final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; + Collections.sort(apps, + new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache)); + if (DEBUG_LOADERS) { + Log.d(TAG, "sort took " + + (SystemClock.uptimeMillis()-sortTime) + "ms"); + } - mHandler.post(new Runnable() { - public void run() { - final long t = SystemClock.uptimeMillis(); - if (callbacks != null) { - if (first) { - callbacks.bindAllApplications(added); - } else { - callbacks.bindAppsAdded(added); - } - if (DEBUG_LOADERS) { - Log.d(TAG, "bound " + added.size() + " apps in " - + (SystemClock.uptimeMillis() - t) + "ms"); - } - } else { - Log.i(TAG, "not binding apps: no Launcher activity"); - } - } - }); + // Create the ApplicationInfos + final long addTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; + for (int i = 0; i < apps.size(); i++) { + // This builds the icon bitmaps. + mBgAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i), + mIconCache, mLabelCache)); + } - if (DEBUG_LOADERS) { - Log.d(TAG, "batch of " + (i-startIndex) + " icons processed in " - + (SystemClock.uptimeMillis()-t2) + "ms"); - } + final Callbacks callbacks = tryGetCallbacks(oldCallbacks); + final ArrayList added = mBgAllAppsList.added; + mBgAllAppsList.added = new ArrayList(); - if (mAllAppsLoadDelay > 0 && i < N) { - try { + // Post callback on main thread + mHandler.post(new Runnable() { + public void run() { + final long bindTime = SystemClock.uptimeMillis(); + if (callbacks != null) { + callbacks.bindAllApplications(added); if (DEBUG_LOADERS) { - Log.d(TAG, "sleeping for " + mAllAppsLoadDelay + "ms"); + Log.d(TAG, "bound " + added.size() + " apps in " + + (SystemClock.uptimeMillis() - bindTime) + "ms"); } - Thread.sleep(mAllAppsLoadDelay); - } catch (InterruptedException exc) { } + } else { + Log.i(TAG, "not binding apps: no Launcher activity"); + } } - } + }); if (DEBUG_LOADERS) { - Log.d(TAG, "cached all " + N + " apps in " - + (SystemClock.uptimeMillis()-t) + "ms" - + (mAllAppsLoadDelay > 0 ? " (including delay)" : "")); + Log.d(TAG, "Icons processed in " + + (SystemClock.uptimeMillis() - loadTime) + "ms"); } } @@ -2364,18 +2369,26 @@ public class LauncherModel extends BroadcastReceiver { } if (added != null) { - final ArrayList addedFinal = added; - mHandler.post(new Runnable() { - public void run() { - Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; - if (callbacks == cb && cb != null) { - callbacks.bindAppsAdded(addedFinal); - } - } - }); + // Ensure that we add all the workspace applications to the db + Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; + addAndBindAddedApps(context, added, cb); } if (modified != null) { final ArrayList modifiedFinal = modified; + + // Update the launcher db to reflect the changes + for (ApplicationInfo a : modifiedFinal) { + ArrayList infos = + getItemInfoForComponentName(a.componentName); + for (ItemInfo i : infos) { + if (isShortcutInfoUpdateable(i)) { + ShortcutInfo info = (ShortcutInfo) i; + info.title = a.title.toString(); + updateItemInDatabase(context, info); + } + } + } + mHandler.post(new Runnable() { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; @@ -2388,16 +2401,34 @@ public class LauncherModel extends BroadcastReceiver { // If a package has been removed, or an app has been removed as a result of // an update (for example), make the removed callback. if (mOp == OP_REMOVE || !removedApps.isEmpty()) { - final boolean permanent = (mOp == OP_REMOVE); + final boolean packageRemoved = (mOp == OP_REMOVE); final ArrayList removedPackageNames = new ArrayList(Arrays.asList(packages)); + // Update the launcher db to reflect the removal of apps + if (packageRemoved) { + for (String pn : removedPackageNames) { + ArrayList infos = getItemInfoForPackageName(pn); + for (ItemInfo i : infos) { + deleteItemFromDatabase(context, i); + } + } + } else { + for (ApplicationInfo a : removedApps) { + ArrayList infos = + getItemInfoForComponentName(a.componentName); + for (ItemInfo i : infos) { + deleteItemFromDatabase(context, i); + } + } + } + mHandler.post(new Runnable() { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; if (callbacks == cb && cb != null) { callbacks.bindComponentsRemoved(removedPackageNames, - removedApps, permanent); + removedApps, packageRemoved); } } }); @@ -2532,22 +2563,71 @@ public class LauncherModel extends BroadcastReceiver { return info; } - /** - * Returns the set of workspace ShortcutInfos with the specified intent. - */ - static ArrayList getWorkspaceShortcutItemInfosWithIntent(Intent intent) { - ArrayList items = new ArrayList(); - synchronized (sBgLock) { - for (ItemInfo info : sBgWorkspaceItems) { - if (info instanceof ShortcutInfo) { - ShortcutInfo shortcut = (ShortcutInfo) info; - if (shortcut.intent.toUri(0).equals(intent.toUri(0))) { - items.add(shortcut); + static ArrayList filterItemInfos(Collection infos, + ItemInfoFilter f) { + HashSet filtered = new HashSet(); + for (ItemInfo i : infos) { + if (i instanceof ShortcutInfo) { + ShortcutInfo info = (ShortcutInfo) i; + ComponentName cn = info.intent.getComponent(); + if (cn != null && f.filterItem(null, info, cn)) { + filtered.add(info); + } + } else if (i instanceof FolderInfo) { + FolderInfo info = (FolderInfo) i; + for (ShortcutInfo s : info.contents) { + ComponentName cn = s.intent.getComponent(); + if (cn != null && f.filterItem(info, s, cn)) { + filtered.add(s); } } + } else if (i instanceof LauncherAppWidgetInfo) { + LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i; + ComponentName cn = info.providerName; + if (cn != null && f.filterItem(null, info, cn)) { + filtered.add(info); + } } } - return items; + return new ArrayList(filtered); + } + + private ArrayList getItemInfoForPackageName(final String pn) { + HashSet infos = new HashSet(); + ItemInfoFilter filter = new ItemInfoFilter() { + @Override + public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) { + return cn.getPackageName().equals(pn); + } + }; + return filterItemInfos(sBgItemsIdMap.values(), filter); + } + + private ArrayList getItemInfoForComponentName(final ComponentName cname) { + HashSet infos = new HashSet(); + ItemInfoFilter filter = new ItemInfoFilter() { + @Override + public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) { + return cn.equals(cname); + } + }; + return filterItemInfos(sBgItemsIdMap.values(), filter); + } + + public static boolean isShortcutInfoUpdateable(ItemInfo i) { + if (i instanceof ShortcutInfo) { + ShortcutInfo info = (ShortcutInfo) i; + // We need to check for ACTION_MAIN otherwise getComponent() might + // return null for some shortcuts (for instance, for shortcuts to + // web pages.) + Intent intent = info.intent; + ComponentName name = intent.getComponent(); + if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && + Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { + return true; + } + } + return false; } /** diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 20d7e5e00..0a20724ee 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1680,7 +1680,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc break; } - System.out.println("onTouch, return true"); return true; } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 851cce591..37ef3c437 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -474,22 +474,31 @@ public class Workspace extends SmoothPagedView } public long insertNewWorkspaceScreen(long screenId) { - return insertNewWorkspaceScreen(screenId, true); + return insertNewWorkspaceScreen(screenId, getChildCount(), true); } - public long insertNewWorkspaceScreenOnBind(long screenId) { - return insertNewWorkspaceScreen(screenId, false); + public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId, boolean updateDb) { + // Find the index to insert this view into. If the empty screen exists, then + // insert it before that. + int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID); + if (insertIndex < 0) { + insertIndex = mScreenOrder.size(); + } + return insertNewWorkspaceScreen(screenId, insertIndex, updateDb); } public long insertNewWorkspaceScreen(long screenId, boolean updateDb) { + return insertNewWorkspaceScreen(screenId, getChildCount(), updateDb); + } + + public long insertNewWorkspaceScreen(long screenId, int insertIndex, boolean updateDb) { CellLayout newScreen = (CellLayout) mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null); - newScreen.setOnLongClickListener(mLongClickListener); mWorkspaceScreens.put(screenId, newScreen); - mScreenOrder.add(screenId); - addView(newScreen, getChildCount()); + mScreenOrder.add(insertIndex, screenId); + addView(newScreen, insertIndex); if (updateDb) { // On bind we don't need to update the screens in the database. mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder); @@ -533,6 +542,10 @@ public class Workspace extends SmoothPagedView mScreenOrder.add(newId); addExtraEmptyScreen(); + + // Update the model for the new screen + mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder); + return newId; } @@ -588,6 +601,11 @@ public class Workspace extends SmoothPagedView removeView(cl); } setCurrentPage(mCurrentPage - pageShift); + + if (!removeScreens.isEmpty()) { + // Update the model if we have changed any screens + mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder); + } } // See implementation for parameter definition. @@ -3741,44 +3759,35 @@ public class Workspace extends SmoothPagedView // has been removed and we want to remove all components (widgets, shortcuts, apps) that // belong to that package. void removeItemsByPackageName(final ArrayList packages) { - HashSet packageNames = new HashSet(); + final HashSet packageNames = new HashSet(); packageNames.addAll(packages); - // Just create a hash table of all the specific components that this will affect - HashSet cns = new HashSet(); + // Filter out all the ItemInfos that this is going to affect + final HashSet infos = new HashSet(); + final HashSet cns = new HashSet(); ArrayList cellLayouts = getWorkspaceAndHotseatCellLayouts(); for (CellLayout layoutParent : cellLayouts) { ViewGroup layout = layoutParent.getShortcutsAndWidgets(); int childCount = layout.getChildCount(); for (int i = 0; i < childCount; ++i) { View view = layout.getChildAt(i); - Object tag = view.getTag(); - - if (tag instanceof ShortcutInfo) { - ShortcutInfo info = (ShortcutInfo) tag; - ComponentName cn = info.intent.getComponent(); - if ((cn != null) && packageNames.contains(cn.getPackageName())) { - cns.add(cn); - } - } else if (tag instanceof FolderInfo) { - FolderInfo info = (FolderInfo) tag; - for (ShortcutInfo s : info.contents) { - ComponentName cn = s.intent.getComponent(); - if ((cn != null) && packageNames.contains(cn.getPackageName())) { - cns.add(cn); - } - } - } else if (tag instanceof LauncherAppWidgetInfo) { - LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag; - ComponentName cn = info.providerName; - if ((cn != null) && packageNames.contains(cn.getPackageName())) { - cns.add(cn); - } - } + infos.add((ItemInfo) view.getTag()); } } + LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() { + @Override + public boolean filterItem(ItemInfo parent, ItemInfo info, + ComponentName cn) { + if (packageNames.contains(cn.getPackageName())) { + cns.add(cn); + return true; + } + return false; + } + }; + LauncherModel.filterItemInfos(infos, filter); - // Remove all the things + // Remove the affected components removeItemsByComponentName(cns); } @@ -3801,81 +3810,70 @@ public class Workspace extends SmoothPagedView for (final CellLayout layoutParent: cellLayouts) { final ViewGroup layout = layoutParent.getShortcutsAndWidgets(); - // Avoid ANRs by treating each screen separately - post(new Runnable() { - public void run() { - final ArrayList childrenToRemove = new ArrayList(); - childrenToRemove.clear(); - - int childCount = layout.getChildCount(); - for (int j = 0; j < childCount; j++) { - final View view = layout.getChildAt(j); - Object tag = view.getTag(); - - if (tag instanceof ShortcutInfo) { - final ShortcutInfo info = (ShortcutInfo) tag; - final Intent intent = info.intent; - final ComponentName name = intent.getComponent(); - - if (name != null) { - if (componentNames.contains(name)) { - LauncherModel.deleteItemFromDatabase(mLauncher, info); - childrenToRemove.add(view); - } - } - } else if (tag instanceof FolderInfo) { - final FolderInfo info = (FolderInfo) tag; - final ArrayList contents = info.contents; - final int contentsCount = contents.size(); - final ArrayList appsToRemoveFromFolder = - new ArrayList(); - - for (int k = 0; k < contentsCount; k++) { - final ShortcutInfo appInfo = contents.get(k); - final Intent intent = appInfo.intent; - final ComponentName name = intent.getComponent(); - - if (name != null) { - if (componentNames.contains(name)) { - appsToRemoveFromFolder.add(appInfo); - } - } - } - for (ShortcutInfo item: appsToRemoveFromFolder) { - info.remove(item); - LauncherModel.deleteItemFromDatabase(mLauncher, item); - } - } else if (tag instanceof LauncherAppWidgetInfo) { - final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag; - final ComponentName provider = info.providerName; - if (provider != null) { - if (componentNames.contains(provider)) { - LauncherModel.deleteItemFromDatabase(mLauncher, info); - childrenToRemove.add(view); - } + final HashMap children = new HashMap(); + for (int j = 0; j < layout.getChildCount(); j++) { + final View view = layout.getChildAt(j); + children.put((ItemInfo) view.getTag(), view); + } + + final ArrayList childrenToRemove = new ArrayList(); + final HashMap> folderAppsToRemove = + new HashMap>(); + LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() { + @Override + public boolean filterItem(ItemInfo parent, ItemInfo info, + ComponentName cn) { + if (parent instanceof FolderInfo) { + if (componentNames.contains(cn)) { + FolderInfo folder = (FolderInfo) parent; + ArrayList appsToRemove; + if (folderAppsToRemove.containsKey(folder)) { + appsToRemove = folderAppsToRemove.get(folder); + } else { + appsToRemove = new ArrayList(); + folderAppsToRemove.put(folder, appsToRemove); } + appsToRemove.add((ShortcutInfo) info); + return true; } - } - - childCount = childrenToRemove.size(); - for (int j = 0; j < childCount; j++) { - View child = childrenToRemove.get(j); - // Note: We can not remove the view directly from CellLayoutChildren as this - // does not re-mark the spaces as unoccupied. - layoutParent.removeViewInLayout(child); - if (child instanceof DropTarget) { - mDragController.removeDropTarget((DropTarget)child); + } else { + if (componentNames.contains(cn)) { + childrenToRemove.add(children.get(info)); + return true; } } + return false; + } + }; + LauncherModel.filterItemInfos(children.keySet(), filter); - if (childCount > 0) { - layout.requestLayout(); - layout.invalidate(); - } + // Remove all the apps from their folders + for (FolderInfo folder : folderAppsToRemove.keySet()) { + ArrayList appsToRemove = folderAppsToRemove.get(folder); + for (ShortcutInfo info : appsToRemove) { + folder.remove(info); + } + } + + // Remove all the other children + for (View child : childrenToRemove) { + // Note: We can not remove the view directly from CellLayoutChildren as this + // does not re-mark the spaces as unoccupied. + layoutParent.removeViewInLayout(child); + if (child instanceof DropTarget) { + mDragController.removeDropTarget((DropTarget) child); } - }); + } + + if (childrenToRemove.size() > 0) { + layout.requestLayout(); + layout.invalidate(); + } } + // Strip all the empty screens + stripEmptyScreens(); + // Clean up new-apps animation list final Context context = getContext(); post(new Runnable() { @@ -3897,15 +3895,6 @@ public class Workspace extends SmoothPagedView if (componentNames.contains(intent.getComponent())) { iter.remove(); } - - // It is possible that we've queued an item to be loaded, yet it has - // not been added to the workspace, so remove those items as well. - ArrayList shortcuts; - shortcuts = LauncherModel.getWorkspaceShortcutItemInfosWithIntent( - intent); - for (ItemInfo info : shortcuts) { - LauncherModel.deleteItemFromDatabase(context, info); - } } catch (URISyntaxException e) {} } } @@ -3921,24 +3910,20 @@ public class Workspace extends SmoothPagedView for (int j = 0; j < childCount; j++) { final View view = layout.getChildAt(j); Object tag = view.getTag(); - if (tag instanceof ShortcutInfo) { + + if (LauncherModel.isShortcutInfoUpdateable((ItemInfo) tag)) { ShortcutInfo info = (ShortcutInfo) tag; - // We need to check for ACTION_MAIN otherwise getComponent() might - // return null for some shortcuts (for instance, for shortcuts to - // web pages.) + final Intent intent = info.intent; final ComponentName name = intent.getComponent(); - if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && - Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { - final int appCount = apps.size(); - for (int k = 0; k < appCount; k++) { - ApplicationInfo app = apps.get(k); - if (app.componentName.equals(name)) { - BubbleTextView shortcut = (BubbleTextView) view; - info.updateIcon(mIconCache); - info.title = app.title.toString(); - shortcut.applyFromShortcutInfo(info, mIconCache); - } + final int appCount = apps.size(); + for (int k = 0; k < appCount; k++) { + ApplicationInfo app = apps.get(k); + if (app.componentName.equals(name)) { + BubbleTextView shortcut = (BubbleTextView) view; + info.updateIcon(mIconCache); + info.title = app.title.toString(); + shortcut.applyFromShortcutInfo(info, mIconCache); } } } @@ -3954,7 +3939,10 @@ public class Workspace extends SmoothPagedView setCurrentPage(mDefaultPage); } } - getChildAt(mDefaultPage).requestFocus(); + View child = getChildAt(mDefaultPage); + if (child != null) { + child.requestFocus(); + } } @Override -- cgit v1.2.3