merge in jb-release history after reset to jb-dev
diff --git a/res/layout-land/drop_target_bar.xml b/res/layout-land/drop_target_bar.xml
new file mode 100644
index 0000000..794a79e
--- /dev/null
+++ b/res/layout-land/drop_target_bar.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/DropTargetButtonContainer"
+ android:layout_weight="1">
+ <!-- Delete target -->
+ <com.android.launcher2.DeleteDropTarget
+ style="@style/DropTargetButton"
+ android:id="@+id/delete_target_text"
+ android:drawableTop="@drawable/remove_target_selector" />
+ </FrameLayout>
+ <FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/DropTargetButtonContainer"
+ android:layout_weight="1">
+ <!-- Info target -->
+ <com.android.launcher2.InfoDropTarget
+ style="@style/DropTargetButton"
+ android:id="@+id/info_target_text"
+ android:drawableTop="@drawable/info_target_selector" />
+ </FrameLayout>
+</merge>
\ No newline at end of file
diff --git a/res/layout/drop_target_bar.xml b/res/layout-port/drop_target_bar.xml
similarity index 100%
rename from res/layout/drop_target_bar.xml
rename to res/layout-port/drop_target_bar.xml
diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml
index 02dd290..02789de 100644
--- a/res/values-sw600dp/config.xml
+++ b/res/values-sw600dp/config.xml
@@ -1,6 +1,4 @@
<resources>
- <bool name="allow_rotation">true</bool>
-
<integer name="cell_count_x">6</integer>
<integer name="cell_count_y">6</integer>
<integer name="hotseat_cell_count">7</integer>
diff --git a/res/values-sw720dp/config.xml b/res/values-sw720dp/config.xml
index cdca805..97a6e9f 100644
--- a/res/values-sw720dp/config.xml
+++ b/res/values-sw720dp/config.xml
@@ -1,6 +1,7 @@
<resources>
<bool name="config_largeHeap">true</bool>
<bool name="is_large_screen">true</bool>
+ <bool name="allow_rotation">true</bool>
<!-- AllApps/Customize/AppsCustomize -->
<!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 98d4c09..f4180cd 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -338,11 +338,6 @@
mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
mAppWidgetHost.startListening();
- // If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
- // this also ensures that any synchronous binding below doesn't re-trigger another
- // LauncherModel load.
- mPaused = false;
-
if (PROFILE_STARTUP) {
android.os.Debug.startMethodTracing(
Environment.getExternalStorageDirectory() + "/launcher");
@@ -370,7 +365,7 @@
}
if (!mRestoring) {
- mModel.startLoader(true, mWorkspace.getCurrentPage());
+ mModel.startLoader(true);
}
if (!mModel.isAllAppsLoaded()) {
@@ -682,7 +677,7 @@
mPaused = false;
if (mRestoring || mOnResumeNeedsLoad) {
mWorkspaceLoading = true;
- mModel.startLoader(true, -1);
+ mModel.startLoader(true);
mRestoring = false;
mOnResumeNeedsLoad = false;
}
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 29723d4..fc1a26d 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -57,10 +57,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
-import java.util.Set;
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
@@ -80,7 +77,6 @@
private final Object mLock = new Object();
private DeferredHandler mHandler = new DeferredHandler();
private LoaderTask mLoaderTask;
- private boolean mIsLoaderTaskRunning;
private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
static {
@@ -94,41 +90,29 @@
private boolean mWorkspaceLoaded;
private boolean mAllAppsLoaded;
- // When we are loading pages synchronously, we can't just post the binding of items on the side
- // pages as this delays the rotation process. Instead, we wait for a callback from the first
- // draw (in Workspace) to initiate the binding of the remaining side pages. Any time we start
- // a normal load, we also clear this set of Runnables.
- static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();
-
private WeakReference<Callbacks> mCallbacks;
// < only access in worker thread >
private AllAppsList mAllAppsList;
- // The lock that must be acquired before referencing any static bg data structures. Unlike
- // other locks, this one can generally be held long-term because we never expect any of these
- // static data structures to be referenced outside of the worker thread except on the first
- // load after configuration change.
- static final Object sBgLock = new Object();
-
- // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
+ // sItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
// LauncherModel to their ids
- static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();
+ static final HashMap<Long, ItemInfo> sItemsIdMap = new HashMap<Long, ItemInfo>();
- // sBgItems is passed to bindItems, which expects a list of all folders and shortcuts created by
+ // sItems is passed to bindItems, which expects a list of all folders and shortcuts created by
// LauncherModel that are directly on the home screen (however, no widgets or shortcuts
// within folders).
- static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();
+ static final ArrayList<ItemInfo> sWorkspaceItems = new ArrayList<ItemInfo>();
- // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()
- static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =
+ // sAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()
+ static final ArrayList<LauncherAppWidgetInfo> sAppWidgets =
new ArrayList<LauncherAppWidgetInfo>();
- // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
- static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();
+ // sFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
+ static final HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
- // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database
- static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();
+ // sDbIconCache is the set of ItemInfos that need to have their icons updated in the database
+ static final HashMap<Object, byte[]> sDbIconCache = new HashMap<Object, byte[]>();
// </ only access in worker thread >
@@ -174,28 +158,6 @@
mPreviousConfigMcc = config.mcc;
}
- /** Runs the specified runnable immediately if called from the main thread, otherwise it is
- * posted on the main thread handler. */
- private void runOnMainThread(Runnable r) {
- if (sWorkerThread.getThreadId() == Process.myTid()) {
- // If we are on the worker thread, post onto the main handler
- mHandler.post(r);
- } else {
- r.run();
- }
- }
-
- /** Runs the specified runnable immediately if called from the worker thread, otherwise it is
- * posted on the worker thread handler. */
- private static void runOnWorkerThread(Runnable r) {
- if (sWorkerThread.getThreadId() == Process.myTid()) {
- r.run();
- } else {
- // If we are not on the worker thread, then post to the worker handler
- sWorker.post(r);
- }
- }
-
public Bitmap getFallbackIcon() {
return Bitmap.createBitmap(mDefaultIcon);
}
@@ -209,28 +171,26 @@
});
}
- /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */
- private void unbindWorkspaceItemsOnMainThread() {
+ /** Unbinds all the sWorkspaceItems on the main thread, and return a copy of sWorkspaceItems
+ * that is save to reference from the main thread. */
+ private ArrayList<ItemInfo> unbindWorkspaceItemsOnMainThread() {
// Ensure that we don't use the same workspace items data structure on the main thread
// by making a copy of workspace items first.
- final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();
- final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();
- synchronized (sBgLock) {
- tmpWorkspaceItems.addAll(sBgWorkspaceItems);
- tmpAppWidgets.addAll(sBgAppWidgets);
- }
- Runnable r = new Runnable() {
- @Override
- public void run() {
- for (ItemInfo item : tmpWorkspaceItems) {
- item.unbind();
- }
- for (ItemInfo item : tmpAppWidgets) {
- item.unbind();
- }
- }
- };
- runOnMainThread(r);
+ final ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>(sWorkspaceItems);
+ final ArrayList<ItemInfo> appWidgets = new ArrayList<ItemInfo>(sAppWidgets);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (ItemInfo item : workspaceItems) {
+ item.unbind();
+ }
+ for (ItemInfo item : appWidgets) {
+ item.unbind();
+ }
+ }
+ });
+
+ return workspaceItems;
}
/**
@@ -258,35 +218,35 @@
public void run() {
cr.update(uri, values, null, null);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
- ItemInfo modelItem = sBgItemsIdMap.get(itemId);
- if (item != modelItem) {
- // the modelItem needs to match up perfectly with item if our model is to be
- // consistent with the database-- for now, just require modelItem == item
- String msg = "item: " + ((item != null) ? item.toString() : "null") +
- "modelItem: " + ((modelItem != null) ? modelItem.toString() : "null") +
- "Error: ItemInfo passed to " + callingFunction + " doesn't match " +
- "original";
- throw new RuntimeException(msg);
- }
+ ItemInfo modelItem = sItemsIdMap.get(itemId);
+ if (item != modelItem) {
+ // the modelItem needs to match up perfectly with item if our model is to be
+ // consistent with the database-- for now, just require modelItem == item
+ String msg = "item: " + ((item != null) ? item.toString() : "null") +
+ "modelItem: " + ((modelItem != null) ? modelItem.toString() : "null") +
+ "Error: ItemInfo passed to " + callingFunction + " doesn't match original";
+ throw new RuntimeException(msg);
+ }
- // Items are added/removed from the corresponding FolderInfo elsewhere, such
- // as in Workspace.onDrop. Here, we just add/remove them from the list of items
- // that are on the desktop, as appropriate
- if (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
- modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- if (!sBgWorkspaceItems.contains(modelItem)) {
- sBgWorkspaceItems.add(modelItem);
-
- }
- } else {
- sBgWorkspaceItems.remove(modelItem);
+ // Items are added/removed from the corresponding FolderInfo elsewhere, such
+ // as in Workspace.onDrop. Here, we just add/remove them from the list of items
+ // that are on the desktop, as appropriate
+ if (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
+ modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ if (!sWorkspaceItems.contains(modelItem)) {
+ sWorkspaceItems.add(modelItem);
}
+ } else {
+ sWorkspaceItems.remove(modelItem);
}
}
};
- runOnWorkerThread(r);
+
+ if (sWorkerThread.getThreadId() == Process.myTid()) {
+ r.run();
+ } else {
+ sWorker.post(r);
+ }
}
/**
@@ -490,33 +450,36 @@
public void run() {
cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
- if (sBgItemsIdMap.containsKey(item.id)) {
- // we should not be adding new items in the db with the same id
- throw new RuntimeException("Error: ItemInfo id (" + item.id + ") passed to " +
- "addItemToDatabase already exists." + item.toString());
- }
- sBgItemsIdMap.put(item.id, item);
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- sBgFolders.put(item.id, (FolderInfo) item);
- // Fall through
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
- item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- sBgWorkspaceItems.add(item);
- }
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- sBgAppWidgets.add((LauncherAppWidgetInfo) item);
- break;
- }
+
+ if (sItemsIdMap.containsKey(item.id)) {
+ // we should not be adding new items in the db with the same id
+ throw new RuntimeException("Error: ItemInfo id (" + item.id + ") passed to " +
+ "addItemToDatabase already exists." + item.toString());
+ }
+ sItemsIdMap.put(item.id, item);
+ switch (item.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ sFolders.put(item.id, (FolderInfo) item);
+ // Fall through
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
+ item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ sWorkspaceItems.add(item);
+ }
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ sAppWidgets.add((LauncherAppWidgetInfo) item);
+ break;
}
}
};
- runOnWorkerThread(r);
+
+ if (sWorkerThread.getThreadId() == Process.myTid()) {
+ r.run();
+ } else {
+ sWorker.post(r);
+ }
}
/**
@@ -556,27 +519,28 @@
Runnable r = new Runnable() {
public void run() {
cr.delete(uriToDelete, null, null);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- sBgFolders.remove(item.id);
- sBgWorkspaceItems.remove(item);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- sBgWorkspaceItems.remove(item);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- sBgAppWidgets.remove((LauncherAppWidgetInfo) item);
- break;
- }
- sBgItemsIdMap.remove(item.id);
- sBgDbIconCache.remove(item);
+ switch (item.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ sFolders.remove(item.id);
+ sWorkspaceItems.remove(item);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ sWorkspaceItems.remove(item);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ sAppWidgets.remove((LauncherAppWidgetInfo) item);
+ break;
}
+ sItemsIdMap.remove(item.id);
+ sDbIconCache.remove(item);
}
};
- runOnWorkerThread(r);
+ if (sWorkerThread.getThreadId() == Process.myTid()) {
+ r.run();
+ } else {
+ sWorker.post(r);
+ }
}
/**
@@ -588,26 +552,24 @@
Runnable r = new Runnable() {
public void run() {
cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
- sBgItemsIdMap.remove(info.id);
- sBgFolders.remove(info.id);
- sBgDbIconCache.remove(info);
- sBgWorkspaceItems.remove(info);
- }
+ sItemsIdMap.remove(info.id);
+ sFolders.remove(info.id);
+ sDbIconCache.remove(info);
+ sWorkspaceItems.remove(info);
cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
- // Lock on mBgLock *after* the db operation
- synchronized (sBgLock) {
- for (ItemInfo childInfo : info.contents) {
- sBgItemsIdMap.remove(childInfo.id);
- sBgDbIconCache.remove(childInfo);
- }
+ for (ItemInfo childInfo : info.contents) {
+ sItemsIdMap.remove(childInfo.id);
+ sDbIconCache.remove(childInfo);
}
}
};
- runOnWorkerThread(r);
+ if (sWorkerThread.getThreadId() == Process.myTid()) {
+ r.run();
+ } else {
+ sWorker.post(r);
+ }
}
/**
@@ -735,7 +697,7 @@
}
}
if (runLoader) {
- startLoader(false, -1);
+ startLoader(false);
}
}
@@ -753,42 +715,24 @@
return isLaunching;
}
- public void startLoader(boolean isLaunching, int synchronousBindPage) {
+ public void startLoader(boolean isLaunching) {
synchronized (mLock) {
if (DEBUG_LOADERS) {
Log.d(TAG, "startLoader isLaunching=" + isLaunching);
}
- // Clear any deferred bind-runnables from the synchronized load process
- // We must do this before any loading/binding is scheduled below.
- mDeferredBindRunnables.clear();
-
// Don't bother to start the thread if we know it's not going to do anything
if (mCallbacks != null && mCallbacks.get() != null) {
// If there is already one running, tell it to stop.
// also, don't downgrade isLaunching if we're already running
isLaunching = isLaunching || stopLoaderLocked();
mLoaderTask = new LoaderTask(mApp, isLaunching);
- if (synchronousBindPage > -1 && mAllAppsLoaded && mWorkspaceLoaded) {
- mLoaderTask.runBindSynchronousPage(synchronousBindPage);
- } else {
- sWorkerThread.setPriority(Thread.NORM_PRIORITY);
- sWorker.post(mLoaderTask);
- }
+ sWorkerThread.setPriority(Thread.NORM_PRIORITY);
+ sWorker.post(mLoaderTask);
}
}
}
- void bindRemainingSynchronousPages() {
- // Post the remaining side pages to be loaded
- if (!mDeferredBindRunnables.isEmpty()) {
- for (final Runnable r : mDeferredBindRunnables) {
- mHandler.post(r);
- }
- mDeferredBindRunnables.clear();
- }
- }
-
public void stopLoader() {
synchronized (mLock) {
if (mLoaderTask != null) {
@@ -818,11 +762,11 @@
*/
private class LoaderTask implements Runnable {
private Context mContext;
+ private Thread mWaitThread;
private boolean mIsLaunching;
private boolean mIsLoadingAndBindingWorkspace;
private boolean mStopped;
private boolean mLoadAndBindStepFinished;
-
private HashMap<Object, CharSequence> mLabelCache;
LoaderTask(Context context, boolean isLaunching) {
@@ -858,7 +802,7 @@
}
// Bind the workspace
- bindWorkspace(-1);
+ bindWorkspace();
}
private void waitForIdle() {
@@ -895,41 +839,7 @@
}
}
- void runBindSynchronousPage(int synchronousBindPage) {
- if (synchronousBindPage < 0) {
- // Ensure that we have a valid page index to load synchronously
- throw new RuntimeException("Should not call runBindSynchronousPage() without " +
- "valid page index");
- }
- if (!mAllAppsLoaded || !mWorkspaceLoaded) {
- // Ensure that we don't try and bind a specified page when the pages have not been
- // loaded already (we should load everything asynchronously in that case)
- throw new RuntimeException("Expecting AllApps and Workspace to be loaded");
- }
- synchronized (mLock) {
- if (mIsLoaderTaskRunning) {
- // Ensure that we are never running the background loading at this point since
- // we also touch the background collections
- throw new RuntimeException("Error! Background loading is already running");
- }
- }
-
- // XXX: Throw an exception if we are already loading (since we touch the worker thread
- // data structures, we can't allow any other thread to touch that data, but because
- // this call is synchronous, we can get away with not locking).
-
- // Divide the set of loaded items into those that we are binding synchronously, and
- // everything else that is to be bound normally (asynchronously).
- bindWorkspace(synchronousBindPage);
- // XXX: For now, continue posting the binding of AllApps as there are other issues that
- // arise from that.
- onlyBindAllApps();
- }
-
public void run() {
- synchronized (mLock) {
- mIsLoaderTaskRunning = true;
- }
// 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).
@@ -985,12 +895,10 @@
// Update the saved icons if necessary
if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");
- synchronized (sBgLock) {
- for (Object key : sBgDbIconCache.keySet()) {
- updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));
- }
- sBgDbIconCache.clear();
+ for (Object key : sDbIconCache.keySet()) {
+ updateSavedIcon(mContext, (ShortcutInfo) key, sDbIconCache.get(key));
}
+ sDbIconCache.clear();
// Clear out this reference, otherwise we end up holding it until all of the
// callback runnables are done.
@@ -1001,7 +909,6 @@
if (mLoaderTask == this) {
mLoaderTask = null;
}
- mIsLoaderTaskRunning = false;
}
}
@@ -1101,365 +1008,278 @@
// Make sure the default workspace is loaded, if needed
mApp.getLauncherProvider().loadDefaultFavoritesIfNecessary();
- synchronized (sBgLock) {
- sBgWorkspaceItems.clear();
- sBgAppWidgets.clear();
- sBgFolders.clear();
- sBgItemsIdMap.clear();
- sBgDbIconCache.clear();
+ sWorkspaceItems.clear();
+ sAppWidgets.clear();
+ sFolders.clear();
+ sItemsIdMap.clear();
+ sDbIconCache.clear();
- final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
+ final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
- final Cursor c = contentResolver.query(
- LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
+ final Cursor c = contentResolver.query(
+ LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
- // +1 for the hotseat (it can be larger than the workspace)
- // Load workspace in reverse order to ensure that latest items are loaded first (and
- // before any earlier duplicates)
- final ItemInfo occupied[][][] =
- new ItemInfo[Launcher.SCREEN_COUNT + 1][mCellCountX + 1][mCellCountY + 1];
+ // +1 for the hotseat (it can be larger than the workspace)
+ // Load workspace in reverse order to ensure that latest items are loaded first (and
+ // before any earlier duplicates)
+ final ItemInfo occupied[][][] =
+ new ItemInfo[Launcher.SCREEN_COUNT + 1][mCellCountX + 1][mCellCountY + 1];
- try {
- final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
- final int intentIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.INTENT);
- final int titleIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.TITLE);
- final int iconTypeIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.ICON_TYPE);
- final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
- final int iconPackageIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.ICON_PACKAGE);
- final int iconResourceIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.ICON_RESOURCE);
- final int containerIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.CONTAINER);
- final int itemTypeIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.ITEM_TYPE);
- final int appWidgetIdIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.APPWIDGET_ID);
- final int screenIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.CELLY);
- final int spanXIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.SPANX);
- final int spanYIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.SPANY);
- //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
- //final int displayModeIndex = c.getColumnIndexOrThrow(
- // LauncherSettings.Favorites.DISPLAY_MODE);
+ try {
+ final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
+ final int intentIndex = c.getColumnIndexOrThrow
+ (LauncherSettings.Favorites.INTENT);
+ final int titleIndex = c.getColumnIndexOrThrow
+ (LauncherSettings.Favorites.TITLE);
+ final int iconTypeIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.ICON_TYPE);
+ final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
+ final int iconPackageIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.ICON_PACKAGE);
+ final int iconResourceIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.ICON_RESOURCE);
+ final int containerIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.CONTAINER);
+ final int itemTypeIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.ITEM_TYPE);
+ final int appWidgetIdIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.APPWIDGET_ID);
+ final int screenIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.SCREEN);
+ final int cellXIndex = c.getColumnIndexOrThrow
+ (LauncherSettings.Favorites.CELLX);
+ final int cellYIndex = c.getColumnIndexOrThrow
+ (LauncherSettings.Favorites.CELLY);
+ final int spanXIndex = c.getColumnIndexOrThrow
+ (LauncherSettings.Favorites.SPANX);
+ final int spanYIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.SPANY);
+ //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
+ //final int displayModeIndex = c.getColumnIndexOrThrow(
+ // LauncherSettings.Favorites.DISPLAY_MODE);
- ShortcutInfo info;
- String intentDescription;
- LauncherAppWidgetInfo appWidgetInfo;
- int container;
- long id;
- Intent intent;
+ ShortcutInfo info;
+ String intentDescription;
+ LauncherAppWidgetInfo appWidgetInfo;
+ int container;
+ long id;
+ Intent intent;
- while (!mStopped && c.moveToNext()) {
- try {
- int itemType = c.getInt(itemTypeIndex);
+ while (!mStopped && c.moveToNext()) {
+ try {
+ int itemType = c.getInt(itemTypeIndex);
- switch (itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- intentDescription = c.getString(intentIndex);
- try {
- intent = Intent.parseUri(intentDescription, 0);
- } catch (URISyntaxException e) {
- continue;
- }
+ switch (itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ intentDescription = c.getString(intentIndex);
+ try {
+ intent = Intent.parseUri(intentDescription, 0);
+ } catch (URISyntaxException e) {
+ continue;
+ }
- if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = getShortcutInfo(manager, intent, context, c, iconIndex,
- titleIndex, mLabelCache);
- } else {
- info = getShortcutInfo(c, context, iconTypeIndex,
- iconPackageIndex, iconResourceIndex, iconIndex,
- titleIndex);
+ if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+ info = getShortcutInfo(manager, intent, context, c, iconIndex,
+ titleIndex, mLabelCache);
+ } else {
+ info = getShortcutInfo(c, context, iconTypeIndex,
+ iconPackageIndex, iconResourceIndex, iconIndex,
+ titleIndex);
- // App shortcuts that used to be automatically added to Launcher
- // didn't always have the correct intent flags set, so do that
- // here
- if (intent.getAction() != null &&
+ // App shortcuts that used to be automatically added to Launcher
+ // didn't always have the correct intent flags set, so do that here
+ if (intent.getAction() != null &&
intent.getCategories() != null &&
intent.getAction().equals(Intent.ACTION_MAIN) &&
intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- intent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
}
+ }
- if (info != null) {
- info.intent = intent;
- info.id = c.getLong(idIndex);
- container = c.getInt(containerIndex);
- info.container = container;
- info.screen = c.getInt(screenIndex);
- info.cellX = c.getInt(cellXIndex);
- info.cellY = c.getInt(cellYIndex);
-
- // check & update map of what's occupied
- if (!checkItemPlacement(occupied, info)) {
- break;
- }
-
- switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
- sBgWorkspaceItems.add(info);
- break;
- default:
- // Item is in a user folder
- FolderInfo folderInfo =
- findOrMakeFolder(sBgFolders, container);
- folderInfo.add(info);
- break;
- }
- sBgItemsIdMap.put(info.id, info);
-
- // now that we've loaded everthing re-save it with the
- // icon in case it disappears somehow.
- queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);
- } else {
- // Failed to load the shortcut, probably because the
- // activity manager couldn't resolve it (maybe the app
- // was uninstalled), or the db row was somehow screwed up.
- // Delete it.
- id = c.getLong(idIndex);
- Log.e(TAG, "Error loading shortcut " + id + ", removing it");
- contentResolver.delete(LauncherSettings.Favorites.getContentUri(
- id, false), null, null);
- }
- break;
-
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- id = c.getLong(idIndex);
- FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);
-
- folderInfo.title = c.getString(titleIndex);
- folderInfo.id = id;
+ if (info != null) {
+ info.intent = intent;
+ info.id = c.getLong(idIndex);
container = c.getInt(containerIndex);
- folderInfo.container = container;
- folderInfo.screen = c.getInt(screenIndex);
- folderInfo.cellX = c.getInt(cellXIndex);
- folderInfo.cellY = c.getInt(cellYIndex);
+ info.container = container;
+ info.screen = c.getInt(screenIndex);
+ info.cellX = c.getInt(cellXIndex);
+ info.cellY = c.getInt(cellYIndex);
// check & update map of what's occupied
- if (!checkItemPlacement(occupied, folderInfo)) {
+ if (!checkItemPlacement(occupied, info)) {
break;
}
+
switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
- sBgWorkspaceItems.add(folderInfo);
- break;
+ case LauncherSettings.Favorites.CONTAINER_DESKTOP:
+ case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
+ sWorkspaceItems.add(info);
+ break;
+ default:
+ // Item is in a user folder
+ FolderInfo folderInfo =
+ findOrMakeFolder(sFolders, container);
+ folderInfo.add(info);
+ break;
}
+ sItemsIdMap.put(info.id, info);
- sBgItemsIdMap.put(folderInfo.id, folderInfo);
- sBgFolders.put(folderInfo.id, folderInfo);
- break;
-
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- // Read all Launcher-specific widget details
- int appWidgetId = c.getInt(appWidgetIdIndex);
+ // now that we've loaded everthing re-save it with the
+ // icon in case it disappears somehow.
+ queueIconToBeChecked(sDbIconCache, info, c, iconIndex);
+ } else {
+ // Failed to load the shortcut, probably because the
+ // activity manager couldn't resolve it (maybe the app
+ // was uninstalled), or the db row was somehow screwed up.
+ // Delete it.
id = c.getLong(idIndex);
+ Log.e(TAG, "Error loading shortcut " + id + ", removing it");
+ contentResolver.delete(LauncherSettings.Favorites.getContentUri(
+ id, false), null, null);
+ }
+ break;
- final AppWidgetProviderInfo provider =
- widgets.getAppWidgetInfo(appWidgetId);
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ id = c.getLong(idIndex);
+ FolderInfo folderInfo = findOrMakeFolder(sFolders, id);
- if (!isSafeMode && (provider == null || provider.provider == null ||
- provider.provider.getPackageName() == null)) {
- String log = "Deleting widget that isn't installed anymore: id="
- + id + " appWidgetId=" + appWidgetId;
- Log.e(TAG, log);
- Launcher.sDumpLogs.add(log);
- itemsToRemove.add(id);
- } else {
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
- provider.provider);
- appWidgetInfo.id = id;
- appWidgetInfo.screen = c.getInt(screenIndex);
- appWidgetInfo.cellX = c.getInt(cellXIndex);
- appWidgetInfo.cellY = c.getInt(cellYIndex);
- appWidgetInfo.spanX = c.getInt(spanXIndex);
- appWidgetInfo.spanY = c.getInt(spanYIndex);
- int[] minSpan = Launcher.getMinSpanForWidget(context, provider);
- appWidgetInfo.minSpanX = minSpan[0];
- appWidgetInfo.minSpanY = minSpan[1];
+ folderInfo.title = c.getString(titleIndex);
+ folderInfo.id = id;
+ container = c.getInt(containerIndex);
+ folderInfo.container = container;
+ folderInfo.screen = c.getInt(screenIndex);
+ folderInfo.cellX = c.getInt(cellXIndex);
+ folderInfo.cellY = c.getInt(cellYIndex);
- container = c.getInt(containerIndex);
- if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- Log.e(TAG, "Widget found where container != " +
- "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
- continue;
- }
- appWidgetInfo.container = c.getInt(containerIndex);
-
- // check & update map of what's occupied
- if (!checkItemPlacement(occupied, appWidgetInfo)) {
- break;
- }
- sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
- sBgAppWidgets.add(appWidgetInfo);
- }
+ // check & update map of what's occupied
+ if (!checkItemPlacement(occupied, folderInfo)) {
break;
}
- } catch (Exception e) {
- Log.w(TAG, "Desktop items loading interrupted:", e);
- }
- }
- } finally {
- c.close();
- }
-
- if (itemsToRemove.size() > 0) {
- ContentProviderClient client = contentResolver.acquireContentProviderClient(
- LauncherSettings.Favorites.CONTENT_URI);
- // Remove dead items
- for (long id : itemsToRemove) {
- if (DEBUG_LOADERS) {
- Log.d(TAG, "Removed id = " + id);
- }
- // Don't notify content observers
- try {
- client.delete(LauncherSettings.Favorites.getContentUri(id, false),
- null, null);
- } catch (RemoteException e) {
- Log.w(TAG, "Could not remove id = " + id);
- }
- }
- }
-
- if (DEBUG_LOADERS) {
- Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");
- Log.d(TAG, "workspace layout: ");
- for (int y = 0; y < mCellCountY; y++) {
- String line = "";
- for (int s = 0; s < Launcher.SCREEN_COUNT; s++) {
- if (s > 0) {
- line += " | ";
+ switch (container) {
+ case LauncherSettings.Favorites.CONTAINER_DESKTOP:
+ case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
+ sWorkspaceItems.add(folderInfo);
+ break;
}
- for (int x = 0; x < mCellCountX; x++) {
- line += ((occupied[s][x][y] != null) ? "#" : ".");
+
+ sItemsIdMap.put(folderInfo.id, folderInfo);
+ sFolders.put(folderInfo.id, folderInfo);
+ break;
+
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ // Read all Launcher-specific widget details
+ int appWidgetId = c.getInt(appWidgetIdIndex);
+ id = c.getLong(idIndex);
+
+ final AppWidgetProviderInfo provider =
+ widgets.getAppWidgetInfo(appWidgetId);
+
+ if (!isSafeMode && (provider == null || provider.provider == null ||
+ provider.provider.getPackageName() == null)) {
+ String log = "Deleting widget that isn't installed anymore: id="
+ + id + " appWidgetId=" + appWidgetId;
+ Log.e(TAG, log);
+ Launcher.sDumpLogs.add(log);
+ itemsToRemove.add(id);
+ } else {
+ appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
+ provider.provider);
+ appWidgetInfo.id = id;
+ appWidgetInfo.screen = c.getInt(screenIndex);
+ appWidgetInfo.cellX = c.getInt(cellXIndex);
+ appWidgetInfo.cellY = c.getInt(cellYIndex);
+ appWidgetInfo.spanX = c.getInt(spanXIndex);
+ appWidgetInfo.spanY = c.getInt(spanYIndex);
+ int[] minSpan = Launcher.getMinSpanForWidget(context, provider);
+ appWidgetInfo.minSpanX = minSpan[0];
+ appWidgetInfo.minSpanY = minSpan[1];
+
+ container = c.getInt(containerIndex);
+ if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
+ container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ Log.e(TAG, "Widget found where container "
+ + "!= CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
+ continue;
+ }
+ appWidgetInfo.container = c.getInt(containerIndex);
+
+ // check & update map of what's occupied
+ if (!checkItemPlacement(occupied, appWidgetInfo)) {
+ break;
+ }
+ sItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
+ sAppWidgets.add(appWidgetInfo);
}
+ break;
}
- Log.d(TAG, "[ " + line + " ]");
+ } catch (Exception e) {
+ Log.w(TAG, "Desktop items loading interrupted:", e);
+ }
+ }
+ } finally {
+ c.close();
+ }
+
+ if (itemsToRemove.size() > 0) {
+ ContentProviderClient client = contentResolver.acquireContentProviderClient(
+ LauncherSettings.Favorites.CONTENT_URI);
+ // Remove dead items
+ for (long id : itemsToRemove) {
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "Removed id = " + id);
+ }
+ // Don't notify content observers
+ try {
+ client.delete(LauncherSettings.Favorites.getContentUri(id, false),
+ null, null);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not remove id = " + id);
}
}
}
- }
- /** Filters the set of items who are directly or indirectly (via another container) on the
- * specified screen. */
- private void filterCurrentWorkspaceItems(int currentScreen,
- ArrayList<ItemInfo> allWorkspaceItems,
- ArrayList<ItemInfo> currentScreenItems,
- ArrayList<ItemInfo> otherScreenItems) {
- // Purge any null ItemInfos
- Iterator<ItemInfo> iter = allWorkspaceItems.iterator();
- while (iter.hasNext()) {
- ItemInfo i = iter.next();
- if (i == null) {
- iter.remove();
- }
- }
-
- // If we aren't filtering on a screen, then the set of items to load is the full set of
- // items given.
- if (currentScreen < 0) {
- currentScreenItems.addAll(allWorkspaceItems);
- }
-
- // Order the set of items by their containers first, this allows use to walk through the
- // list sequentially, build up a list of containers that are in the specified screen,
- // as well as all items in those containers.
- Set<Long> itemsOnScreen = new HashSet<Long>();
- Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {
- @Override
- public int compare(ItemInfo lhs, ItemInfo rhs) {
- return (int) (lhs.container - rhs.container);
- }
- });
- for (ItemInfo info : allWorkspaceItems) {
- if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- if (info.screen == currentScreen) {
- currentScreenItems.add(info);
- itemsOnScreen.add(info.id);
- } else {
- otherScreenItems.add(info);
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");
+ Log.d(TAG, "workspace layout: ");
+ for (int y = 0; y < mCellCountY; y++) {
+ String line = "";
+ for (int s = 0; s < Launcher.SCREEN_COUNT; s++) {
+ if (s > 0) {
+ line += " | ";
+ }
+ for (int x = 0; x < mCellCountX; x++) {
+ line += ((occupied[s][x][y] != null) ? "#" : ".");
+ }
}
- } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- currentScreenItems.add(info);
- itemsOnScreen.add(info.id);
- } else {
- if (itemsOnScreen.contains(info.container)) {
- currentScreenItems.add(info);
- itemsOnScreen.add(info.id);
- } else {
- otherScreenItems.add(info);
- }
+ Log.d(TAG, "[ " + line + " ]");
}
}
}
- /** Filters the set of widgets which are on the specified screen. */
- private void filterCurrentAppWidgets(int currentScreen,
- ArrayList<LauncherAppWidgetInfo> appWidgets,
- ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,
- ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {
- // If we aren't filtering on a screen, then the set of items to load is the full set of
- // widgets given.
- if (currentScreen < 0) {
- currentScreenWidgets.addAll(appWidgets);
+ /**
+ * Read everything out of our database.
+ */
+ private void bindWorkspace() {
+ final long t = SystemClock.uptimeMillis();
+
+ // 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");
+ return;
}
- for (LauncherAppWidgetInfo widget : appWidgets) {
- if (widget == null) continue;
- if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- widget.screen == currentScreen) {
- currentScreenWidgets.add(widget);
- } else {
- otherScreenWidgets.add(widget);
- }
- }
- }
-
- /** Filters the set of folders which are on the specified screen. */
- private void filterCurrentFolders(int currentScreen,
- HashMap<Long, ItemInfo> itemsIdMap,
- HashMap<Long, FolderInfo> folders,
- HashMap<Long, FolderInfo> currentScreenFolders,
- HashMap<Long, FolderInfo> otherScreenFolders) {
- // If we aren't filtering on a screen, then the set of items to load is the full set of
- // widgets given.
- if (currentScreen < 0) {
- currentScreenFolders.putAll(folders);
- }
-
- for (long id : folders.keySet()) {
- ItemInfo info = itemsIdMap.get(id);
- FolderInfo folder = folders.get(id);
- if (info == null || folder == null) continue;
- if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- info.screen == currentScreen) {
- currentScreenFolders.put(id, folder);
- } else {
- otherScreenFolders.put(id, folder);
- }
- }
- }
-
- /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to
- * right) */
- private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {
- // XXX: review this
- Collections.sort(workspaceItems, new Comparator<ItemInfo>() {
+ // Get the list of workspace items to load and unbind the existing ShortcutInfos
+ // before we call startBinding() below.
+ final int currentScreen = oldCallbacks.getCurrentWorkspaceScreen();
+ final ArrayList<ItemInfo> tmpWorkspaceItems = unbindWorkspaceItemsOnMainThread();
+ // Order the items for loading as follows: current workspace, hotseat, everything else
+ Collections.sort(tmpWorkspaceItems, new Comparator<ItemInfo>() {
@Override
public int compare(ItemInfo lhs, ItemInfo rhs) {
int cellCountX = LauncherModel.getCellCountX();
@@ -1473,155 +1293,108 @@
return (int) (lr - rr);
}
});
- }
-
- private void bindWorkspaceItems(final Callbacks oldCallbacks,
- final ArrayList<ItemInfo> workspaceItems,
- final ArrayList<LauncherAppWidgetInfo> appWidgets,
- final HashMap<Long, FolderInfo> folders,
- ArrayList<Runnable> deferredBindRunnables) {
-
- final boolean postOnMainThread = (deferredBindRunnables != null);
-
- // Bind the workspace items
- int N = workspaceItems.size();
- for (int i = 0; i < N; i += ITEMS_CHUNK) {
- final int start = i;
- final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);
- final Runnable r = new Runnable() {
- @Override
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.bindItems(workspaceItems, start, start+chunkSize);
- }
- }
- };
- if (postOnMainThread) {
- deferredBindRunnables.add(r);
+ // Precondition: the items are ordered by page, screen
+ final ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();
+ for (ItemInfo ii : tmpWorkspaceItems) {
+ // Prepend the current items, hotseat items, append everything else
+ if (ii.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
+ ii.screen == currentScreen) {
+ workspaceItems.add(0, ii);
+ } else if (ii.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ workspaceItems.add(0, ii);
} else {
- runOnMainThread(r);
+ workspaceItems.add(ii);
}
}
- // Bind the folders
- if (!folders.isEmpty()) {
- final Runnable r = new Runnable() {
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.bindFolders(folders);
- }
- }
- };
- if (postOnMainThread) {
- deferredBindRunnables.add(r);
- } else {
- runOnMainThread(r);
- }
- }
-
- // Bind the widgets, one at a time
- N = appWidgets.size();
- for (int i = 0; i < N; i++) {
- final LauncherAppWidgetInfo widget = appWidgets.get(i);
- final Runnable r = new Runnable() {
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.bindAppWidget(widget);
- }
- }
- };
- if (postOnMainThread) {
- deferredBindRunnables.add(r);
- } else {
- runOnMainThread(r);
- }
- }
- }
-
- /**
- * Binds all loaded data to actual views on the main thread.
- */
- private void bindWorkspace(int synchronizeBindPage) {
- final long t = SystemClock.uptimeMillis();
- Runnable r;
-
- // 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");
- return;
- }
-
- final int currentScreen = (synchronizeBindPage > -1) ? synchronizeBindPage :
- oldCallbacks.getCurrentWorkspaceScreen();
-
- // Load all the items that are on the current page first (and in the process, unbind
- // all the existing workspace items before we call startBinding() below.
- unbindWorkspaceItemsOnMainThread();
- ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();
- ArrayList<LauncherAppWidgetInfo> appWidgets =
- new ArrayList<LauncherAppWidgetInfo>();
- HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();
- HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();
- synchronized (sBgLock) {
- workspaceItems.addAll(sBgWorkspaceItems);
- appWidgets.addAll(sBgAppWidgets);
- folders.putAll(sBgFolders);
- itemsIdMap.putAll(sBgItemsIdMap);
- }
-
- ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();
- ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();
- ArrayList<LauncherAppWidgetInfo> currentAppWidgets =
- new ArrayList<LauncherAppWidgetInfo>();
- ArrayList<LauncherAppWidgetInfo> otherAppWidgets =
- new ArrayList<LauncherAppWidgetInfo>();
- HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();
- HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();
-
- // Separate the items that are on the current screen, and all the other remaining items
- filterCurrentWorkspaceItems(currentScreen, workspaceItems, currentWorkspaceItems,
- otherWorkspaceItems);
- filterCurrentAppWidgets(currentScreen, appWidgets, currentAppWidgets,
- otherAppWidgets);
- filterCurrentFolders(currentScreen, itemsIdMap, folders, currentFolders,
- otherFolders);
- sortWorkspaceItemsSpatially(currentWorkspaceItems);
- sortWorkspaceItemsSpatially(otherWorkspaceItems);
-
- // Tell the workspace that we're about to start binding items
- r = new Runnable() {
+ // Tell the workspace that we're about to start firing items at it
+ mHandler.post(new Runnable() {
public void run() {
Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.startBinding();
}
}
- };
- runOnMainThread(r);
+ });
- // Load items on the current page
- bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,
- currentFolders, null);
-
- // Load all the remaining pages
- mDeferredBindRunnables.clear();
- bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,
- mDeferredBindRunnables);
-
- // Tell the workspace that we're done binding items
- r = new Runnable() {
+ // Add the items to the workspace.
+ int N = workspaceItems.size();
+ for (int i=0; i<N; i+=ITEMS_CHUNK) {
+ final int start = i;
+ final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);
+ mHandler.post(new Runnable() {
+ public void run() {
+ Callbacks callbacks = tryGetCallbacks(oldCallbacks);
+ if (callbacks != null) {
+ callbacks.bindItems(workspaceItems, start, start+chunkSize);
+ }
+ }
+ });
+ }
+ // Ensure that we don't use the same folders data structure on the main thread
+ final HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>(sFolders);
+ mHandler.post(new Runnable() {
+ public void run() {
+ Callbacks callbacks = tryGetCallbacks(oldCallbacks);
+ if (callbacks != null) {
+ callbacks.bindFolders(folders);
+ }
+ }
+ });
+ // Wait until the queue goes empty.
+ mHandler.post(new Runnable() {
+ public void run() {
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "Going to start binding widgets soon.");
+ }
+ }
+ });
+ // Bind the widgets, one at a time.
+ // WARNING: this is calling into the workspace from the background thread,
+ // but since getCurrentScreen() just returns the int, we should be okay. This
+ // is just a hint for the order, and if it's wrong, we'll be okay.
+ // TODO: instead, we should have that push the current screen into here.
+ N = sAppWidgets.size();
+ // once for the current screen
+ for (int i=0; i<N; i++) {
+ final LauncherAppWidgetInfo widget = sAppWidgets.get(i);
+ if (widget.screen == currentScreen) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ Callbacks callbacks = tryGetCallbacks(oldCallbacks);
+ if (callbacks != null) {
+ callbacks.bindAppWidget(widget);
+ }
+ }
+ });
+ }
+ }
+ // once for the other screens
+ for (int i=0; i<N; i++) {
+ final LauncherAppWidgetInfo widget = sAppWidgets.get(i);
+ if (widget.screen != currentScreen) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ Callbacks callbacks = tryGetCallbacks(oldCallbacks);
+ if (callbacks != null) {
+ callbacks.bindAppWidget(widget);
+ }
+ }
+ });
+ }
+ }
+ // Tell the workspace that we're done.
+ mHandler.post(new Runnable() {
public void run() {
Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.finishBindingItems();
}
-
+ }
+ });
+ // Cleanup
+ mHandler.post(new Runnable() {
+ public void run() {
// If we're profiling, ensure this is the last thing in the queue.
if (DEBUG_LOADERS) {
Log.d(TAG, "bound workspace in "
@@ -1630,8 +1403,7 @@
mIsLoadingAndBindingWorkspace = false;
}
- };
- mDeferredBindRunnables.add(r);
+ });
}
private void loadAndBindAllApps() {
@@ -1676,6 +1448,7 @@
}
}
});
+
}
private void loadAllAppsByBatch() {
@@ -1793,13 +1566,12 @@
}
public void dumpState() {
- synchronized (sBgLock) {
- Log.d(TAG, "mLoaderTask.mContext=" + mContext);
- Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);
- Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
- Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
- Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());
- }
+ 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);
+ Log.d(TAG, "mItems size=" + sWorkspaceItems.size());
}
}
@@ -1930,13 +1702,11 @@
*/
ArrayList<ShortcutInfo> getShortcutInfosForPackage(String packageName) {
ArrayList<ShortcutInfo> infos = new ArrayList<ShortcutInfo>();
- synchronized (sBgLock) {
- for (ItemInfo i : sBgWorkspaceItems) {
- if (i instanceof ShortcutInfo) {
- ShortcutInfo info = (ShortcutInfo) i;
- if (packageName.equals(info.getPackageName())) {
- infos.add(info);
- }
+ for (ItemInfo i : sWorkspaceItems) {
+ if (i instanceof ShortcutInfo) {
+ ShortcutInfo info = (ShortcutInfo) i;
+ if (packageName.equals(info.getPackageName())) {
+ infos.add(info);
}
}
}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 331e86f..2d2340a 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -1329,14 +1329,6 @@
}
super.onDraw(canvas);
-
- // Call back to LauncherModel to finish binding after the first draw
- post(new Runnable() {
- @Override
- public void run() {
- mLauncher.getModel().bindRemainingSynchronousPages();
- }
- });
}
boolean isDrawingBackgroundGradient() {