summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorJoe Onorato <joeo@android.com>2009-08-17 11:03:03 -0400
committerJoe Onorato <joeo@android.com>2009-08-24 14:58:44 -0400
commit9c1289cb3bfb74f86e53ec7ac6dd76bb39666b2d (patch)
treebb6f3ea57e53ccf695bd7cf2e3db33786506be5c /src/com/android
parent02e638e6bf6dac903396a67029d4d48e3cfa87d9 (diff)
downloadandroid_packages_apps_Trebuchet-9c1289cb3bfb74f86e53ec7ac6dd76bb39666b2d.tar.gz
android_packages_apps_Trebuchet-9c1289cb3bfb74f86e53ec7ac6dd76bb39666b2d.tar.bz2
android_packages_apps_Trebuchet-9c1289cb3bfb74f86e53ec7ac6dd76bb39666b2d.zip
Redo the launcher loading code and put the real app icons into rollo.
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/launcher2/ActivityPicker.java2
-rw-r--r--src/com/android/launcher2/AllAppsList.java216
-rw-r--r--src/com/android/launcher2/AllAppsView.java93
-rw-r--r--src/com/android/launcher2/AppInfoCache.java174
-rw-r--r--src/com/android/launcher2/ApplicationInfo.java16
-rw-r--r--src/com/android/launcher2/ApplicationsAdapter.java4
-rw-r--r--src/com/android/launcher2/BubbleTextView.java13
-rw-r--r--src/com/android/launcher2/DeferredHandler.java104
-rw-r--r--src/com/android/launcher2/DeleteZone.java11
-rw-r--r--src/com/android/launcher2/DragController.java6
-rw-r--r--src/com/android/launcher2/FolderIcon.java2
-rw-r--r--src/com/android/launcher2/ItemInfo.java2
-rw-r--r--src/com/android/launcher2/Launcher.java707
-rw-r--r--src/com/android/launcher2/LauncherAppWidgetInfo.java7
-rw-r--r--src/com/android/launcher2/LauncherApplication.java61
-rw-r--r--src/com/android/launcher2/LauncherModel.java2101
-rw-r--r--src/com/android/launcher2/LiveFolderAdapter.java3
-rw-r--r--src/com/android/launcher2/LiveFolderIcon.java4
-rw-r--r--src/com/android/launcher2/UserFolderInfo.java2
-rw-r--r--src/com/android/launcher2/Utilities.java198
-rw-r--r--src/com/android/launcher2/Workspace.java41
21 files changed, 1922 insertions, 1845 deletions
diff --git a/src/com/android/launcher2/ActivityPicker.java b/src/com/android/launcher2/ActivityPicker.java
index f502e2728..b6da08e4b 100644
--- a/src/com/android/launcher2/ActivityPicker.java
+++ b/src/com/android/launcher2/ActivityPicker.java
@@ -402,4 +402,4 @@ public class ActivityPicker extends AlertActivity implements
return icon;
}
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java
new file mode 100644
index 000000000..4d3ee77ec
--- /dev/null
+++ b/src/com/android/launcher2/AllAppsList.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.launcher2;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.util.Log;
+import android.os.Process;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+
+/**
+ * Stores the list of all applications for the all apps view.
+ */
+class AllAppsList {
+ public static final int DEFAULT_APPLICATIONS_NUMBER = 42;
+
+ /** The list off all apps. */
+ public ArrayList<ApplicationInfo> data = new ArrayList(DEFAULT_APPLICATIONS_NUMBER);
+ /** The list of apps that have been added since the last notify() call. */
+ public ArrayList<ApplicationInfo> added = new ArrayList(DEFAULT_APPLICATIONS_NUMBER);
+ /** The list of apps that have been removed since the last notify() call. */
+ public ArrayList<ApplicationInfo> removed = new ArrayList();
+ /** The list of apps that have been modified since the last notify() call. */
+ public ArrayList<ApplicationInfo> modified = new ArrayList();
+
+ /**
+ * Boring constructor.
+ */
+ public AllAppsList() {
+ }
+
+ /**
+ * Add the supplied ApplicationInfo objects to the list, and enqueue it into the
+ * list to broadcast when notify() is called.
+ */
+ public void add(ApplicationInfo info) {
+ data.add(info);
+ added.add(info);
+ }
+
+ public void clear() {
+ data.clear();
+ // TODO: do we clear these too?
+ added.clear();
+ removed.clear();
+ modified.clear();
+ }
+
+ public int size() {
+ return data.size();
+ }
+
+ public ApplicationInfo get(int index) {
+ return data.get(index);
+ }
+
+ /**
+ * Add the icons for the supplied apk called packageName.
+ */
+ public void addPackage(Context context, String packageName) {
+ final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName);
+
+ if (matches.size() > 0) {
+ Utilities.BubbleText bubble = new Utilities.BubbleText(context);
+ for (ResolveInfo info : matches) {
+ ApplicationInfo item = AppInfoCache.cache(info, context, bubble);
+ data.add(item);
+ added.add(item);
+ }
+ }
+ }
+
+ /**
+ * Remove the apps for the given apk identified by packageName.
+ */
+ public void removePackage(String packageName) {
+ final List<ApplicationInfo> data = this.data;
+ for (int i=data.size()-1; i>=0; i--) {
+ ApplicationInfo info = data.get(i);
+ final ComponentName component = info.intent.getComponent();
+ if (packageName.equals(component.getPackageName())) {
+ removed.add(info);
+ data.remove(i);
+ }
+ }
+ // This is more aggressive than it needs to be.
+ AppInfoCache.flush();
+ }
+
+ /**
+ * Add and remove icons for this package which has been updated.
+ */
+ public void updatePackage(Context context, String packageName) {
+ final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName);
+ if (matches.size() > 0) {
+ // Find disabled/removed activities and remove them from data and add them
+ // to the removed list.
+ for (int i=data.size()-1; i>=0; i--) {
+ final ApplicationInfo applicationInfo = data.get(i);
+ final ComponentName component = applicationInfo.intent.getComponent();
+ if (packageName.equals(component.getPackageName())) {
+ if (!findActivity(matches, component)) {
+ removed.add(applicationInfo);
+ AppInfoCache.remove(component);
+ data.remove(i);
+ }
+ }
+ }
+
+ // Find enabled activities and add them to the adapter
+ // Also updates existing activities with new labels/icons
+ Utilities.BubbleText bubble = new Utilities.BubbleText(context);
+ int count = matches.size();
+ for (int i=0; i<count; i++) {
+ final ResolveInfo info = matches.get(i);
+ ApplicationInfo applicationInfo = findApplicationInfoLocked(
+ info.activityInfo.applicationInfo.packageName,
+ info.activityInfo.name);
+ if (applicationInfo == null) {
+ applicationInfo = AppInfoCache.cache(info, context, bubble);
+ data.add(applicationInfo);
+ added.add(applicationInfo);
+ } else {
+ AppInfoCache.update(info, applicationInfo, context);
+ modified.add(applicationInfo);
+ }
+ }
+ }
+ }
+
+ /**
+ * Query the package manager for MAIN/LAUNCHER activities in the supplied package.
+ */
+ private static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) {
+ final PackageManager packageManager = context.getPackageManager();
+
+ final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
+ final List<ResolveInfo> matches = new ArrayList<ResolveInfo>();
+
+ if (apps != null) {
+ // Find all activities that match the packageName
+ int count = apps.size();
+ for (int i = 0; i < count; i++) {
+ final ResolveInfo info = apps.get(i);
+ final ActivityInfo activityInfo = info.activityInfo;
+ if (packageName.equals(activityInfo.packageName)) {
+ matches.add(info);
+ }
+ }
+ }
+
+ return matches;
+ }
+
+ /**
+ * Returns whether <em>apps</em> contains <em>component</em>.
+ */
+ private static boolean findActivity(List<ResolveInfo> apps, ComponentName component) {
+ final String className = component.getClassName();
+ for (ResolveInfo info : apps) {
+ final ActivityInfo activityInfo = info.activityInfo;
+ if (activityInfo.name.equals(className)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Find an ApplicationInfo object for the given packageName and className.
+ */
+ private ApplicationInfo findApplicationInfoLocked(String packageName, String className) {
+ for (ApplicationInfo info: data) {
+ final ComponentName component = info.intent.getComponent();
+ if (packageName.equals(component.getPackageName())
+ && className.equals(component.getClassName())) {
+ return info;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
index 755ba65f4..dbb7564e1 100644
--- a/src/com/android/launcher2/AllAppsView.java
+++ b/src/com/android/launcher2/AllAppsView.java
@@ -59,8 +59,11 @@ import android.graphics.PixelFormat;
public class AllAppsView extends RSSurfaceView {
+ private static final String TAG = "Launcher.AllAppsView";
+
private RenderScript mRS;
private RolloRS mRollo;
+ private ArrayList<ApplicationInfo> mAllAppsList;
private ViewConfiguration mConfig;
private VelocityTracker mVelocity;
@@ -97,6 +100,9 @@ public class AllAppsView extends RSSurfaceView {
mRS = createRenderScript();
mRollo = new RolloRS();
mRollo.init(getResources(), w, h);
+ if (mAllAppsList != null) {
+ mRollo.setApps(mAllAppsList);
+ }
}
@Override
@@ -109,7 +115,6 @@ public class AllAppsView extends RSSurfaceView {
@Override
public boolean onTouchEvent(MotionEvent ev)
{
- Log.d(Launcher.LOG_TAG, "onTouchEvent " + ev);
int x = (int)ev.getX();
int deltaX;
switch (ev.getAction()) {
@@ -163,10 +168,17 @@ public class AllAppsView extends RSSurfaceView {
DataSetObserver mIconObserver = new DataSetObserver() {
public void onChanged() {
- Log.d(Launcher.LOG_TAG, "new icons arrived! now have " + mAdapter.getCount());
+ Log.d(TAG, "new icons arrived! now have " + mAdapter.getCount());
}
};
+ public void setApps(ArrayList<ApplicationInfo> list) {
+ mAllAppsList = list;
+ if (mRollo != null) {
+ mRollo.setApps(list);
+ }
+ }
+
public class RolloRS {
// Allocations ======
@@ -316,22 +328,9 @@ public class AllAppsView extends RSSurfaceView {
}
private void initData() {
- final int count = 100;
mParams = new Params(mRS);
mState = new State(mRS);
- mIcons = new Allocation[count];
- mAllocIconIDBuf = new int[count];
- mAllocIconID = Allocation.createSized(mRS,
- Element.USER_I32, mAllocIconIDBuf.length);
-
- mLabels = new Allocation[count];
- mAllocLabelIDBuf = new int[mLabels.length];
- mAllocLabelID = Allocation.createSized(mRS,
- Element.USER_I32, mLabels.length);
-
- Element ie8888 = Element.RGBA_8888;
-
final Utilities.BubbleText bubble = new Utilities.BubbleText(getContext());
mParams.bubbleWidth = bubble.getBubbleWidth();
@@ -339,25 +338,10 @@ public class AllAppsView extends RSSurfaceView {
mParams.bubbleBitmapWidth = bubble.getBitmapWidth();
mParams.bubbleBitmapHeight = bubble.getBitmapHeight();
- for (int i=0; i<count; i++) {
- mIcons[i] = Allocation.createFromBitmapResource(
- mRS, mRes, R.raw.maps, ie8888, true);
- mLabels[i] = makeTextBitmap(bubble, i%9==0 ? "Google Maps" : "Maps");
- }
-
- for (int i=0; i<count; i++) {
- mIcons[i].uploadToTexture(0);
- mLabels[i].uploadToTexture(0);
- mAllocIconIDBuf[i] = mIcons[i].getID();
- mAllocLabelIDBuf[i] = mLabels[i].getID();
- }
- mAllocIconID.data(mAllocIconIDBuf);
- mAllocLabelID.data(mAllocLabelIDBuf);
-
- mState.iconCount = count;
-
mParams.save();
mState.save();
+
+ setApps(null);
}
Allocation makeTextBitmap(Utilities.BubbleText bubble, String label) {
@@ -383,8 +367,51 @@ public class AllAppsView extends RSSurfaceView {
mRS.contextBindRootScript(mScript);
}
- }
+ private void setApps(ArrayList<ApplicationInfo> list) {
+ final int count = list != null ? list.size() : 0;
+ mIcons = new Allocation[count];
+ mAllocIconIDBuf = new int[count];
+ mAllocIconID = Allocation.createSized(mRS, Element.USER_I32, count);
+
+ mLabels = new Allocation[count];
+ mAllocLabelIDBuf = new int[count];
+ mAllocLabelID = Allocation.createSized(mRS, Element.USER_I32, count);
+
+ Element ie8888 = Element.RGBA_8888;
+
+ Utilities.BubbleText bubble = new Utilities.BubbleText(getContext());
+
+ for (int i=0; i<count; i++) {
+ final ApplicationInfo item = list.get(i);
+
+ mIcons[i] = Allocation.createFromBitmap(mRS, item.iconBitmap,
+ Element.RGBA_8888, true);
+ mLabels[i] = Allocation.createFromBitmap(mRS, item.titleBitmap,
+ Element.RGBA_8888, true);
+
+ mIcons[i].uploadToTexture(0);
+ mLabels[i].uploadToTexture(0);
+
+ mAllocIconIDBuf[i] = mIcons[i].getID();
+ mAllocLabelIDBuf[i] = mLabels[i].getID();
+ }
+
+ mAllocIconID.data(mAllocIconIDBuf);
+ mAllocLabelID.data(mAllocLabelIDBuf);
+
+ mState.iconCount = count;
+
+ Log.d("AllAppsView", "mScript=" + mScript + " mAllocIconID=" + mAllocIconID);
+
+ if (mScript != null) { // wtf
+ mScript.bindAllocation(mAllocIconID, Defines.ALLOC_ICON_IDS);
+ mScript.bindAllocation(mAllocLabelID, Defines.ALLOC_LABEL_IDS);
+ }
+
+ mState.save();
+ }
+ }
}
diff --git a/src/com/android/launcher2/AppInfoCache.java b/src/com/android/launcher2/AppInfoCache.java
new file mode 100644
index 000000000..34e843e83
--- /dev/null
+++ b/src/com/android/launcher2/AppInfoCache.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.launcher2;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.util.Log;
+import android.os.Process;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Cache of application icons. Icons can be made from any thread.
+ */
+public class AppInfoCache {
+ private static final String TAG = "Launcher.AppInfoCache";
+
+ private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
+
+ private static final HashMap<ComponentName, ApplicationInfo> sCache =
+ new HashMap<ComponentName, ApplicationInfo>(INITIAL_ICON_CACHE_CAPACITY);
+
+ /**
+ * no public constructor.
+ */
+ private AppInfoCache() {
+ }
+
+ /**
+ * For the given ResolveInfo, return an ApplicationInfo and cache the result for later.
+ */
+ public static ApplicationInfo cache(ResolveInfo info, Context context,
+ Utilities.BubbleText bubble) {
+ synchronized (sCache) {
+ ComponentName componentName = new ComponentName(
+ info.activityInfo.applicationInfo.packageName,
+ info.activityInfo.name);
+ ApplicationInfo application = sCache.get(componentName);
+
+ if (application == null) {
+ application = new ApplicationInfo();
+ application.container = ItemInfo.NO_ID;
+
+ updateTitleAndIcon(info, application, context, bubble);
+
+ application.setActivity(componentName,
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+
+ sCache.put(componentName, application);
+ }
+
+ return application;
+ }
+ }
+
+ /**
+ * Update the entry in the in the cache with its new metadata.
+ */
+ public static void update(ResolveInfo info, ApplicationInfo applicationInfo, Context context) {
+ synchronized (sCache) {
+ updateTitleAndIcon(info, applicationInfo, context, new Utilities.BubbleText(context));
+
+ ComponentName componentName = new ComponentName(
+ info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
+ sCache.put(componentName, applicationInfo);
+ }
+ }
+
+ /**
+ * Remove any records for the supplied ComponentName.
+ */
+ public static void remove(ComponentName componentName) {
+ synchronized (sCache) {
+ sCache.remove(componentName);
+ }
+ }
+
+ /**
+ * Empty out the cache.
+ */
+ public static void flush() {
+ synchronized (sCache) {
+ sCache.clear();
+ }
+ }
+
+ /**
+ * Get the icon for the supplied ApplicationInfo. If that activity already
+ * exists in the cache, use that.
+ */
+ public static Drawable getIconDrawable(PackageManager packageManager, ApplicationInfo info) {
+ final ResolveInfo resolveInfo = packageManager.resolveActivity(info.intent, 0);
+ if (resolveInfo == null) {
+ return null;
+ }
+
+ ComponentName componentName = new ComponentName(
+ resolveInfo.activityInfo.applicationInfo.packageName,
+ resolveInfo.activityInfo.name);
+ ApplicationInfo cached;
+ synchronized (sCache) {
+ cached = sCache.get(componentName);
+ }
+
+ if (cached != null) {
+ return cached.icon;
+ } else {
+ return resolveInfo.activityInfo.loadIcon(packageManager);
+ }
+ }
+
+ /**
+ * Go through the cache and disconnect any of the callbacks in the drawables or we
+ * leak the previous Home screen on orientation change.
+ */
+ public static void unbindDrawables() {
+ synchronized (sCache) {
+ for (ApplicationInfo appInfo: sCache.values()) {
+ appInfo.icon.setCallback(null);
+ }
+ }
+ }
+
+ /**
+ * Update the title and icon. Don't keep a reference to the context!
+ */
+ private static void updateTitleAndIcon(ResolveInfo info, ApplicationInfo application,
+ Context context, Utilities.BubbleText bubble) {
+ final PackageManager packageManager = context.getPackageManager();
+
+ application.title = info.loadLabel(packageManager);
+ if (application.title == null) {
+ application.title = info.activityInfo.name;
+ }
+
+ Drawable icon = Utilities.createIconThumbnail(info.activityInfo.loadIcon(packageManager),
+ context, true);
+ application.iconBitmap = ((FastBitmapDrawable)icon).getBitmap();
+ application.filtered = true;
+
+ application.titleBitmap = bubble.createTextBitmap(application.title.toString());
+ }
+}
+
diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java
index 912f04edc..db802c757 100644
--- a/src/com/android/launcher2/ApplicationInfo.java
+++ b/src/com/android/launcher2/ApplicationInfo.java
@@ -34,6 +34,11 @@ class ApplicationInfo extends ItemInfo {
CharSequence title;
/**
+ * A bitmap of the application's text in the bubble.
+ */
+ Bitmap titleBitmap;
+
+ /**
* The intent used to start the application.
*/
Intent intent;
@@ -44,6 +49,11 @@ class ApplicationInfo extends ItemInfo {
Drawable icon;
/**
+ * A bitmap version of the application icon.
+ */
+ Bitmap iconBitmap;
+
+ /**
* When set to true, indicates that the icon has been resized.
*/
boolean filtered;
@@ -124,4 +134,10 @@ class ApplicationInfo extends ItemInfo {
public String toString() {
return title.toString();
}
+
+ @Override
+ void unbind() {
+ super.unbind();
+ icon.setCallback(null);
+ }
}
diff --git a/src/com/android/launcher2/ApplicationsAdapter.java b/src/com/android/launcher2/ApplicationsAdapter.java
index 98f7c63e9..fc69703ca 100644
--- a/src/com/android/launcher2/ApplicationsAdapter.java
+++ b/src/com/android/launcher2/ApplicationsAdapter.java
@@ -28,7 +28,7 @@ import java.util.ArrayList;
/**
* GridView adapter to show the list of applications and shortcuts
*/
-public class ApplicationsAdapter extends ArrayAdapter<ApplicationInfo> {
+public class ApplicationsAdapter extends ArrayAdapter<ApplicationInfo> {
private final LayoutInflater mInflater;
public ApplicationsAdapter(Context context, ArrayList<ApplicationInfo> apps) {
@@ -45,7 +45,7 @@ public class ApplicationsAdapter extends ArrayAdapter<ApplicationInfo> {
}
if (!info.filtered) {
- info.icon = Utilities.createIconThumbnail(info.icon, getContext());
+ info.icon = Utilities.createIconThumbnail(info.icon, getContext(), false);
info.filtered = true;
}
diff --git a/src/com/android/launcher2/BubbleTextView.java b/src/com/android/launcher2/BubbleTextView.java
index de375b696..eaaff1cbb 100644
--- a/src/com/android/launcher2/BubbleTextView.java
+++ b/src/com/android/launcher2/BubbleTextView.java
@@ -63,7 +63,6 @@ public class BubbleTextView extends TextView {
setFocusable(true);
mBackground = getBackground();
setBackgroundDrawable(null);
- mBackground.setCallback(this);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(getContext().getResources().getColor(R.color.bubble_dark_background));
@@ -131,4 +130,16 @@ public class BubbleTextView extends TextView {
super.draw(canvas);
}
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mBackground.setCallback(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mBackground.setCallback(null);
+ }
}
diff --git a/src/com/android/launcher2/DeferredHandler.java b/src/com/android/launcher2/DeferredHandler.java
new file mode 100644
index 000000000..433bf5599
--- /dev/null
+++ b/src/com/android/launcher2/DeferredHandler.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.launcher2;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.util.Log;
+
+import java.util.LinkedList;
+
+/**
+ * Queue of things to run on a looper thread. Items posted with {@link #post} will not
+ * be actually enqued on the handler until after the last one has run, to keep from
+ * starving the thread.
+ *
+ * This class is fifo.
+ */
+public class DeferredHandler {
+ private LinkedList<Runnable> mQueue = new LinkedList();
+ private MessageQueue mMessageQueue = Looper.myQueue();
+ private Impl mHandler = new Impl();
+
+ private class Impl extends Handler implements MessageQueue.IdleHandler {
+ public void handleMessage(Message msg) {
+ Runnable r;
+ synchronized (mQueue) {
+ r = mQueue.removeFirst();
+ }
+ r.run();
+ synchronized (mQueue) {
+ scheduleNextLocked();
+ }
+ }
+
+ public boolean queueIdle() {
+ handleMessage(null);
+ return false;
+ }
+ }
+
+ private class IdleRunnable implements Runnable {
+ Runnable mRunnable;
+
+ IdleRunnable(Runnable r) {
+ mRunnable = r;
+ }
+
+ public void run() {
+ mRunnable.run();
+ }
+ }
+
+ public DeferredHandler() {
+ }
+
+ /** Schedule runnable to run after everything that's on the queue right now. */
+ public void post(Runnable runnable) {
+ synchronized (mQueue) {
+ mQueue.add(runnable);
+ if (mQueue.size() == 1) {
+ scheduleNextLocked();
+ }
+ }
+ }
+
+ /** Schedule runnable to run when the queue goes idle. */
+ public void postIdle(final Runnable runnable) {
+ post(new IdleRunnable(runnable));
+ }
+
+ public void cancel() {
+ synchronized (mQueue) {
+ mQueue.clear();
+ }
+ }
+
+ void scheduleNextLocked() {
+ if (mQueue.size() > 0) {
+ Runnable peek = mQueue.getFirst();
+ if (peek instanceof IdleRunnable) {
+ mMessageQueue.addIdleHandler(mHandler);
+ } else {
+ mHandler.sendEmptyMessage(1);
+ }
+ }
+ }
+}
+
diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java
index 8a2545fd5..43fb1a69a 100644
--- a/src/com/android/launcher2/DeleteZone.java
+++ b/src/com/android/launcher2/DeleteZone.java
@@ -93,24 +93,23 @@ public class DeleteZone extends ImageView implements DropTarget, DragController.
if (item.container == -1) return;
- final LauncherModel model = Launcher.getModel();
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
if (item instanceof LauncherAppWidgetInfo) {
- model.removeDesktopAppWidget((LauncherAppWidgetInfo) item);
- } else {
- model.removeDesktopItem(item);
+ mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
}
} else {
if (source instanceof UserFolder) {
final UserFolder userFolder = (UserFolder) source;
final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo();
- model.removeUserFolderItem(userFolderInfo, item);
+ // item must be an ApplicationInfo otherwise it couldn't have been in the folder
+ // in the first place.
+ userFolderInfo.remove((ApplicationInfo)item);
}
}
if (item instanceof UserFolderInfo) {
final UserFolderInfo userFolderInfo = (UserFolderInfo)item;
LauncherModel.deleteUserFolderContentsFromDatabase(mLauncher, userFolderInfo);
- model.removeUserFolder(userFolderInfo);
+ mLauncher.removeFolder(userFolderInfo);
} else if (item instanceof LauncherAppWidgetInfo) {
final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 51cf5e17a..38bc468e6 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -273,8 +273,10 @@ public class DragController {
* Call this from a drag source view.
*/
public boolean onInterceptTouchEvent(MotionEvent ev) {
- Log.d(Launcher.LOG_TAG, "DragController.onInterceptTouchEvent " + ev + " mDragging="
- + mDragging);
+ if (false) {
+ Log.d(Launcher.LOG_TAG, "DragController.onInterceptTouchEvent " + ev + " mDragging="
+ + mDragging);
+ }
final int action = ev.getAction();
final float screenX = ev.getRawX();
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 85fc3a754..c135fa3a2 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -48,7 +48,7 @@ public class FolderIcon extends BubbleTextView implements DropTarget {
final Resources resources = launcher.getResources();
Drawable d = resources.getDrawable(R.drawable.ic_launcher_folder);
- d = Utilities.createIconThumbnail(d, launcher);
+ d = Utilities.createIconThumbnail(d, launcher, false);
icon.mCloseIcon = d;
icon.mOpenIcon = resources.getDrawable(R.drawable.ic_launcher_folder_open);
icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null);
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index b371163c3..f04880ddd 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -130,4 +130,6 @@ class ItemInfo {
}
}
+ void unbind() {
+ }
}
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index e388ac3a3..40f4b3995 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -24,25 +24,20 @@ import android.app.SearchManager;
import android.app.StatusBarManager;
import android.app.WallpaperManager;
import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.Intent.ShortcutIconResource;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
-import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
@@ -74,6 +69,7 @@ import android.appwidget.AppWidgetProviderInfo;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.LinkedList;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
@@ -83,13 +79,15 @@ import java.io.DataInputStream;
/**
* Default launcher application.
*/
-public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener {
+public final class Launcher extends Activity
+ implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks {
static final String LOG_TAG = "Launcher";
+ static final String TAG = LOG_TAG;
static final boolean LOGD = false;
- private static final boolean PROFILE_STARTUP = false;
- private static final boolean PROFILE_ROTATE = false;
- private static final boolean DEBUG_USER_INTERFACE = false;
+ static final boolean PROFILE_STARTUP = false;
+ static final boolean PROFILE_ROTATE = false;
+ static final boolean DEBUG_USER_INTERFACE = false;
private static final int WALLPAPER_SCREENS_SPAN = 2;
@@ -150,14 +148,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On
// Type: long
private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME_ID = "launcher.rename_folder_id";
- private static final LauncherModel sModel = new LauncherModel();
+ static final int APPWIDGET_HOST_ID = 1024;
private static final Object sLock = new Object();
private static int sScreen = DEFAULT_SCREN;
- private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();
- private final ContentObserver mObserver = new FavoritesChangeObserver();
-
private LayoutInflater mInflater;
private DragController mDragController;
@@ -166,8 +161,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private AppWidgetManager mAppWidgetManager;
private LauncherAppWidgetHost mAppWidgetHost;
- static final int APPWIDGET_HOST_ID = 1024;
-
private CellLayout.CellInfo mAddItemCellInfo;
private CellLayout.CellInfo mMenuAddInfo;
private final int[] mCellCoordinates = new int[2];
@@ -178,15 +171,14 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private AllAppsView mAllAppsGrid;
private boolean mAllAppsVisible;
- private boolean mDesktopLocked = true;
private Bundle mSavedState;
private SpannableStringBuilder mDefaultKeySsb = null;
- private boolean mDestroyed;
-
private boolean mIsNewIntent;
+ private boolean mWorkspaceLoading = true;
+
private boolean mRestoring;
private boolean mWaitingForResult;
private boolean mLocaleChanged;
@@ -196,12 +188,17 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private Bundle mSavedInstanceState;
- private DesktopBinder mBinder;
+ private LauncherModel mModel;
+
+ private ArrayList<ItemInfo> mDesktopItems = new ArrayList();
+ private static HashMap<Long, FolderInfo> mFolders = new HashMap();
+ private ArrayList<ApplicationInfo> mAllAppsList = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mModel = ((LauncherApplication)getApplication()).setLauncher(this);
mInflater = getLayoutInflater();
mAppWidgetManager = AppWidgetManager.getInstance(this);
@@ -221,9 +218,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
lockAllApps();
- registerIntentReceivers();
- registerContentObservers();
-
mSavedState = savedInstanceState;
restoreState(mSavedState);
@@ -232,7 +226,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
}
if (!mRestoring) {
- startLoaders();
+ mModel.startLoader(this, true);
}
// For handling default keys
@@ -263,6 +257,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
localeConfiguration.mnc = mnc;
writeConfiguration(this, localeConfiguration);
+ AppInfoCache.flush();
}
}
@@ -330,13 +325,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
}
}
- private void startLoaders() {
- boolean loadApplications = sModel.loadApplications(true, this, mLocaleChanged);
- sModel.loadUserItems(!mLocaleChanged, this, mLocaleChanged, loadApplications);
-
- mRestoring = false;
- }
-
private void setWallpaperDimension() {
WallpaperManager wpm = (WallpaperManager)getSystemService(WALLPAPER_SERVICE);
@@ -361,25 +349,25 @@ public final class Launcher extends Activity implements View.OnClickListener, On
if (resultCode == RESULT_OK && mAddItemCellInfo != null) {
switch (requestCode) {
case REQUEST_PICK_APPLICATION:
- completeAddApplication(this, data, mAddItemCellInfo, !mDesktopLocked);
+ completeAddApplication(this, data, mAddItemCellInfo);
break;
case REQUEST_PICK_SHORTCUT:
processShortcut(data, REQUEST_PICK_APPLICATION, REQUEST_CREATE_SHORTCUT);
break;
case REQUEST_CREATE_SHORTCUT:
- completeAddShortcut(data, mAddItemCellInfo, !mDesktopLocked);
+ completeAddShortcut(data, mAddItemCellInfo);
break;
case REQUEST_PICK_LIVE_FOLDER:
addLiveFolder(data);
break;
case REQUEST_CREATE_LIVE_FOLDER:
- completeAddLiveFolder(data, mAddItemCellInfo, !mDesktopLocked);
+ completeAddLiveFolder(data, mAddItemCellInfo);
break;
case REQUEST_PICK_APPWIDGET:
addAppWidget(data);
break;
case REQUEST_CREATE_APPWIDGET:
- completeAddAppWidget(data, mAddItemCellInfo, !mDesktopLocked);
+ completeAddAppWidget(data, mAddItemCellInfo);
break;
}
} else if (requestCode == REQUEST_PICK_APPWIDGET &&
@@ -396,8 +384,12 @@ public final class Launcher extends Activity implements View.OnClickListener, On
protected void onResume() {
super.onResume();
+ Log.d(TAG, "onResume mRestoring=" + mRestoring);
+
if (mRestoring) {
- startLoaders();
+ mWorkspaceLoading = true;
+ mModel.startLoader(this, true);
+ mRestoring = false;
}
// If this was a new intent (i.e., the mIsNewIntent flag got set to true by
@@ -430,10 +422,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On
@Override
public Object onRetainNonConfigurationInstance() {
- // Flag any binder to stop early before switching
- if (mBinder != null) {
- mBinder.mTerminate = true;
- }
+ // Flag the loader to stop early before switching
+ mModel.stopLoader();
if (PROFILE_ROTATE) {
android.os.Debug.startMethodTracing("/sdcard/launcher-rotate");
@@ -512,7 +502,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
boolean renameFolder = savedState.getBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, false);
if (renameFolder) {
long id = savedState.getLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID);
- mFolderInfo = sModel.getFolderById(this, id);
+ mFolderInfo = mModel.getFolderById(this, mFolders, id);
mRestoring = true;
}
}
@@ -583,7 +573,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
TextView favorite = (TextView) mInflater.inflate(layoutResId, parent, false);
if (!info.filtered) {
- info.icon = Utilities.createIconThumbnail(info.icon, this);
+ info.icon = Utilities.createIconThumbnail(info.icon, this, false);
info.filtered = true;
}
@@ -601,14 +591,13 @@ public final class Launcher extends Activity implements View.OnClickListener, On
* @param data The intent describing the application.
* @param cellInfo The position on screen where to create the shortcut.
*/
- void completeAddApplication(Context context, Intent data, CellLayout.CellInfo cellInfo,
- boolean insertAtFirst) {
+ void completeAddApplication(Context context, Intent data, CellLayout.CellInfo cellInfo) {
cellInfo.screen = mWorkspace.getCurrentScreen();
if (!findSingleSlot(cellInfo)) return;
final ApplicationInfo info = infoFromApplicationIntent(context, data);
if (info != null) {
- mWorkspace.addApplicationShortcut(info, cellInfo, insertAtFirst);
+ mWorkspace.addApplicationShortcut(info, cellInfo, isWorkspaceLocked());
}
}
@@ -646,22 +635,17 @@ public final class Launcher extends Activity implements View.OnClickListener, On
*
* @param data The intent describing the shortcut.
* @param cellInfo The position on screen where to create the shortcut.
- * @param insertAtFirst
*/
- private void completeAddShortcut(Intent data, CellLayout.CellInfo cellInfo,
- boolean insertAtFirst) {
+ private void completeAddShortcut(Intent data, CellLayout.CellInfo cellInfo) {
cellInfo.screen = mWorkspace.getCurrentScreen();
if (!findSingleSlot(cellInfo)) return;
final ApplicationInfo info = addShortcut(this, data, cellInfo, false);
if (!mRestoring) {
- sModel.addDesktopItem(info);
-
final View view = createShortcut(info);
- mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1, insertAtFirst);
- } else if (sModel.isDesktopLoaded()) {
- sModel.addDesktopItem(info);
+ mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1,
+ isWorkspaceLocked());
}
}
@@ -672,9 +656,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
* @param data The intent describing the appWidgetId.
* @param cellInfo The position on screen where to create the widget.
*/
- private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo,
- boolean insertAtFirst) {
-
+ private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) {
Bundle extras = data.getExtras();
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
@@ -700,7 +682,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
if (!mRestoring) {
- sModel.addDesktopAppWidget(launcherInfo);
+ mDesktopItems.add(launcherInfo);
// Perform actual inflation because we're live
launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
@@ -709,12 +691,15 @@ public final class Launcher extends Activity implements View.OnClickListener, On
launcherInfo.hostView.setTag(launcherInfo);
mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1],
- launcherInfo.spanX, launcherInfo.spanY, insertAtFirst);
- } else if (sModel.isDesktopLoaded()) {
- sModel.addDesktopAppWidget(launcherInfo);
+ launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
}
}
+ public void removeAppWidget(LauncherAppWidgetInfo launcherInfo) {
+ mDesktopItems.remove(launcherInfo);
+ launcherInfo.hostView = null;
+ }
+
public LauncherAppWidgetHost getAppWidgetHost() {
return mAppWidgetHost;
}
@@ -790,7 +775,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
try {
dismissDialog(DIALOG_CREATE_SHORTCUT);
// Unlock the workspace if the dialog was showing
- mWorkspace.unlock();
} catch (Exception e) {
// An exception is thrown if the dialog is not visible, which is fine
}
@@ -798,7 +782,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
try {
dismissDialog(DIALOG_RENAME_FOLDER);
// Unlock the workspace if the dialog was showing
- mWorkspace.unlock();
} catch (Exception e) {
// An exception is thrown if the dialog is not visible, which is fine
}
@@ -878,8 +861,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
@Override
public void onDestroy() {
- mDestroyed = true;
-
super.onDestroy();
try {
@@ -891,11 +872,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On
TextKeyListener.getInstance().release();
mAllAppsGrid.setAdapter(null);
- sModel.unbind();
- sModel.abortLoaders();
+ mModel.stopLoader();
- getContentResolver().unregisterContentObserver(mObserver);
- unregisterReceiver(mApplicationsReceiver);
+ unbindDesktopItems();
+ AppInfoCache.unbindDrawables();
}
@Override
@@ -975,7 +955,9 @@ public final class Launcher extends Activity implements View.OnClickListener, On
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- if (mDesktopLocked) return false;
+ if (isWorkspaceLocked()) {
+ return false;
+ }
super.onCreateOptionsMenu(menu);
menu.add(MENU_GROUP_ADD, MENU_ADD, 0, R.string.menu_add)
@@ -1043,20 +1025,12 @@ public final class Launcher extends Activity implements View.OnClickListener, On
return true;
}
- private void addItems() {
- showAddDialog(mMenuAddInfo);
+ public boolean isWorkspaceLocked() {
+ return mWorkspaceLoading || mWaitingForResult;
}
- private void removeShortcutsForPackage(String packageName) {
- if (packageName != null && packageName.length() > 0) {
- mWorkspace.removeShortcutsForPackage(packageName);
- }
- }
-
- private void updateShortcutsForPackage(String packageName) {
- if (packageName != null && packageName.length() > 0) {
- mWorkspace.updateShortcutsForPackage(packageName);
- }
+ private void addItems() {
+ showAddDialog(mMenuAddInfo);
}
void addAppWidget(Intent data) {
@@ -1096,7 +1070,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
if (!findSlot(cellInfo, xy, spanX, spanY)) return;
- sModel.addDesktopItem(info);
LauncherModel.addItemToDatabase(this, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
@@ -1131,13 +1104,13 @@ public final class Launcher extends Activity implements View.OnClickListener, On
String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
if (folderName != null && folderName.equals(shortcutName)) {
- addFolder(!mDesktopLocked);
+ addFolder();
} else {
startActivityForResult(intent, REQUEST_CREATE_LIVE_FOLDER);
}
}
- void addFolder(boolean insertAtFirst) {
+ void addFolder() {
UserFolderInfo folderInfo = new UserFolderInfo();
folderInfo.title = getText(R.string.folder_name);
@@ -1146,33 +1119,33 @@ public final class Launcher extends Activity implements View.OnClickListener, On
if (!findSingleSlot(cellInfo)) return;
// Update the model
- LauncherModel.addItemToDatabase(this, folderInfo, LauncherSettings.Favorites.CONTAINER_DESKTOP,
+ LauncherModel.addItemToDatabase(this, folderInfo,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP,
mWorkspace.getCurrentScreen(), cellInfo.cellX, cellInfo.cellY, false);
- sModel.addDesktopItem(folderInfo);
- sModel.addFolder(folderInfo);
+ mFolders.put(folderInfo.id, folderInfo);
// Create the view
FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
(ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), folderInfo);
mWorkspace.addInCurrentScreen(newFolder,
- cellInfo.cellX, cellInfo.cellY, 1, 1, insertAtFirst);
+ cellInfo.cellX, cellInfo.cellY, 1, 1, isWorkspaceLocked());
+ }
+
+ void removeFolder(FolderInfo folder) {
+ mFolders.remove(folder.id);
}
- private void completeAddLiveFolder(Intent data, CellLayout.CellInfo cellInfo,
- boolean insertAtFirst) {
+ private void completeAddLiveFolder(Intent data, CellLayout.CellInfo cellInfo) {
cellInfo.screen = mWorkspace.getCurrentScreen();
if (!findSingleSlot(cellInfo)) return;
final LiveFolderInfo info = addLiveFolder(this, data, cellInfo, false);
if (!mRestoring) {
- sModel.addDesktopItem(info);
-
final View view = LiveFolderIcon.fromXml(R.layout.live_folder_icon, this,
(ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), info);
- mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1, insertAtFirst);
- } else if (sModel.isDesktopLoaded()) {
- sModel.addDesktopItem(info);
+ mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1,
+ isWorkspaceLocked());
}
}
@@ -1216,7 +1189,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify);
- sModel.addFolder(info);
+ mFolders.put(info.id, info);
return info;
}
@@ -1256,28 +1229,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
startActivity(Intent.createChooser(pickWallpaper, getString(R.string.chooser_wallpaper)));
}
- /**
- * Registers various intent receivers. The current implementation registers
- * only a wallpaper intent receiver to let other applications change the
- * wallpaper.
- */
- private void registerIntentReceivers() {
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- registerReceiver(mApplicationsReceiver, filter);
- }
-
- /**
- * Registers various content observers. The current implementation registers
- * only a favorites observer to keep track of the favorites applications.
- */
- private void registerContentObservers() {
- ContentResolver resolver = getContentResolver();
- resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true, mObserver);
- }
-
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
@@ -1331,202 +1282,19 @@ public final class Launcher extends Activity implements View.OnClickListener, On
ViewGroup parent = (ViewGroup) folder.getParent();
if (parent != null) {
parent.removeView(folder);
- mDragController.removeDropTarget((DropTarget)folder);
+ // TODO: this line crashes.
+ //mDragController.removeDropTarget((DropTarget)folder);
}
folder.onClose();
}
/**
- * When the notification that favorites have changed is received, requests
- * a favorites list refresh.
+ * Go through the and disconnect any of the callbacks in the drawables and the views or we
+ * leak the previous Home screen on orientation change.
*/
- private void onFavoritesChanged() {
- mDesktopLocked = true;
- lockAllApps();
- sModel.loadUserItems(false, this, false, false);
- }
-
- void onDesktopItemsLoaded() {
- if (mDestroyed) return;
- bindDesktopItems();
- }
-
- /**
- * Refreshes the shortcuts shown on the workspace.
- */
- private void bindDesktopItems() {
- final ArrayList<ItemInfo> shortcuts = sModel.getDesktopItems();
- final ArrayList<LauncherAppWidgetInfo> appWidgets = sModel.getDesktopAppWidgets();
- final ApplicationsAdapter drawerAdapter = sModel.getApplicationsAdapter();
- if (shortcuts == null || appWidgets == null || drawerAdapter == null) {
- return;
- }
-
- final Workspace workspace = mWorkspace;
- int count = workspace.getChildCount();
- for (int i = 0; i < count; i++) {
- ((ViewGroup) workspace.getChildAt(i)).removeAllViewsInLayout();
- }
-
- if (DEBUG_USER_INTERFACE) {
- android.widget.Button finishButton = new android.widget.Button(this);
- finishButton.setText("Finish");
- workspace.addInScreen(finishButton, 1, 0, 0, 1, 1);
-
- finishButton.setOnClickListener(new android.widget.Button.OnClickListener() {
- public void onClick(View v) {
- finish();
- }
- });
- }
-
- // Flag any old binder to terminate early
- if (mBinder != null) {
- mBinder.mTerminate = true;
- }
-
- mBinder = new DesktopBinder(this, shortcuts, appWidgets, drawerAdapter);
- mBinder.startBindingItems();
- }
-
- private void bindItems(Launcher.DesktopBinder binder,
- ArrayList<ItemInfo> shortcuts, int start, int count) {
-
- final Workspace workspace = mWorkspace;
- final boolean desktopLocked = mDesktopLocked;
-
- final int end = Math.min(start + DesktopBinder.ITEMS_COUNT, count);
- int i = start;
-
- for ( ; i < end; i++) {
- final ItemInfo item = shortcuts.get(i);
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- final View shortcut = createShortcut((ApplicationInfo) item);
- workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1,
- !desktopLocked);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
- final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
- (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()),
- (UserFolderInfo) item);
- workspace.addInScreen(newFolder, item.screen, item.cellX, item.cellY, 1, 1,
- !desktopLocked);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
- final FolderIcon newLiveFolder = LiveFolderIcon.fromXml(
- R.layout.live_folder_icon, this,
- (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()),
- (LiveFolderInfo) item);
- workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1,
- !desktopLocked);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
- final int screen = workspace.getCurrentScreen();
- final View view = mInflater.inflate(R.layout.widget_search,
- (ViewGroup) workspace.getChildAt(screen), false);
-
- Search search = (Search) view.findViewById(R.id.widget_search);
- search.setLauncher(this);
-
- final Widget widget = (Widget) item;
- view.setTag(widget);
-
- workspace.addWidget(view, widget, !desktopLocked);
- break;
- }
- }
-
- workspace.requestLayout();
-
- if (end >= count) {
- finishBindDesktopItems();
- binder.startBindingDrawer();
- } else {
- binder.obtainMessage(DesktopBinder.MESSAGE_BIND_ITEMS, i, count).sendToTarget();
- }
- }
-
- private void finishBindDesktopItems() {
- if (mSavedState != null) {
- if (!mWorkspace.hasFocus()) {
- mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus();
- }
-
- final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS);
- if (userFolders != null) {
- for (long folderId : userFolders) {
- final FolderInfo info = sModel.findFolderById(folderId);
- if (info != null) {
- openFolder(info);
- }
- }
- final Folder openFolder = mWorkspace.getOpenFolder();
- if (openFolder != null) {
- openFolder.requestFocus();
- }
- }
-
- final boolean allApps = mSavedState.getBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, false);
- if (allApps) {
- showAllAppsDialog();
- }
-
- mSavedState = null;
- }
-
- if (mSavedInstanceState != null) {
- super.onRestoreInstanceState(mSavedInstanceState);
- mSavedInstanceState = null;
- }
-
- /* TODO
- if (mAllAppsVisible && !mDrawer.hasFocus()) {
- mDrawer.requestFocus();
- }
- */
-
- mDesktopLocked = false;
- unlockAllApps();
- }
-
- private void bindDrawer(Launcher.DesktopBinder binder,
- ApplicationsAdapter drawerAdapter) {
- mAllAppsGrid.setAdapter(drawerAdapter);
- binder.startBindingAppWidgetsWhenIdle();
- }
-
- private void bindAppWidgets(Launcher.DesktopBinder binder,
- LinkedList<LauncherAppWidgetInfo> appWidgets) {
-
- final Workspace workspace = mWorkspace;
- final boolean desktopLocked = mDesktopLocked;
-
- if (!appWidgets.isEmpty()) {
- final LauncherAppWidgetInfo item = appWidgets.removeFirst();
-
- final int appWidgetId = item.appWidgetId;
- final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
- item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
-
- if (LOGD) d(LOG_TAG, String.format("about to setAppWidget for id=%d, info=%s", appWidgetId, appWidgetInfo));
-
- item.hostView.setAppWidget(appWidgetId, appWidgetInfo);
- item.hostView.setTag(item);
-
- workspace.addInScreen(item.hostView, item.screen, item.cellX,
- item.cellY, item.spanX, item.spanY, !desktopLocked);
-
- workspace.requestLayout();
- }
-
- if (appWidgets.isEmpty()) {
- if (PROFILE_ROTATE) {
- android.os.Debug.stopMethodTracing();
- }
- } else {
- binder.obtainMessage(DesktopBinder.MESSAGE_BIND_APPWIDGETS).sendToTarget();
+ private void unbindDesktopItems() {
+ for (ItemInfo item: mDesktopItems) {
+ item.unbind();
}
}
@@ -1618,18 +1386,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On
openFolder.onOpen();
}
- /**
- * Returns true if the workspace is being loaded. When the workspace is loading,
- * no user interaction should be allowed to avoid any conflict.
- *
- * @return True if the workspace is locked, false otherwise.
- */
- boolean isWorkspaceLocked() {
- return mDesktopLocked;
- }
-
public boolean onLongClick(View v) {
- if (mDesktopLocked) {
+ if (isWorkspaceLocked()) {
return false;
}
@@ -1661,10 +1419,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
return true;
}
- static LauncherModel getModel() {
- return sModel;
- }
-
View getDrawerHandle() {
return mHandleView;
}
@@ -1779,7 +1533,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
public void onShow(DialogInterface dialog) {
- mWorkspace.lock();
}
});
@@ -1790,13 +1543,14 @@ public final class Launcher extends Activity implements View.OnClickListener, On
final String name = mInput.getText().toString();
if (!TextUtils.isEmpty(name)) {
// Make sure we have the right folder info
- mFolderInfo = sModel.findFolderById(mFolderInfo.id);
+ mFolderInfo = mFolders.get(mFolderInfo.id);
mFolderInfo.title = name;
LauncherModel.updateItemInDatabase(Launcher.this, mFolderInfo);
- if (mDesktopLocked) {
+ if (mWorkspaceLoading) {
lockAllApps();
- sModel.loadUserItems(false, Launcher.this, false, false);
+ mModel.setWorkspaceDirty();
+ mModel.startLoader(Launcher.this, false);
} else {
final FolderIcon folderIcon = (FolderIcon)
mWorkspace.getViewForTag(mFolderInfo);
@@ -1804,9 +1558,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On
folderIcon.setText(name);
getWorkspace().requestLayout();
} else {
- mDesktopLocked = true;
lockAllApps();
- sModel.loadUserItems(false, Launcher.this, false, false);
+ mModel.setWorkspaceDirty();
+ mWorkspaceLoading = true;
+ mModel.startLoader(Launcher.this, false);
}
}
}
@@ -1814,7 +1569,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
}
private void cleanup() {
- mWorkspace.unlock();
dismissDialog(DIALOG_RENAME_FOLDER);
mWaitingForResult = false;
mFolderInfo = null;
@@ -1893,11 +1647,9 @@ public final class Launcher extends Activity implements View.OnClickListener, On
}
public void onDismiss(DialogInterface dialog) {
- mWorkspace.unlock();
}
private void cleanup() {
- mWorkspace.unlock();
dismissDialog(DIALOG_CREATE_SHORTCUT);
}
@@ -1974,158 +1726,215 @@ public final class Launcher extends Activity implements View.OnClickListener, On
}
public void onShow(DialogInterface dialog) {
- mWorkspace.lock();
}
}
/**
- * Receives notifications when applications are added/removed.
+ * Implementation of the method from LauncherModel.Callbacks.
*/
- private class ApplicationsIntentReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final String packageName = intent.getData().getSchemeSpecificPart();
- final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
-
- if (LauncherModel.DEBUG_LOADERS) {
- d(LauncherModel.LOG_TAG, "application intent received: " + action +
- ", replacing=" + replacing);
- d(LauncherModel.LOG_TAG, " --> " + intent.getData());
- }
+ public int getCurrentWorkspaceScreen() {
+ return mWorkspace.getCurrentScreen();
+ }
- if (!Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- if (!replacing) {
- removeShortcutsForPackage(packageName);
- if (LauncherModel.DEBUG_LOADERS) {
- d(LauncherModel.LOG_TAG, " --> remove package");
- }
- sModel.removePackage(Launcher.this, packageName);
- }
- // else, we are replacing the package, so a PACKAGE_ADDED will be sent
- // later, we will update the package at this time
- } else {
- if (!replacing) {
- if (LauncherModel.DEBUG_LOADERS) {
- d(LauncherModel.LOG_TAG, " --> add package");
- }
- sModel.addPackage(Launcher.this, packageName);
- } else {
- if (LauncherModel.DEBUG_LOADERS) {
- d(LauncherModel.LOG_TAG, " --> update package " + packageName);
- }
- sModel.updatePackage(Launcher.this, packageName);
- updateShortcutsForPackage(packageName);
- }
- }
- removeDialog(DIALOG_CREATE_SHORTCUT);
- } else {
- if (LauncherModel.DEBUG_LOADERS) {
- d(LauncherModel.LOG_TAG, " --> sync package " + packageName);
+ /**
+ * Refreshes the shortcuts shown on the workspace.
+ *
+ * Implementation of the method from LauncherModel.Callbacks.
+ */
+ public void startBinding() {
+ final Workspace workspace = mWorkspace;
+ int count = workspace.getChildCount();
+ for (int i = 0; i < count; i++) {
+ ((ViewGroup) workspace.getChildAt(i)).removeAllViewsInLayout();
+ }
+
+ if (DEBUG_USER_INTERFACE) {
+ android.widget.Button finishButton = new android.widget.Button(this);
+ finishButton.setText("Finish");
+ workspace.addInScreen(finishButton, 1, 0, 0, 1, 1);
+
+ finishButton.setOnClickListener(new android.widget.Button.OnClickListener() {
+ public void onClick(View v) {
+ finish();
}
- sModel.syncPackage(Launcher.this, packageName);
- }
+ });
}
}
/**
- * Receives notifications whenever the user favorites have changed.
+ * Bind the items start-end from the list.
+ *
+ * Implementation of the method from LauncherModel.Callbacks.
*/
- private class FavoritesChangeObserver extends ContentObserver {
- public FavoritesChangeObserver() {
- super(new Handler());
- }
+ public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end) {
+
+ final Workspace workspace = mWorkspace;
+
+ for (int i=start; i<end; i++) {
+ final ItemInfo item = shortcuts.get(i);
+ mDesktopItems.add(item);
+ switch (item.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ final View shortcut = createShortcut((ApplicationInfo) item);
+ workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1,
+ false);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+ final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
+ (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()),
+ (UserFolderInfo) item);
+ workspace.addInScreen(newFolder, item.screen, item.cellX, item.cellY, 1, 1,
+ false);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
+ final FolderIcon newLiveFolder = LiveFolderIcon.fromXml(
+ R.layout.live_folder_icon, this,
+ (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()),
+ (LiveFolderInfo) item);
+ workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1,
+ false);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
+ final int screen = workspace.getCurrentScreen();
+ final View view = mInflater.inflate(R.layout.widget_search,
+ (ViewGroup) workspace.getChildAt(screen), false);
- @Override
- public void onChange(boolean selfChange) {
- onFavoritesChanged();
+ Search search = (Search) view.findViewById(R.id.widget_search);
+ search.setLauncher(this);
+
+ final Widget widget = (Widget) item;
+ view.setTag(widget);
+
+ workspace.addWidget(view, widget, false);
+ break;
+ }
}
+
+ workspace.requestLayout();
+ }
+
+ /**
+ * Implementation of the method from LauncherModel.Callbacks.
+ */
+ void bindFolders(HashMap<Long, FolderInfo> folders) {
+ mFolders.putAll(folders);
}
- private static class DesktopBinder extends Handler implements MessageQueue.IdleHandler {
- static final int MESSAGE_BIND_ITEMS = 0x1;
- static final int MESSAGE_BIND_APPWIDGETS = 0x2;
- static final int MESSAGE_BIND_DRAWER = 0x3;
+ /**
+ * Add the views for a widget to the workspace.
+ *
+ * Implementation of the method from LauncherModel.Callbacks.
+ */
+ public void bindAppWidget(LauncherAppWidgetInfo item) {
+ final Workspace workspace = mWorkspace;
- // Number of items to bind in every pass
- static final int ITEMS_COUNT = 6;
+ final int appWidgetId = item.appWidgetId;
+ final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+ item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
- private final ArrayList<ItemInfo> mShortcuts;
- private final LinkedList<LauncherAppWidgetInfo> mAppWidgets;
- private final ApplicationsAdapter mDrawerAdapter;
- private final WeakReference<Launcher> mLauncher;
+ if (true) {
+ Log.d(LOG_TAG, String.format("about to setAppWidget for id=%d, info=%s",
+ appWidgetId, appWidgetInfo));
+ }
- public boolean mTerminate = false;
+ item.hostView.setAppWidget(appWidgetId, appWidgetInfo);
+ item.hostView.setTag(item);
- DesktopBinder(Launcher launcher, ArrayList<ItemInfo> shortcuts,
- ArrayList<LauncherAppWidgetInfo> appWidgets,
- ApplicationsAdapter drawerAdapter) {
+ workspace.addInScreen(item.hostView, item.screen, item.cellX,
+ item.cellY, item.spanX, item.spanY, false);
- mLauncher = new WeakReference<Launcher>(launcher);
- mShortcuts = shortcuts;
- mDrawerAdapter = drawerAdapter;
+ workspace.requestLayout();
- // Sort widgets so active workspace is bound first
- final int currentScreen = launcher.mWorkspace.getCurrentScreen();
- final int size = appWidgets.size();
- mAppWidgets = new LinkedList<LauncherAppWidgetInfo>();
+ mDesktopItems.add(item);
+ }
- for (int i = 0; i < size; i++) {
- LauncherAppWidgetInfo appWidgetInfo = appWidgets.get(i);
- if (appWidgetInfo.screen == currentScreen) {
- mAppWidgets.addFirst(appWidgetInfo);
- } else {
- mAppWidgets.addLast(appWidgetInfo);
+ /**
+ * Callback saying that there aren't any more items to bind.
+ *
+ * Implementation of the method from LauncherModel.Callbacks.
+ */
+ public void finishBindingItems() {
+ if (mSavedState != null) {
+ if (!mWorkspace.hasFocus()) {
+ mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus();
+ }
+
+ final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS);
+ if (userFolders != null) {
+ for (long folderId : userFolders) {
+ final FolderInfo info = mFolders.get(folderId);
+ if (info != null) {
+ openFolder(info);
+ }
+ }
+ final Folder openFolder = mWorkspace.getOpenFolder();
+ if (openFolder != null) {
+ openFolder.requestFocus();
}
}
- }
- public void startBindingItems() {
- obtainMessage(MESSAGE_BIND_ITEMS, 0, mShortcuts.size()).sendToTarget();
- }
+ final boolean allApps = mSavedState.getBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, false);
+ if (allApps) {
+ showAllAppsDialog();
+ }
- public void startBindingDrawer() {
- obtainMessage(MESSAGE_BIND_DRAWER).sendToTarget();
+ mSavedState = null;
}
- public void startBindingAppWidgetsWhenIdle() {
- // Ask for notification when message queue becomes idle
- final MessageQueue messageQueue = Looper.myQueue();
- messageQueue.addIdleHandler(this);
+ if (mSavedInstanceState != null) {
+ super.onRestoreInstanceState(mSavedInstanceState);
+ mSavedInstanceState = null;
}
- public boolean queueIdle() {
- // Queue is idle, so start binding items
- startBindingAppWidgets();
- return false;
+ /* TODO
+ if (mAllAppsVisible && !mDrawer.hasFocus()) {
+ mDrawer.requestFocus();
}
+ */
- public void startBindingAppWidgets() {
- obtainMessage(MESSAGE_BIND_APPWIDGETS).sendToTarget();
- }
+ Log.d(TAG, "finishBindingItems done");
+ mWorkspaceLoading = false;
+ }
- @Override
- public void handleMessage(Message msg) {
- Launcher launcher = mLauncher.get();
- if (launcher == null || mTerminate) {
- return;
- }
+ /**
+ * Add the icons for all apps.
+ *
+ * Implementation of the method from LauncherModel.Callbacks.
+ */
+ public void bindAllApplications(ArrayList<ApplicationInfo> apps) {
+ Log.d(LOG_TAG, "got info for " + apps.size() + " apps");
+ mAllAppsList = apps;
+ mAllAppsGrid.setApps(mAllAppsList);
+ }
- switch (msg.what) {
- case MESSAGE_BIND_ITEMS: {
- launcher.bindItems(this, mShortcuts, msg.arg1, msg.arg2);
- break;
- }
- case MESSAGE_BIND_DRAWER: {
- launcher.bindDrawer(this, mDrawerAdapter);
- break;
- }
- case MESSAGE_BIND_APPWIDGETS: {
- launcher.bindAppWidgets(this, mAppWidgets);
- break;
- }
- }
- }
+ /**
+ * A package was installed.
+ *
+ * Implementation of the method from LauncherModel.Callbacks.
+ */
+ public void bindPackageAdded(ArrayList<ApplicationInfo> apps) {
+ removeDialog(DIALOG_CREATE_SHORTCUT);
+ }
+
+ /**
+ * A package was updated.
+ *
+ * Implementation of the method from LauncherModel.Callbacks.
+ */
+ public void bindPackageUpdated(String packageName, ArrayList<ApplicationInfo> apps) {
+ removeDialog(DIALOG_CREATE_SHORTCUT);
+ mWorkspace.updateShortcutsForPackage(packageName);
+ }
+
+ /**
+ * A package was uninstalled.
+ *
+ * Implementation of the method from LauncherModel.Callbacks.
+ */
+ public void bindPackageRemoved(String packageName, ArrayList<ApplicationInfo> apps) {
+ removeDialog(DIALOG_CREATE_SHORTCUT);
+ mWorkspace.removeShortcutsForPackage(packageName);
}
+
}
diff --git a/src/com/android/launcher2/LauncherAppWidgetInfo.java b/src/com/android/launcher2/LauncherAppWidgetInfo.java
index cd4643461..25db72bed 100644
--- a/src/com/android/launcher2/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher2/LauncherAppWidgetInfo.java
@@ -50,4 +50,11 @@ class LauncherAppWidgetInfo extends ItemInfo {
public String toString() {
return Integer.toString(appWidgetId);
}
+
+
+ @Override
+ void unbind() {
+ super.unbind();
+ hostView = null;
+ }
}
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
index 03fe5626d..ee6006c5b 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -17,13 +17,74 @@
package com.android.launcher2;
import android.app.Application;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.os.Handler;
import dalvik.system.VMRuntime;
public class LauncherApplication extends Application {
+ public static final LauncherModel sModel = new LauncherModel();
+
@Override
public void onCreate() {
VMRuntime.getRuntime().setMinimumHeapSize(4 * 1024 * 1024);
super.onCreate();
+
+ // Register intent receivers
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+ registerReceiver(mApplicationsReceiver, filter);
+
+ // Register for changes to the favorites
+ ContentResolver resolver = getContentResolver();
+ resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,
+ mFavoritesObserver);
+ }
+
+ /**
+ * There's no guarantee that this function is ever called.
+ */
+ @Override
+ public void onTerminate() {
+ super.onTerminate();
+
+ unregisterReceiver(mApplicationsReceiver);
+
+ ContentResolver resolver = getContentResolver();
+ resolver.unregisterContentObserver(mFavoritesObserver);
+ }
+
+ /**
+ * Receives notifications when applications are added/removed.
+ */
+ private final BroadcastReceiver mApplicationsReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ sModel.onReceiveIntent(LauncherApplication.this, intent);
+ }
+ };
+
+ /**
+ * Receives notifications whenever the user favorites have changed.
+ */
+ private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ // TODO: lockAllApps();
+ sModel.setWorkspaceDirty();
+ sModel.startLoader(LauncherApplication.this, false);
+ }
+ };
+
+ LauncherModel setLauncher(Launcher launcher) {
+ sModel.initialize(launcher);
+ return sModel;
}
}
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 7676b846a..36b2090e1 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -31,15 +31,18 @@ import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import static android.util.Log.*;
+import android.util.Log;
import android.os.Process;
+import android.os.SystemClock;
+import java.lang.ref.WeakReference;
+import java.net.URISyntaxException;
+import java.text.Collator;
import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
-import java.util.Comparator;
-import java.lang.ref.WeakReference;
-import java.text.Collator;
-import java.net.URISyntaxException;
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
@@ -48,1096 +51,887 @@ import java.net.URISyntaxException;
*/
public class LauncherModel {
static final boolean DEBUG_LOADERS = true;
- static final String LOG_TAG = "HomeLoaders";
-
- private static final int UI_NOTIFICATION_RATE = 4;
- private static final int DEFAULT_APPLICATIONS_NUMBER = 42;
- private static final long APPLICATION_NOT_RESPONDING_TIMEOUT = 5000;
- private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
-
- private static final Collator sCollator = Collator.getInstance();
-
- private boolean mApplicationsLoaded;
- private boolean mDesktopItemsLoaded;
-
- private ArrayList<ItemInfo> mDesktopItems;
- private ArrayList<LauncherAppWidgetInfo> mDesktopAppWidgets;
- private HashMap<Long, FolderInfo> mFolders;
-
- private ArrayList<ApplicationInfo> mApplications;
- private ApplicationsAdapter mApplicationsAdapter;
- private ApplicationsLoader mApplicationsLoader;
- private DesktopItemsLoader mDesktopItemsLoader;
- private Thread mApplicationsLoaderThread;
- private Thread mDesktopLoaderThread;
-
- private final HashMap<ComponentName, ApplicationInfo> mAppInfoCache =
- new HashMap<ComponentName, ApplicationInfo>(INITIAL_ICON_CACHE_CAPACITY);
-
- synchronized void abortLoaders() {
- if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
- mApplicationsLoader.stop();
- mApplicationsLoaded = false;
- }
-
- if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) {
- mDesktopItemsLoader.stop();
- mDesktopItemsLoaded = false;
- }
+ static final String TAG = "Launcher.Model";
+
+ private final Object mLock = new Object();
+ private DeferredHandler mHandler = new DeferredHandler();
+ private Loader mLoader = new Loader();
+
+ private WeakReference<Callbacks> mCallbacks;
+
+ private AllAppsList mAllAppsList = new AllAppsList();
+
+ public interface Callbacks {
+ public int getCurrentWorkspaceScreen();
+ public void startBinding();
+ public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end);
+ public void finishBindingItems();
+ public void bindAppWidget(LauncherAppWidgetInfo info);
+ public void bindAllApplications(ArrayList<ApplicationInfo> apps);
+ public void bindPackageAdded(ArrayList<ApplicationInfo> apps);
+ public void bindPackageUpdated(String packageName, ArrayList<ApplicationInfo> apps);
+ public void bindPackageRemoved(String packageName, ArrayList<ApplicationInfo> apps);
}
- /**
- * Drop our cache of components to their lables & icons. We do
- * this from Launcher when applications are added/removed. It's a
- * bit overkill, but it's a rare operation anyway.
- */
- synchronized void dropApplicationCache() {
- mAppInfoCache.clear();
- }
/**
- * Loads the list of installed applications in mApplications.
- *
- * @return true if the applications loader must be started
- * (see startApplicationsLoader()), false otherwise.
+ * Adds an item to the DB if it was not created previously, or move it to a new
+ * <container, screen, cellX, cellY>
*/
- synchronized boolean loadApplications(boolean isLaunching, Launcher launcher,
- boolean localeChanged) {
-
- if (DEBUG_LOADERS) d(LOG_TAG, "load applications");
-
- if (isLaunching && mApplicationsLoaded && !localeChanged) {
- mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
- if (DEBUG_LOADERS) d(LOG_TAG, " --> applications loaded, return");
- return false;
- }
-
- stopAndWaitForApplicationsLoader();
-
- if (localeChanged) {
- dropApplicationCache();
- }
-
- if (mApplicationsAdapter == null || isLaunching || localeChanged) {
- mApplications = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER);
- mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
- }
-
- mApplicationsLoaded = false;
-
- if (!isLaunching) {
- startApplicationsLoader(launcher, false);
- return false;
+ static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,
+ int screen, int cellX, int cellY) {
+ if (item.container == ItemInfo.NO_ID) {
+ // From all apps
+ addItemToDatabase(context, item, container, screen, cellX, cellY, false);
+ } else {
+ // From somewhere else
+ moveItemInDatabase(context, item, container, screen, cellX, cellY);
}
-
- return true;
}
- private synchronized void stopAndWaitForApplicationsLoader() {
- if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
- if (DEBUG_LOADERS) d(LOG_TAG, " --> wait for applications loader");
-
- mApplicationsLoader.stop();
- // Wait for the currently running thread to finish, this can take a little
- // time but it should be well below the timeout limit
- try {
- mApplicationsLoaderThread.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
- } catch (InterruptedException e) {
- // EMpty
- }
- }
- }
+ /**
+ * Move an item in the DB to a new <container, screen, cellX, cellY>
+ */
+ static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen,
+ int cellX, int cellY) {
+ item.container = container;
+ item.screen = screen;
+ item.cellX = cellX;
+ item.cellY = cellY;
- private synchronized void startApplicationsLoader(Launcher launcher, boolean isLaunching) {
- if (DEBUG_LOADERS) d(LOG_TAG, " --> starting applications loader");
+ final ContentValues values = new ContentValues();
+ final ContentResolver cr = context.getContentResolver();
- stopAndWaitForApplicationsLoader();
+ values.put(LauncherSettings.Favorites.CONTAINER, item.container);
+ values.put(LauncherSettings.Favorites.CELLX, item.cellX);
+ values.put(LauncherSettings.Favorites.CELLY, item.cellY);
+ values.put(LauncherSettings.Favorites.SCREEN, item.screen);
- mApplicationsLoader = new ApplicationsLoader(launcher, isLaunching);
- mApplicationsLoaderThread = new Thread(mApplicationsLoader, "Applications Loader");
- mApplicationsLoaderThread.start();
+ cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
}
- synchronized void addPackage(Launcher launcher, String packageName) {
- if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
- startApplicationsLoader(launcher, false);
- return;
- }
-
- if (packageName != null && packageName.length() > 0) {
- final PackageManager packageManager = launcher.getPackageManager();
- final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
-
- if (matches.size() > 0) {
- final ApplicationsAdapter adapter = mApplicationsAdapter;
- final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
-
- for (ResolveInfo info : matches) {
- adapter.setNotifyOnChange(false);
- adapter.add(makeAndCacheApplicationInfo(packageManager, cache, info, launcher));
- }
-
- adapter.sort(new ApplicationInfoComparator());
- adapter.notifyDataSetChanged();
- }
+ /**
+ * Returns true if the shortcuts already exists in the database.
+ * we identify a shortcut by its title and intent.
+ */
+ static boolean shortcutExists(Context context, String title, Intent intent) {
+ final ContentResolver cr = context.getContentResolver();
+ Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
+ new String[] { "title", "intent" }, "title=? and intent=?",
+ new String[] { title, intent.toUri(0) }, null);
+ boolean result = false;
+ try {
+ result = c.moveToFirst();
+ } finally {
+ c.close();
}
+ return result;
}
- synchronized void removePackage(Launcher launcher, String packageName) {
- if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
- dropApplicationCache(); // TODO: this could be optimized
- startApplicationsLoader(launcher, false);
- return;
- }
-
- if (packageName != null && packageName.length() > 0) {
- final ApplicationsAdapter adapter = mApplicationsAdapter;
+ /**
+ * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
+ */
+ FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {
+ final ContentResolver cr = context.getContentResolver();
+ Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
+ "_id=? and (itemType=? or itemType=?)",
+ new String[] { String.valueOf(id),
+ String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER),
+ String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) }, null);
- final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>();
- final int count = adapter.getCount();
+ try {
+ if (c.moveToFirst()) {
+ final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+ final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+ final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
+ final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
+ final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+ final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
- for (int i = 0; i < count; i++) {
- final ApplicationInfo applicationInfo = adapter.getItem(i);
- final Intent intent = applicationInfo.intent;
- final ComponentName component = intent.getComponent();
- if (packageName.equals(component.getPackageName())) {
- toRemove.add(applicationInfo);
+ FolderInfo folderInfo = null;
+ switch (c.getInt(itemTypeIndex)) {
+ case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+ folderInfo = findOrMakeUserFolder(folderList, id);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
+ folderInfo = findOrMakeLiveFolder(folderList, id);
+ break;
}
- }
- final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
- for (ApplicationInfo info : toRemove) {
- adapter.setNotifyOnChange(false);
- adapter.remove(info);
- cache.remove(info.intent.getComponent());
- }
+ folderInfo.title = c.getString(titleIndex);
+ folderInfo.id = id;
+ folderInfo.container = c.getInt(containerIndex);
+ folderInfo.screen = c.getInt(screenIndex);
+ folderInfo.cellX = c.getInt(cellXIndex);
+ folderInfo.cellY = c.getInt(cellYIndex);
- if (toRemove.size() > 0) {
- adapter.sort(new ApplicationInfoComparator());
- adapter.notifyDataSetChanged();
+ return folderInfo;
}
- }
- }
-
- synchronized void updatePackage(Launcher launcher, String packageName) {
- if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
- startApplicationsLoader(launcher, false);
- return;
+ } finally {
+ c.close();
}
- if (packageName != null && packageName.length() > 0) {
- final PackageManager packageManager = launcher.getPackageManager();
- final ApplicationsAdapter adapter = mApplicationsAdapter;
+ return null;
+ }
- final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
- final int count = matches.size();
+ /**
+ * Add an item to the database in a specified container. Sets the container, screen, cellX and
+ * cellY fields of the item. Also assigns an ID to the item.
+ */
+ static void addItemToDatabase(Context context, ItemInfo item, long container,
+ int screen, int cellX, int cellY, boolean notify) {
+ item.container = container;
+ item.screen = screen;
+ item.cellX = cellX;
+ item.cellY = cellY;
- boolean changed = false;
+ final ContentValues values = new ContentValues();
+ final ContentResolver cr = context.getContentResolver();
- for (int i = 0; i < count; i++) {
- final ResolveInfo info = matches.get(i);
- final ApplicationInfo applicationInfo = findIntent(adapter,
- info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
- if (applicationInfo != null) {
- updateAndCacheApplicationInfo(packageManager, info, applicationInfo, launcher);
- changed = true;
- }
- }
+ item.onAddToDatabase(values);
- if (syncLocked(launcher, packageName)) changed = true;
+ Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
+ LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
- if (changed) {
- adapter.sort(new ApplicationInfoComparator());
- adapter.notifyDataSetChanged();
- }
+ if (result != null) {
+ item.id = Integer.parseInt(result.getPathSegments().get(1));
}
}
- private void updateAndCacheApplicationInfo(PackageManager packageManager, ResolveInfo info,
- ApplicationInfo applicationInfo, Context context) {
+ /**
+ * Update an item to the database in a specified container.
+ */
+ static void updateItemInDatabase(Context context, ItemInfo item) {
+ final ContentValues values = new ContentValues();
+ final ContentResolver cr = context.getContentResolver();
- updateApplicationInfoTitleAndIcon(packageManager, info, applicationInfo, context);
+ item.onAddToDatabase(values);
- ComponentName componentName = new ComponentName(
- info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
- mAppInfoCache.put(componentName, applicationInfo);
+ cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
}
- synchronized void syncPackage(Launcher launcher, String packageName) {
- if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
- startApplicationsLoader(launcher, false);
- return;
- }
+ /**
+ * Removes the specified item from the database
+ * @param context
+ * @param item
+ */
+ static void deleteItemFromDatabase(Context context, ItemInfo item) {
+ final ContentResolver cr = context.getContentResolver();
- if (packageName != null && packageName.length() > 0) {
- if (syncLocked(launcher, packageName)) {
- final ApplicationsAdapter adapter = mApplicationsAdapter;
- adapter.sort(new ApplicationInfoComparator());
- adapter.notifyDataSetChanged();
- }
- }
+ cr.delete(LauncherSettings.Favorites.getContentUri(item.id, false), null, null);
}
- private boolean syncLocked(Launcher launcher, String packageName) {
- final PackageManager packageManager = launcher.getPackageManager();
- final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
-
- if (matches.size() > 0) {
- final ApplicationsAdapter adapter = mApplicationsAdapter;
-
- // Find disabled activities and remove them from the adapter
- boolean removed = removeDisabledActivities(packageName, matches, adapter);
- // Find enable activities and add them to the adapter
- // Also updates existing activities with new labels/icons
- boolean added = addEnabledAndUpdateActivities(matches, adapter, launcher);
-
- return added || removed;
- }
+ /**
+ * Remove the contents of the specified folder from the database
+ */
+ static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) {
+ final ContentResolver cr = context.getContentResolver();
- return false;
+ cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
+ cr.delete(LauncherSettings.Favorites.CONTENT_URI,
+ LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
}
- private static List<ResolveInfo> findActivitiesForPackage(PackageManager packageManager,
- String packageName) {
-
- final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
- final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
- final List<ResolveInfo> matches = new ArrayList<ResolveInfo>();
-
- if (apps != null) {
- // Find all activities that match the packageName
- int count = apps.size();
- for (int i = 0; i < count; i++) {
- final ResolveInfo info = apps.get(i);
- final ActivityInfo activityInfo = info.activityInfo;
- if (packageName.equals(activityInfo.packageName)) {
- matches.add(info);
- }
- }
+ /**
+ * Set this as the current Launcher activity object for the loader.
+ */
+ public void initialize(Callbacks callbacks) {
+ synchronized (mLock) {
+ mCallbacks = new WeakReference<Callbacks>(callbacks);
}
+ }
- return matches;
+ public void startLoader(Context context, boolean isLaunching) {
+ mLoader.startLoader(context, isLaunching);
}
- private boolean addEnabledAndUpdateActivities(List<ResolveInfo> matches,
- ApplicationsAdapter adapter, Launcher launcher) {
+ public void stopLoader() {
+ mLoader.stopLoader();
+ }
- final List<ApplicationInfo> toAdd = new ArrayList<ApplicationInfo>();
- final int count = matches.size();
+ public void setWorkspaceDirty() {
+ mLoader.setWorkspaceDirty();
+ }
- boolean changed = false;
+ /**
+ * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
+ * ACTION_PACKAGE_CHANGED.
+ */
+ public void onReceiveIntent(Context context, Intent intent) {
+ final String packageName = intent.getData().getSchemeSpecificPart();
+
+ ArrayList<ApplicationInfo> added = null;
+ ArrayList<ApplicationInfo> removed = null;
+ ArrayList<ApplicationInfo> modified = null;
+ boolean update = false;
+ boolean remove = false;
+
+ synchronized (mLock) {
+ final String action = intent.getAction();
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+
+ if (packageName == null || packageName.length() == 0) {
+ // they sent us a bad intent
+ return;
+ }
- for (int i = 0; i < count; i++) {
- final ResolveInfo info = matches.get(i);
- final ApplicationInfo applicationInfo = findIntent(adapter,
- info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
- if (applicationInfo == null) {
- toAdd.add(makeAndCacheApplicationInfo(launcher.getPackageManager(),
- mAppInfoCache, info, launcher));
- changed = true;
+ if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ mAllAppsList.updatePackage(context, packageName);
+ update = true;
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ if (!replacing) {
+ mAllAppsList.removePackage(packageName);
+ remove = true;
+ }
+ // else, we are replacing the package, so a PACKAGE_ADDED will be sent
+ // later, we will update the package at this time
} else {
- updateAndCacheApplicationInfo(
- launcher.getPackageManager(), info, applicationInfo, launcher);
- changed = true;
+ if (!replacing) {
+ mAllAppsList.addPackage(context, packageName);
+ } else {
+ mAllAppsList.updatePackage(context, packageName);
+ update = true;
+ }
}
- }
-
- for (ApplicationInfo info : toAdd) {
- adapter.setNotifyOnChange(false);
- adapter.add(info);
- }
-
- return changed;
- }
-
- private boolean removeDisabledActivities(String packageName, List<ResolveInfo> matches,
- ApplicationsAdapter adapter) {
-
- final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>();
- final int count = adapter.getCount();
- boolean changed = false;
-
- for (int i = 0; i < count; i++) {
- final ApplicationInfo applicationInfo = adapter.getItem(i);
- final Intent intent = applicationInfo.intent;
- final ComponentName component = intent.getComponent();
- if (packageName.equals(component.getPackageName())) {
- if (!findIntent(matches, component)) {
- toRemove.add(applicationInfo);
- changed = true;
+ if (mAllAppsList.added.size() > 0) {
+ added = mAllAppsList.added;
+ added = new ArrayList();
+ }
+ if (mAllAppsList.removed.size() > 0) {
+ removed = mAllAppsList.removed;
+ removed = new ArrayList();
+ for (ApplicationInfo info: removed) {
+ AppInfoCache.remove(info.intent.getComponent());
}
}
- }
-
- final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
- for (ApplicationInfo info : toRemove) {
- adapter.setNotifyOnChange(false);
- adapter.remove(info);
- cache.remove(info.intent.getComponent());
- }
-
- return changed;
- }
-
- private static ApplicationInfo findIntent(ApplicationsAdapter adapter, String packageName,
- String name) {
-
- final int count = adapter.getCount();
- for (int i = 0; i < count; i++) {
- final ApplicationInfo applicationInfo = adapter.getItem(i);
- final Intent intent = applicationInfo.intent;
- final ComponentName component = intent.getComponent();
- if (packageName.equals(component.getPackageName()) &&
- name.equals(component.getClassName())) {
- return applicationInfo;
+ if (mAllAppsList.modified.size() > 0) {
+ modified = mAllAppsList.modified;
+ modified = new ArrayList();
}
- }
-
- return null;
- }
- private static boolean findIntent(List<ResolveInfo> apps, ComponentName component) {
- final String className = component.getClassName();
- for (ResolveInfo info : apps) {
- final ActivityInfo activityInfo = info.activityInfo;
- if (activityInfo.name.equals(className)) {
- return true;
+ final Callbacks callbacks = mCallbacks.get();
+ if (callbacks == null) {
+ return;
}
- }
- return false;
- }
-
- Drawable getApplicationInfoIcon(PackageManager manager, ApplicationInfo info) {
- final ResolveInfo resolveInfo = manager.resolveActivity(info.intent, 0);
- if (resolveInfo == null) {
- return null;
- }
-
- ComponentName componentName = new ComponentName(
- resolveInfo.activityInfo.applicationInfo.packageName,
- resolveInfo.activityInfo.name);
- ApplicationInfo application = mAppInfoCache.get(componentName);
-
- if (application == null) {
- return resolveInfo.activityInfo.loadIcon(manager);
- }
-
- return application.icon;
- }
-
- private static ApplicationInfo makeAndCacheApplicationInfo(PackageManager manager,
- HashMap<ComponentName, ApplicationInfo> appInfoCache, ResolveInfo info,
- Context context) {
-
- ComponentName componentName = new ComponentName(
- info.activityInfo.applicationInfo.packageName,
- info.activityInfo.name);
- ApplicationInfo application = appInfoCache.get(componentName);
- if (application == null) {
- application = new ApplicationInfo();
- application.container = ItemInfo.NO_ID;
-
- updateApplicationInfoTitleAndIcon(manager, info, application, context);
-
- application.setActivity(componentName,
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-
- appInfoCache.put(componentName, application);
- }
-
- return application;
- }
-
- private static void updateApplicationInfoTitleAndIcon(PackageManager manager, ResolveInfo info,
- ApplicationInfo application, Context context) {
-
- application.title = info.loadLabel(manager);
- if (application.title == null) {
- application.title = info.activityInfo.name;
+ if (added != null) {
+ final ArrayList<ApplicationInfo> addedFinal = added;
+ mHandler.post(new Runnable() {
+ public void run() {
+ callbacks.bindPackageAdded(addedFinal);
+ }
+ });
+ }
+ if (update || modified != null) {
+ final ArrayList<ApplicationInfo> modifiedFinal = modified;
+ mHandler.post(new Runnable() {
+ public void run() {
+ callbacks.bindPackageUpdated(packageName, modifiedFinal);
+ }
+ });
+ }
+ if (remove || removed != null) {
+ final ArrayList<ApplicationInfo> removedFinal = removed;
+ mHandler.post(new Runnable() {
+ public void run() {
+ callbacks.bindPackageRemoved(packageName, removedFinal);
+ }
+ });
+ }
}
-
- application.icon =
- Utilities.createIconThumbnail(info.activityInfo.loadIcon(manager), context);
- application.filtered = false;
}
- private class ApplicationsLoader implements Runnable {
- private final WeakReference<Launcher> mLauncher;
+ public class Loader {
+ private static final int ITEMS_CHUNK = 6;
- private volatile boolean mStopped;
- private volatile boolean mRunning;
- private final boolean mIsLaunching;
+ private LoaderThread mLoaderThread;
- ApplicationsLoader(Launcher launcher, boolean isLaunching) {
- mIsLaunching = isLaunching;
- mLauncher = new WeakReference<Launcher>(launcher);
- }
+ private int mLastWorkspaceSeq = 0;
+ private int mWorkspaceSeq = 1;
- void stop() {
- mStopped = true;
- }
+ private int mLastAllAppsSeq = 0;
+ private int mAllAppsSeq = 1;
- boolean isRunning() {
- return mRunning;
+ final ArrayList<ItemInfo> mItems = new ArrayList();
+ final ArrayList<LauncherAppWidgetInfo> mAppWidgets = new ArrayList();
+ final HashMap<Long, FolderInfo> folders = new HashMap();
+
+ /**
+ * Call this from the ui thread so the handler is initialized on the correct thread.
+ */
+ public Loader() {
}
- public void run() {
- mRunning = true;
-
- // Elevate priority when Home launches for the first time to avoid
- // starving at boot time. Staring at a blank home is not cool.
- android.os.Process.setThreadPriority(mIsLaunching ? Process.THREAD_PRIORITY_DEFAULT :
- Process.THREAD_PRIORITY_BACKGROUND);
-
- final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
- final Launcher launcher = mLauncher.get();
- final PackageManager manager = launcher.getPackageManager();
- final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
-
- if (apps != null && !mStopped) {
- final int count = apps.size();
- // Can be set to null on the UI thread by the unbind() method
- // Do not access without checking for null first
- final ApplicationsAdapter applicationList = mApplicationsAdapter;
-
- ChangeNotifier action = new ChangeNotifier(applicationList, true);
- final HashMap<ComponentName, ApplicationInfo> appInfoCache = mAppInfoCache;
-
- for (int i = 0; i < count && !mStopped; i++) {
- ResolveInfo info = apps.get(i);
- ApplicationInfo application =
- makeAndCacheApplicationInfo(manager, appInfoCache, info, launcher);
-
- if (action.add(application) && !mStopped) {
- launcher.runOnUiThread(action);
- action = new ChangeNotifier(applicationList, false);
+ public void startLoader(Context context, boolean isLaunching) {
+ synchronized (mLock) {
+ Log.d(TAG, "startLoader isLaunching=" + isLaunching);
+ // Don't bother to start the thread if we know it's not going to do anything
+ if (mCallbacks.get() != null) {
+ LoaderThread oldThread = mLoaderThread;
+ if (oldThread != null) {
+ if (oldThread.isLaunching()) {
+ // don't downgrade isLaunching if we're already running
+ isLaunching = true;
+ }
+ oldThread.stopLocked();
}
+ mLoaderThread = new LoaderThread(context, oldThread, isLaunching);
+ mLoaderThread.start();
}
-
- launcher.runOnUiThread(action);
}
-
- if (!mStopped) {
- mApplicationsLoaded = true;
- }
- mRunning = false;
}
- }
- private static class ChangeNotifier implements Runnable {
- private final ApplicationsAdapter mApplicationList;
- private final ArrayList<ApplicationInfo> mBuffer;
-
- private boolean mFirst = true;
-
- ChangeNotifier(ApplicationsAdapter applicationList, boolean first) {
- mApplicationList = applicationList;
- mFirst = first;
- mBuffer = new ArrayList<ApplicationInfo>(UI_NOTIFICATION_RATE);
- }
-
- public void run() {
- final ApplicationsAdapter applicationList = mApplicationList;
- // Can be set to null on the UI thread by the unbind() method
- if (applicationList == null) return;
-
- if (mFirst) {
- applicationList.setNotifyOnChange(false);
- applicationList.clear();
- mFirst = false;
- }
-
- final ArrayList<ApplicationInfo> buffer = mBuffer;
- final int count = buffer.size();
-
- for (int i = 0; i < count; i++) {
- applicationList.setNotifyOnChange(false);
- applicationList.add(buffer.get(i));
+ public void stopLoader() {
+ synchronized (mLock) {
+ if (mLoaderThread != null) {
+ mLoaderThread.stopLocked();
+ }
}
-
- buffer.clear();
-
- applicationList.sort(new ApplicationInfoComparator());
- applicationList.notifyDataSetChanged();
- }
-
- boolean add(ApplicationInfo application) {
- final ArrayList<ApplicationInfo> buffer = mBuffer;
- buffer.add(application);
- return buffer.size() >= UI_NOTIFICATION_RATE;
}
- }
- static class ApplicationInfoComparator implements Comparator<ApplicationInfo> {
- public final int compare(ApplicationInfo a, ApplicationInfo b) {
- return sCollator.compare(a.title.toString(), b.title.toString());
- }
- }
-
- boolean isDesktopLoaded() {
- return mDesktopItems != null && mDesktopAppWidgets != null && mDesktopItemsLoaded;
- }
-
- /**
- * Loads all of the items on the desktop, in folders, or in the dock.
- * These can be apps, shortcuts or widgets
- */
- void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged,
- boolean loadApplications) {
- if (DEBUG_LOADERS) d(LOG_TAG, "loading user items");
-
- if (isLaunching && isDesktopLoaded()) {
- if (DEBUG_LOADERS) d(LOG_TAG, " --> items loaded, return");
- if (loadApplications) startApplicationsLoader(launcher, true);
- // We have already loaded our data from the DB
- launcher.onDesktopItemsLoaded();
- return;
+ public void setWorkspaceDirty() {
+ synchronized (mLock) {
+ mWorkspaceSeq++;
+ }
}
- if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) {
- if (DEBUG_LOADERS) d(LOG_TAG, " --> stopping workspace loader");
- mDesktopItemsLoader.stop();
- // Wait for the currently running thread to finish, this can take a little
- // time but it should be well below the timeout limit
- try {
- mDesktopLoaderThread.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
- } catch (InterruptedException e) {
- // Empty
+ public void setAllAppsDirty() {
+ synchronized (mLock) {
+ mAllAppsSeq++;
}
-
- // If the thread we are interrupting was tasked to load the list of
- // applications make sure we keep that information in the new loader
- // spawned below
- // note: we don't apply this to localeChanged because the thread can
- // only be stopped *after* the localeChanged handling has occured
- loadApplications = mDesktopItemsLoader.mLoadApplications;
}
- if (DEBUG_LOADERS) d(LOG_TAG, " --> starting workspace loader");
- mDesktopItemsLoaded = false;
- mDesktopItemsLoader = new DesktopItemsLoader(launcher, localeChanged, loadApplications,
- isLaunching);
- mDesktopLoaderThread = new Thread(mDesktopItemsLoader, "Desktop Items Loader");
- mDesktopLoaderThread.start();
- }
-
- private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) {
- final Cursor c = resolver.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.TITLE,
- LauncherSettings.Favorites.INTENT, LauncherSettings.Favorites.ITEM_TYPE },
- null, null, null);
-
- final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
- final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
- final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
- final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+ /**
+ * Runnable for the thread that loads the contents of the launcher:
+ * - workspace icons
+ * - widgets
+ * - all apps icons
+ */
+ private class LoaderThread extends Thread {
+ private Context mContext;
+ private Thread mWaitThread;
+ private boolean mIsLaunching;
+ private boolean mStopped;
+ private boolean mWorkspaceDoneBinding;
+
+ LoaderThread(Context context, Thread waitThread, boolean isLaunching) {
+ mContext = context;
+ mWaitThread = waitThread;
+ mIsLaunching = isLaunching;
+ }
- // boolean changed = false;
+ boolean isLaunching() {
+ return mIsLaunching;
+ }
- try {
- while (c.moveToNext()) {
- try {
- if (c.getInt(itemTypeIndex) !=
- LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- continue;
+ /**
+ * If another LoaderThread was supplied, we need to wait for that to finish before
+ * we start our processing. This keeps the ordering of the setting and clearing
+ * of the dirty flags correct by making sure we don't start processing stuff until
+ * they've had a chance to re-set them. We do this waiting the worker thread, not
+ * the ui thread to avoid ANRs.
+ */
+ private void waitForOtherThread() {
+ if (mWaitThread != null) {
+ boolean done = false;
+ while (!done) {
+ try {
+ mWaitThread.join();
+ } catch (InterruptedException ex) {
+ }
}
+ mWaitThread = null;
+ }
+ }
- final String intentUri = c.getString(intentIndex);
- if (intentUri != null) {
- final Intent shortcut = Intent.parseUri(intentUri, 0);
- if (Intent.ACTION_MAIN.equals(shortcut.getAction())) {
- final ComponentName name = shortcut.getComponent();
- if (name != null) {
- final ActivityInfo activityInfo = manager.getActivityInfo(name, 0);
- final String title = c.getString(titleIndex);
- String label = getLabel(manager, activityInfo);
+ public void run() {
+ waitForOtherThread();
- if (title == null || !title.equals(label)) {
- final ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.TITLE, label);
+ // Elevate priority when Home launches for the first time to avoid
+ // starving at boot time. Staring at a blank home is not cool.
+ synchronized (mLock) {
+ android.os.Process.setThreadPriority(mIsLaunching
+ ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
+ }
- resolver.update(
- LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
- values, "_id=?",
- new String[] { String.valueOf(c.getLong(idIndex)) });
+ // Load the workspace only if it's dirty.
+ int workspaceSeq;
+ boolean workspaceDirty;
+ synchronized (mLock) {
+ workspaceSeq = mWorkspaceSeq;
+ workspaceDirty = mWorkspaceSeq != mLastWorkspaceSeq;
+ }
+ if (workspaceDirty) {
+ loadWorkspace();
+ }
+ synchronized (mLock) {
+ // If we're not stopped, and nobody has incremented mWorkspaceSeq.
+ if (mStopped) {
+ return;
+ }
+ if (workspaceSeq == mWorkspaceSeq) {
+ mLastWorkspaceSeq = mWorkspaceSeq;
+ }
+ }
- // changed = true;
+ // Bind the workspace
+ bindWorkspace();
+
+ // Wait until the either we're stopped or the other threads are done.
+ // This way we don't start loading all apps until the workspace has settled
+ // down.
+ synchronized (LoaderThread.this) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ synchronized (LoaderThread.this) {
+ mWorkspaceDoneBinding = true;
+ Log.d(TAG, "done with workspace");
+ LoaderThread.this.notify();
}
}
+ });
+ Log.d(TAG, "waiting to be done with workspace");
+ while (!mStopped && !mWorkspaceDoneBinding) {
+ try {
+ this.wait();
+ } catch (InterruptedException ex) {
}
}
- } catch (URISyntaxException e) {
- // Ignore
- } catch (PackageManager.NameNotFoundException e) {
- // Ignore
+ Log.d(TAG, "done waiting to be done with workspace");
}
- }
- } finally {
- c.close();
- }
- // if (changed) resolver.notifyChange(Settings.Favorites.CONTENT_URI, null);
- }
+ // Load all apps if they're dirty
+ int allAppsSeq;
+ boolean allAppsDirty;
+ synchronized (mLock) {
+ allAppsSeq = mAllAppsSeq;
+ allAppsDirty = mAllAppsSeq != mLastAllAppsSeq;
+ }
+ if (allAppsDirty) {
+ loadAllApps();
+ }
+ synchronized (mLock) {
+ // If we're not stopped, and nobody has incremented mAllAppsSeq.
+ if (mStopped) {
+ return;
+ }
+ if (allAppsSeq == mAllAppsSeq) {
+ mLastAllAppsSeq = mAllAppsSeq;
+ }
+ }
- private static String getLabel(PackageManager manager, ActivityInfo activityInfo) {
- String label = activityInfo.loadLabel(manager).toString();
- if (label == null) {
- label = manager.getApplicationLabel(activityInfo.applicationInfo).toString();
- if (label == null) {
- label = activityInfo.name;
+ // Bind all apps
+ bindAllApps();
+
+ // Clear out this reference, otherwise we end up holding it until all of the
+ // callback runnables are done.
+ mContext = null;
+
+ synchronized (mLock) {
+ // Setting the reference is atomic, but we can't do it inside the other critical
+ // sections.
+ mLoaderThread = null;
+ return;
+ }
}
- }
- return label;
- }
- private class DesktopItemsLoader implements Runnable {
- private volatile boolean mStopped;
- private volatile boolean mRunning;
-
- private final WeakReference<Launcher> mLauncher;
- private final boolean mLocaleChanged;
- private final boolean mLoadApplications;
- private final boolean mIsLaunching;
-
- DesktopItemsLoader(Launcher launcher, boolean localeChanged, boolean loadApplications,
- boolean isLaunching) {
- mLoadApplications = loadApplications;
- mIsLaunching = isLaunching;
- mLauncher = new WeakReference<Launcher>(launcher);
- mLocaleChanged = localeChanged;
- }
+ public void stopLocked() {
+ synchronized (LoaderThread.this) {
+ mStopped = true;
+ this.notify();
+ }
+ }
- void stop() {
- mStopped = true;
- }
+ /**
+ * Gets the callbacks object. If we've been stopped, or if the launcher object
+ * has somehow been garbage collected, return null instead.
+ */
+ Callbacks tryGetCallbacks() {
+ synchronized (mLock) {
+ if (mStopped) {
+ return null;
+ }
- boolean isRunning() {
- return mRunning;
- }
+ final Callbacks callbacks = mCallbacks.get();
+ if (callbacks == null) {
+ Log.w(TAG, "no mCallbacks");
+ return null;
+ }
- public void run() {
- mRunning = true;
+ return callbacks;
+ }
+ }
- android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ private void loadWorkspace() {
+ long t = SystemClock.uptimeMillis();
- final Launcher launcher = mLauncher.get();
- final ContentResolver contentResolver = launcher.getContentResolver();
- final PackageManager manager = launcher.getPackageManager();
+ final Context context = mContext;
+ final ContentResolver contentResolver = context.getContentResolver();
+ final PackageManager manager = context.getPackageManager();
- if (mLocaleChanged) {
- updateShortcutLabels(contentResolver, manager);
- }
+ /* TODO
+ if (mLocaleChanged) {
+ updateShortcutLabels(contentResolver, manager);
+ }
+ */
- mDesktopItems = new ArrayList<ItemInfo>();
- mDesktopAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
- mFolders = new HashMap<Long, FolderInfo>();
+ final Cursor c = contentResolver.query(
+ LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
- final ArrayList<ItemInfo> desktopItems = mDesktopItems;
- final ArrayList<LauncherAppWidgetInfo> desktopAppWidgets = mDesktopAppWidgets;
+ 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);
+
+ ApplicationInfo info;
+ String intentDescription;
+ Widget widgetInfo;
+ LauncherAppWidgetInfo appWidgetInfo;
+ int container;
+ long id;
+ Intent intent;
+
+ while (!mStopped && c.moveToNext()) {
+ try {
+ int itemType = c.getInt(itemTypeIndex);
- final Cursor c = contentResolver.query(
- LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
+ 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;
+ }
- 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);
-
- ApplicationInfo info;
- String intentDescription;
- Widget widgetInfo;
- LauncherAppWidgetInfo appWidgetInfo;
- int container;
- long id;
- Intent intent;
-
- final HashMap<Long, FolderInfo> folders = mFolders;
-
- 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 (java.net.URISyntaxException e) {
- continue;
- }
+ if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+ info = getApplicationInfo(manager, intent, context);
+ } else {
+ info = getApplicationInfoShortcut(c, context, iconTypeIndex,
+ iconPackageIndex, iconResourceIndex, iconIndex);
+ }
- if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = getApplicationInfo(manager, intent, launcher);
- } else {
- info = getApplicationInfoShortcut(c, launcher, iconTypeIndex,
- iconPackageIndex, iconResourceIndex, iconIndex);
- }
+ if (info == null) {
+ info = new ApplicationInfo();
+ info.icon = manager.getDefaultActivityIcon();
+ }
- if (info == null) {
- info = new ApplicationInfo();
- info.icon = manager.getDefaultActivityIcon();
- }
+ if (info != null) {
+ info.title = c.getString(titleIndex);
+ 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);
+
+ switch (container) {
+ case LauncherSettings.Favorites.CONTAINER_DESKTOP:
+ mItems.add(info);
+ break;
+ default:
+ // Item is in a user folder
+ UserFolderInfo folderInfo =
+ findOrMakeUserFolder(folders, container);
+ folderInfo.add(info);
+ break;
+ }
+ }
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+
+ id = c.getLong(idIndex);
+ UserFolderInfo folderInfo = findOrMakeUserFolder(folders, id);
- if (info != null) {
- info.title = c.getString(titleIndex);
- info.intent = intent;
+ folderInfo.title = c.getString(titleIndex);
- info.id = c.getLong(idIndex);
+ folderInfo.id = id;
container = c.getInt(containerIndex);
- info.container = container;
- info.screen = c.getInt(screenIndex);
- info.cellX = c.getInt(cellXIndex);
- info.cellY = c.getInt(cellYIndex);
+ folderInfo.container = container;
+ folderInfo.screen = c.getInt(screenIndex);
+ folderInfo.cellX = c.getInt(cellXIndex);
+ folderInfo.cellY = c.getInt(cellYIndex);
switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- desktopItems.add(info);
- break;
- default:
- // Item is in a user folder
- UserFolderInfo folderInfo =
- findOrMakeUserFolder(folders, container);
- folderInfo.add(info);
- break;
+ case LauncherSettings.Favorites.CONTAINER_DESKTOP:
+ mItems.add(folderInfo);
+ break;
+ }
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
+
+ id = c.getLong(idIndex);
+ LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(folders, id);
+
+ intentDescription = c.getString(intentIndex);
+ intent = null;
+ if (intentDescription != null) {
+ try {
+ intent = Intent.parseUri(intentDescription, 0);
+ } catch (URISyntaxException e) {
+ // Ignore, a live folder might not have a base intent
+ }
}
- }
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
- id = c.getLong(idIndex);
- UserFolderInfo folderInfo = findOrMakeUserFolder(folders, id);
+ liveFolderInfo.title = c.getString(titleIndex);
+ liveFolderInfo.id = id;
+ container = c.getInt(containerIndex);
+ liveFolderInfo.container = container;
+ liveFolderInfo.screen = c.getInt(screenIndex);
+ liveFolderInfo.cellX = c.getInt(cellXIndex);
+ liveFolderInfo.cellY = c.getInt(cellYIndex);
+ liveFolderInfo.uri = Uri.parse(c.getString(uriIndex));
+ liveFolderInfo.baseIntent = intent;
+ liveFolderInfo.displayMode = c.getInt(displayModeIndex);
- folderInfo.title = c.getString(titleIndex);
+ loadLiveFolderIcon(context, c, iconTypeIndex, iconPackageIndex,
+ iconResourceIndex, liveFolderInfo);
- 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);
+ switch (container) {
+ case LauncherSettings.Favorites.CONTAINER_DESKTOP:
+ mItems.add(liveFolderInfo);
+ break;
+ }
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
+ widgetInfo = Widget.makeSearch();
- switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- desktopItems.add(folderInfo);
- break;
- }
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
+ container = c.getInt(containerIndex);
+ if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ Log.e(TAG, "Widget found where container "
+ + "!= CONTAINER_DESKTOP ignoring!");
+ continue;
+ }
- id = c.getLong(idIndex);
- LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(folders, id);
+ widgetInfo.id = c.getLong(idIndex);
+ widgetInfo.screen = c.getInt(screenIndex);
+ widgetInfo.container = container;
+ widgetInfo.cellX = c.getInt(cellXIndex);
+ widgetInfo.cellY = c.getInt(cellYIndex);
+
+ mItems.add(widgetInfo);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ // Read all Launcher-specific widget details
+ int appWidgetId = c.getInt(appWidgetIdIndex);
+ appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId);
+ appWidgetInfo.id = c.getLong(idIndex);
+ 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);
- intentDescription = c.getString(intentIndex);
- intent = null;
- if (intentDescription != null) {
- try {
- intent = Intent.parseUri(intentDescription, 0);
- } catch (java.net.URISyntaxException e) {
- // Ignore, a live folder might not have a base intent
+ container = c.getInt(containerIndex);
+ if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ Log.e(TAG, "Widget found where container "
+ + "!= CONTAINER_DESKTOP -- ignoring!");
+ continue;
}
- }
+ appWidgetInfo.container = c.getInt(containerIndex);
- liveFolderInfo.title = c.getString(titleIndex);
- liveFolderInfo.id = id;
- container = c.getInt(containerIndex);
- liveFolderInfo.container = container;
- liveFolderInfo.screen = c.getInt(screenIndex);
- liveFolderInfo.cellX = c.getInt(cellXIndex);
- liveFolderInfo.cellY = c.getInt(cellYIndex);
- liveFolderInfo.uri = Uri.parse(c.getString(uriIndex));
- liveFolderInfo.baseIntent = intent;
- liveFolderInfo.displayMode = c.getInt(displayModeIndex);
-
- loadLiveFolderIcon(launcher, c, iconTypeIndex, iconPackageIndex,
- iconResourceIndex, liveFolderInfo);
-
- switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- desktopItems.add(liveFolderInfo);
- break;
- }
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
- widgetInfo = Widget.makeSearch();
-
- container = c.getInt(containerIndex);
- if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- e(Launcher.LOG_TAG, "Widget found where container "
- + "!= CONTAINER_DESKTOP ignoring!");
- continue;
+ mAppWidgets.add(appWidgetInfo);
+ break;
}
-
- widgetInfo.id = c.getLong(idIndex);
- widgetInfo.screen = c.getInt(screenIndex);
- widgetInfo.container = container;
- widgetInfo.cellX = c.getInt(cellXIndex);
- widgetInfo.cellY = c.getInt(cellYIndex);
-
- desktopItems.add(widgetInfo);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- // Read all Launcher-specific widget details
- int appWidgetId = c.getInt(appWidgetIdIndex);
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId);
- appWidgetInfo.id = c.getLong(idIndex);
- 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);
-
- container = c.getInt(containerIndex);
- if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- e(Launcher.LOG_TAG, "Widget found where container "
- + "!= CONTAINER_DESKTOP -- ignoring!");
- continue;
- }
- appWidgetInfo.container = c.getInt(containerIndex);
-
- desktopAppWidgets.add(appWidgetInfo);
- break;
+ } catch (Exception e) {
+ Log.w(TAG, "Desktop items loading interrupted:", e);
}
- } catch (Exception e) {
- w(Launcher.LOG_TAG, "Desktop items loading interrupted:", e);
}
+ } finally {
+ c.close();
}
- } finally {
- c.close();
+ Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");
}
- if (!mStopped) {
- launcher.runOnUiThread(new Runnable() {
+ /**
+ * 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.
+ Callbacks callbacks = mCallbacks.get();
+ if (callbacks == null) {
+ // This launcher has exited and nobody bothered to tell us. Just bail.
+ Log.w(TAG, "LoaderThread running with no launcher");
+ return;
+ }
+
+ int N;
+ // Tell the workspace that we're about to start firing items at it
+ mHandler.post(new Runnable() {
public void run() {
- launcher.onDesktopItemsLoaded();
+ Callbacks callbacks = tryGetCallbacks();
+ if (callbacks != null) {
+ callbacks.startBinding();
+ }
+ }
+ });
+ // Add the items to the workspace.
+ N = mItems.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();
+ if (callbacks != null) {
+ callbacks.bindItems(mItems, start, start+chunkSize);
+ }
+ }
+ });
+ }
+ // Wait until the queue goes empty.
+ mHandler.postIdle(new Runnable() {
+ public void run() {
+ 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.
+ final int currentScreen = callbacks.getCurrentWorkspaceScreen();
+ N = mAppWidgets.size();
+ // once for the current screen
+ for (int i=0; i<N; i++) {
+ final LauncherAppWidgetInfo widget = mAppWidgets.get(i);
+ if (widget.screen == currentScreen) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ Callbacks callbacks = tryGetCallbacks();
+ if (callbacks != null) {
+ callbacks.bindAppWidget(widget);
+ }
+ }
+ });
+ }
+ }
+ // once for the other screens
+ for (int i=0; i<N; i++) {
+ final LauncherAppWidgetInfo widget = mAppWidgets.get(i);
+ if (widget.screen != currentScreen) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ Callbacks callbacks = tryGetCallbacks();
+ if (callbacks != null) {
+ callbacks.bindAppWidget(widget);
+ }
+ }
+ });
+ }
+ }
+ // TODO: Bind the folders
+ // Tell the workspace that we're done.
+ mHandler.post(new Runnable() {
+ public void run() {
+ Callbacks callbacks = tryGetCallbacks();
+ if (callbacks != null) {
+ callbacks.finishBindingItems();
+ }
+ }
+ });
+ // If we're profiling, this is the last thing in the queue.
+ mHandler.post(new Runnable() {
+ public void run() {
+ Log.d(TAG, "bound workspace in " + (SystemClock.uptimeMillis()-t) + "ms");
+ if (Launcher.PROFILE_ROTATE) {
+ android.os.Debug.stopMethodTracing();
+ }
}
});
- if (mLoadApplications) startApplicationsLoader(launcher, mIsLaunching);
- }
-
- if (!mStopped) {
- mDesktopItemsLoaded = true;
}
- mRunning = false;
- }
- }
- private static void loadLiveFolderIcon(Launcher launcher, Cursor c, int iconTypeIndex,
- int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) {
+ private void loadAllApps() {
+ final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- int iconType = c.getInt(iconTypeIndex);
- switch (iconType) {
- case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
- String packageName = c.getString(iconPackageIndex);
- String resourceName = c.getString(iconResourceIndex);
- PackageManager packageManager = launcher.getPackageManager();
- try {
- Resources resources = packageManager.getResourcesForApplication(packageName);
- final int id = resources.getIdentifier(resourceName, null, null);
- liveFolderInfo.icon = resources.getDrawable(id);
- } catch (Exception e) {
- liveFolderInfo.icon =
- launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);
+ final Callbacks callbacks = tryGetCallbacks();
+ if (callbacks == null) {
+ return;
}
- liveFolderInfo.iconResource = new Intent.ShortcutIconResource();
- liveFolderInfo.iconResource.packageName = packageName;
- liveFolderInfo.iconResource.resourceName = resourceName;
- break;
- default:
- liveFolderInfo.icon =
- launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);
- }
- }
- /**
- * Finds the user folder defined by the specified id.
- *
- * @param id The id of the folder to look for.
- *
- * @return A UserFolderInfo if the folder exists or null otherwise.
- */
- FolderInfo findFolderById(long id) {
- return mFolders.get(id);
- }
+ final Context context = mContext;
+ final PackageManager packageManager = context.getPackageManager();
- void addFolder(FolderInfo info) {
- mFolders.put(info.id, info);
- }
+ final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
- /**
- * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
- * new one.
- */
- private UserFolderInfo findOrMakeUserFolder(HashMap<Long, FolderInfo> folders, long id) {
- // See if a placeholder was created for us already
- FolderInfo folderInfo = folders.get(id);
- if (folderInfo == null || !(folderInfo instanceof UserFolderInfo)) {
- // No placeholder -- create a new instance
- folderInfo = new UserFolderInfo();
- folders.put(id, folderInfo);
- }
- return (UserFolderInfo) folderInfo;
- }
+ synchronized (mLock) {
+ mAllAppsList.clear();
+ if (apps != null) {
+ long t = SystemClock.uptimeMillis();
- /**
- * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
- * new one.
- */
- private LiveFolderInfo findOrMakeLiveFolder(HashMap<Long, FolderInfo> folders, long id) {
- // See if a placeholder was created for us already
- FolderInfo folderInfo = folders.get(id);
- if (folderInfo == null || !(folderInfo instanceof LiveFolderInfo)) {
- // No placeholder -- create a new instance
- folderInfo = new LiveFolderInfo();
- folders.put(id, folderInfo);
- }
- return (LiveFolderInfo) folderInfo;
- }
-
- /**
- * Remove the callback for the cached drawables or we leak the previous
- * Home screen on orientation change.
- */
- void unbind() {
- // Interrupt the applications loader before setting the adapter to null
- stopAndWaitForApplicationsLoader();
- mApplicationsAdapter = null;
- unbindAppDrawables(mApplications);
- unbindDrawables(mDesktopItems);
- unbindAppWidgetHostViews(mDesktopAppWidgets);
- unbindCachedIconDrawables();
- }
-
- /**
- * Remove the callback for the cached drawables or we leak the previous
- * Home screen on orientation change.
- */
- private void unbindDrawables(ArrayList<ItemInfo> desktopItems) {
- if (desktopItems != null) {
- final int count = desktopItems.size();
- for (int i = 0; i < count; i++) {
- ItemInfo item = desktopItems.get(i);
- switch (item.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- ((ApplicationInfo)item).icon.setCallback(null);
- break;
+ int N = apps.size();
+ Utilities.BubbleText bubble = new Utilities.BubbleText(context);
+ for (int i=0; i<N && !mStopped; i++) {
+ // This builds the icon bitmaps.
+ mAllAppsList.add(AppInfoCache.cache(apps.get(i), context, bubble));
+ }
+ Collections.sort(mAllAppsList.data, sComparator);
+ Collections.sort(mAllAppsList.added, sComparator);
+ Log.d(TAG, "cached app icons in " + (SystemClock.uptimeMillis()-t) + "ms");
+ }
}
}
- }
- }
- /**
- * Remove the callback for the cached drawables or we leak the previous
- * Home screen on orientation change.
- */
- private void unbindAppDrawables(ArrayList<ApplicationInfo> applications) {
- if (applications != null) {
- final int count = applications.size();
- for (int i = 0; i < count; i++) {
- applications.get(i).icon.setCallback(null);
- }
- }
- }
+ private void bindAllApps() {
+ synchronized (mLock) {
+ final ArrayList<ApplicationInfo> results = mAllAppsList.added;
+ mAllAppsList.added = new ArrayList();
+ mHandler.post(new Runnable() {
+ public void run() {
+ long t = SystemClock.uptimeMillis();
+
+ Callbacks callbacks = tryGetCallbacks();
+ if (callbacks != null) {
+ callbacks.bindAllApplications(results);
+ }
- /**
- * Remove any {@link LauncherAppWidgetHostView} references in our widgets.
- */
- private void unbindAppWidgetHostViews(ArrayList<LauncherAppWidgetInfo> appWidgets) {
- if (appWidgets != null) {
- final int count = appWidgets.size();
- for (int i = 0; i < count; i++) {
- LauncherAppWidgetInfo launcherInfo = appWidgets.get(i);
- launcherInfo.hostView = null;
+ Log.d(TAG, "bound app icons in "
+ + (SystemClock.uptimeMillis()-t) + "ms");
+ }
+ });
+ }
}
}
}
/**
- * Remove the callback for the cached drawables or we leak the previous
- * Home screen on orientation change.
- */
- private void unbindCachedIconDrawables() {
- for (ApplicationInfo appInfo : mAppInfoCache.values()) {
- appInfo.icon.setCallback(null);
- }
- }
-
- /**
- * @return The current list of applications
- */
- ApplicationsAdapter getApplicationsAdapter() {
- return mApplicationsAdapter;
- }
-
- /**
- * @return The current list of desktop items
- */
- ArrayList<ItemInfo> getDesktopItems() {
- return mDesktopItems;
- }
-
- /**
- * @return The current list of desktop items
- */
- ArrayList<LauncherAppWidgetInfo> getDesktopAppWidgets() {
- return mDesktopAppWidgets;
- }
-
- /**
- * Add an item to the desktop
- * @param info
- */
- void addDesktopItem(ItemInfo info) {
- // TODO: write to DB; also check that folder has been added to folders list
- mDesktopItems.add(info);
- }
-
- /**
- * Remove an item from the desktop
- * @param info
- */
- void removeDesktopItem(ItemInfo info) {
- // TODO: write to DB; figure out if we should remove folder from folders list
- mDesktopItems.remove(info);
- }
-
- /**
- * Add a widget to the desktop
- */
- void addDesktopAppWidget(LauncherAppWidgetInfo info) {
- mDesktopAppWidgets.add(info);
- }
-
- /**
- * Remove a widget from the desktop
- */
- void removeDesktopAppWidget(LauncherAppWidgetInfo info) {
- mDesktopAppWidgets.remove(info);
- }
-
- /**
- * Make an ApplicationInfo object for an application
+ * Make an ApplicationInfo object for an application.
*/
private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent,
Context context) {
@@ -1149,7 +943,7 @@ public class LauncherModel {
final ApplicationInfo info = new ApplicationInfo();
final ActivityInfo activityInfo = resolveInfo.activityInfo;
- info.icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context);
+ info.icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context, false);
if (info.title == null || info.title.length() == 0) {
info.title = activityInfo.loadLabel(manager);
}
@@ -1163,7 +957,7 @@ public class LauncherModel {
/**
* Make an ApplicationInfo object for a sortcut
*/
- private ApplicationInfo getApplicationInfoShortcut(Cursor c, Context context,
+ private static ApplicationInfo getApplicationInfoShortcut(Cursor c, Context context,
int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) {
final ApplicationInfo info = new ApplicationInfo();
@@ -1171,312 +965,175 @@ public class LauncherModel {
int iconType = c.getInt(iconTypeIndex);
switch (iconType) {
- case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
- String packageName = c.getString(iconPackageIndex);
- String resourceName = c.getString(iconResourceIndex);
- PackageManager packageManager = context.getPackageManager();
- try {
- Resources resources = packageManager.getResourcesForApplication(packageName);
- final int id = resources.getIdentifier(resourceName, null, null);
- info.icon = Utilities.createIconThumbnail(resources.getDrawable(id), context);
- } catch (Exception e) {
- info.icon = packageManager.getDefaultActivityIcon();
- }
- info.iconResource = new Intent.ShortcutIconResource();
- info.iconResource.packageName = packageName;
- info.iconResource.resourceName = resourceName;
- info.customIcon = false;
- break;
- case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
- byte[] data = c.getBlob(iconIndex);
- try {
- Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- info.icon = new FastBitmapDrawable(
- Utilities.createBitmapThumbnail(bitmap, context));
- } catch (Exception e) {
- packageManager = context.getPackageManager();
- info.icon = packageManager.getDefaultActivityIcon();
- }
- info.filtered = true;
- info.customIcon = true;
- break;
- default:
- info.icon = context.getPackageManager().getDefaultActivityIcon();
- info.customIcon = false;
- break;
+ case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
+ String packageName = c.getString(iconPackageIndex);
+ String resourceName = c.getString(iconResourceIndex);
+ PackageManager packageManager = context.getPackageManager();
+ try {
+ Resources resources = packageManager.getResourcesForApplication(packageName);
+ final int id = resources.getIdentifier(resourceName, null, null);
+ info.icon = Utilities.createIconThumbnail(resources.getDrawable(id), context,
+ false);
+ } catch (Exception e) {
+ info.icon = packageManager.getDefaultActivityIcon();
+ }
+ info.iconResource = new Intent.ShortcutIconResource();
+ info.iconResource.packageName = packageName;
+ info.iconResource.resourceName = resourceName;
+ info.customIcon = false;
+ break;
+ case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
+ byte[] data = c.getBlob(iconIndex);
+ try {
+ Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
+ info.icon = new FastBitmapDrawable(
+ Utilities.createBitmapThumbnail(bitmap, context));
+ } catch (Exception e) {
+ packageManager = context.getPackageManager();
+ info.icon = packageManager.getDefaultActivityIcon();
+ }
+ info.filtered = true;
+ info.customIcon = true;
+ break;
+ default:
+ info.icon = context.getPackageManager().getDefaultActivityIcon();
+ info.customIcon = false;
+ break;
}
return info;
}
- /**
- * Remove an item from the in-memory represention of a user folder. Does not change the DB.
- */
- void removeUserFolderItem(UserFolderInfo folder, ItemInfo info) {
- //noinspection SuspiciousMethodCalls
- folder.contents.remove(info);
- }
-
- /**
- * Removes a UserFolder from the in-memory list of folders. Does not change the DB.
- * @param userFolderInfo
- */
- void removeUserFolder(UserFolderInfo userFolderInfo) {
- mFolders.remove(userFolderInfo.id);
- }
-
- /**
- * Adds an item to the DB if it was not created previously, or move it to a new
- * <container, screen, cellX, cellY>
- */
- static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,
- int screen, int cellX, int cellY) {
- if (item.container == ItemInfo.NO_ID) {
- // From all apps
- addItemToDatabase(context, item, container, screen, cellX, cellY, false);
- } else {
- // From somewhere else
- moveItemInDatabase(context, item, container, screen, cellX, cellY);
- }
- }
-
- /**
- * Move an item in the DB to a new <container, screen, cellX, cellY>
- */
- static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen,
- int cellX, int cellY) {
- item.container = container;
- item.screen = screen;
- item.cellX = cellX;
- item.cellY = cellY;
-
- final ContentValues values = new ContentValues();
- final ContentResolver cr = context.getContentResolver();
-
- values.put(LauncherSettings.Favorites.CONTAINER, item.container);
- values.put(LauncherSettings.Favorites.CELLX, item.cellX);
- values.put(LauncherSettings.Favorites.CELLY, item.cellY);
- values.put(LauncherSettings.Favorites.SCREEN, item.screen);
-
- cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
- }
-
- /**
- * Returns true if the shortcuts already exists in the database.
- * we identify a shortcut by its title and intent.
- */
- static boolean shortcutExists(Context context, String title, Intent intent) {
- final ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { "title", "intent" }, "title=? and intent=?",
- new String[] { title, intent.toUri(0) }, null);
- boolean result = false;
- try {
- result = c.moveToFirst();
- } finally {
- c.close();
- }
- return result;
- }
-
- FolderInfo getFolderById(Context context, long id) {
- final ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
- "_id=? and (itemType=? or itemType=?)",
- new String[] { String.valueOf(id),
- String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER),
- String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) }, null);
-
- try {
- if (c.moveToFirst()) {
- final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
- final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
- final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
- final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
-
- FolderInfo folderInfo = null;
- switch (c.getInt(itemTypeIndex)) {
- case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
- folderInfo = findOrMakeUserFolder(mFolders, id);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
- folderInfo = findOrMakeLiveFolder(mFolders, id);
- break;
- }
-
- folderInfo.title = c.getString(titleIndex);
- folderInfo.id = id;
- folderInfo.container = c.getInt(containerIndex);
- folderInfo.screen = c.getInt(screenIndex);
- folderInfo.cellX = c.getInt(cellXIndex);
- folderInfo.cellY = c.getInt(cellYIndex);
+ private static void loadLiveFolderIcon(Context context, Cursor c, int iconTypeIndex,
+ int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) {
- return folderInfo;
+ int iconType = c.getInt(iconTypeIndex);
+ switch (iconType) {
+ case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
+ String packageName = c.getString(iconPackageIndex);
+ String resourceName = c.getString(iconResourceIndex);
+ PackageManager packageManager = context.getPackageManager();
+ try {
+ Resources resources = packageManager.getResourcesForApplication(packageName);
+ final int id = resources.getIdentifier(resourceName, null, null);
+ liveFolderInfo.icon = resources.getDrawable(id);
+ } catch (Exception e) {
+ liveFolderInfo.icon =
+ context.getResources().getDrawable(R.drawable.ic_launcher_folder);
}
- } finally {
- c.close();
+ liveFolderInfo.iconResource = new Intent.ShortcutIconResource();
+ liveFolderInfo.iconResource.packageName = packageName;
+ liveFolderInfo.iconResource.resourceName = resourceName;
+ break;
+ default:
+ liveFolderInfo.icon =
+ context.getResources().getDrawable(R.drawable.ic_launcher_folder);
}
-
- return null;
}
/**
- * Add an item to the database in a specified container. Sets the container, screen, cellX and
- * cellY fields of the item. Also assigns an ID to the item.
+ * Return an existing UserFolderInfo object if we have encountered this ID previously,
+ * or make a new one.
*/
- static void addItemToDatabase(Context context, ItemInfo item, long container,
- int screen, int cellX, int cellY, boolean notify) {
- item.container = container;
- item.screen = screen;
- item.cellX = cellX;
- item.cellY = cellY;
-
- final ContentValues values = new ContentValues();
- final ContentResolver cr = context.getContentResolver();
-
- item.onAddToDatabase(values);
-
- Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
- LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
-
- if (result != null) {
- item.id = Integer.parseInt(result.getPathSegments().get(1));
+ private static UserFolderInfo findOrMakeUserFolder(HashMap<Long, FolderInfo> folders, long id) {
+ // See if a placeholder was created for us already
+ FolderInfo folderInfo = folders.get(id);
+ if (folderInfo == null || !(folderInfo instanceof UserFolderInfo)) {
+ // No placeholder -- create a new instance
+ folderInfo = new UserFolderInfo();
+ folders.put(id, folderInfo);
}
+ return (UserFolderInfo) folderInfo;
}
/**
- * Add an item to the database in a specified container. Sets the container, screen, cellX and
- * cellY fields of the item. Also assigns an ID to the item.
+ * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
+ * new one.
*/
- static boolean addGestureToDatabase(Context context, ItemInfo item, boolean notify) {
- final ContentValues values = new ContentValues();
- final ContentResolver cr = context.getContentResolver();
-
- item.onAddToDatabase(values);
-
- Uri result = cr.insert(notify ? LauncherSettings.Gestures.CONTENT_URI :
- LauncherSettings.Gestures.CONTENT_URI_NO_NOTIFICATION, values);
-
- if (result != null) {
- item.id = Integer.parseInt(result.getPathSegments().get(1));
+ private static LiveFolderInfo findOrMakeLiveFolder(HashMap<Long, FolderInfo> folders, long id) {
+ // See if a placeholder was created for us already
+ FolderInfo folderInfo = folders.get(id);
+ if (folderInfo == null || !(folderInfo instanceof LiveFolderInfo)) {
+ // No placeholder -- create a new instance
+ folderInfo = new LiveFolderInfo();
+ folders.put(id, folderInfo);
}
-
- return result != null;
- }
-
- /**
- * Update an item to the database in a specified container.
- */
- static void updateItemInDatabase(Context context, ItemInfo item) {
- final ContentValues values = new ContentValues();
- final ContentResolver cr = context.getContentResolver();
-
- item.onAddToDatabase(values);
-
- cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
- }
-
- /**
- * Removes the specified item from the database
- * @param context
- * @param item
- */
- static void deleteItemFromDatabase(Context context, ItemInfo item) {
- final ContentResolver cr = context.getContentResolver();
-
- cr.delete(LauncherSettings.Favorites.getContentUri(item.id, false), null, null);
- }
-
-
- /**
- * Remove the contents of the specified folder from the database
- */
- static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) {
- final ContentResolver cr = context.getContentResolver();
-
- cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
- cr.delete(LauncherSettings.Favorites.CONTENT_URI,
- LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
- }
-
- static void deleteGestureFromDatabase(Context context, ItemInfo item) {
- final ContentResolver cr = context.getContentResolver();
-
- cr.delete(LauncherSettings.Gestures.getContentUri(item.id, false), null, null);
- }
-
- static void updateGestureInDatabase(Context context, ItemInfo item) {
- final ContentValues values = new ContentValues();
- final ContentResolver cr = context.getContentResolver();
-
- item.onAddToDatabase(values);
-
- cr.update(LauncherSettings.Gestures.getContentUri(item.id, false), values, null, null);
+ return (LiveFolderInfo) folderInfo;
}
+ private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) {
+ final Cursor c = resolver.query(LauncherSettings.Favorites.CONTENT_URI,
+ new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.TITLE,
+ LauncherSettings.Favorites.INTENT, LauncherSettings.Favorites.ITEM_TYPE },
+ null, null, null);
- ApplicationInfo queryGesture(Context context, String id) {
- final ContentResolver contentResolver = context.getContentResolver();
- final PackageManager manager = context.getPackageManager();
- final Cursor c = contentResolver.query(
- LauncherSettings.Gestures.CONTENT_URI, null, LauncherSettings.Gestures._ID + "=?",
- new String[] { id }, null);
+ final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
+ final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
+ final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+ final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
- ApplicationInfo info = null;
+ // boolean changed = false;
try {
- final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures._ID);
- final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.INTENT);
- final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.TITLE);
- final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_TYPE);
- final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON);
- final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_PACKAGE);
- final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_RESOURCE);
- final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ITEM_TYPE);
-
- String intentDescription;
- Intent intent;
-
- if (c.moveToNext()) {
- 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 (java.net.URISyntaxException e) {
- return null;
- }
+ while (c.moveToNext()) {
+ try {
+ if (c.getInt(itemTypeIndex) !=
+ LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+ continue;
+ }
- if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = getApplicationInfo(manager, intent, context);
- } else {
- info = getApplicationInfoShortcut(c, context, iconTypeIndex,
- iconPackageIndex, iconResourceIndex, iconIndex);
- }
+ final String intentUri = c.getString(intentIndex);
+ if (intentUri != null) {
+ final Intent shortcut = Intent.parseUri(intentUri, 0);
+ if (Intent.ACTION_MAIN.equals(shortcut.getAction())) {
+ final ComponentName name = shortcut.getComponent();
+ if (name != null) {
+ final ActivityInfo activityInfo = manager.getActivityInfo(name, 0);
+ final String title = c.getString(titleIndex);
+ String label = getLabel(manager, activityInfo);
- if (info == null) {
- info = new ApplicationInfo();
- info.icon = manager.getDefaultActivityIcon();
- }
+ if (title == null || !title.equals(label)) {
+ final ContentValues values = new ContentValues();
+ values.put(LauncherSettings.Favorites.TITLE, label);
- info.isGesture = true;
- info.title = c.getString(titleIndex);
- info.intent = intent;
- info.id = c.getLong(idIndex);
+ resolver.update(
+ LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
+ values, "_id=?",
+ new String[] { String.valueOf(c.getLong(idIndex)) });
- break;
+ // changed = true;
+ }
+ }
+ }
+ }
+ } catch (URISyntaxException e) {
+ // Ignore
+ } catch (PackageManager.NameNotFoundException e) {
+ // Ignore
}
}
- } catch (Exception e) {
- w(LOG_TAG, "Could not load gesture with name " + id);
} finally {
c.close();
}
- return info;
+ // if (changed) resolver.notifyChange(Settings.Favorites.CONTENT_URI, null);
+ }
+
+ private static String getLabel(PackageManager manager, ActivityInfo activityInfo) {
+ String label = activityInfo.loadLabel(manager).toString();
+ if (label == null) {
+ label = manager.getApplicationLabel(activityInfo.applicationInfo).toString();
+ if (label == null) {
+ label = activityInfo.name;
+ }
+ }
+ return label;
}
+
+ private static final Collator sCollator = Collator.getInstance();
+ private static final Comparator<ApplicationInfo> sComparator
+ = new Comparator<ApplicationInfo>() {
+ public final int compare(ApplicationInfo a, ApplicationInfo b) {
+ return sCollator.compare(a.title.toString(), b.title.toString());
+ }
+ };
}
diff --git a/src/com/android/launcher2/LiveFolderAdapter.java b/src/com/android/launcher2/LiveFolderAdapter.java
index b0e9eff1f..05e7a6a82 100644
--- a/src/com/android/launcher2/LiveFolderAdapter.java
+++ b/src/com/android/launcher2/LiveFolderAdapter.java
@@ -154,7 +154,8 @@ class LiveFolderAdapter extends CursorAdapter {
cursor.getString(holder.iconPackageIndex));
final int id = resources.getIdentifier(resource,
null, null);
- icon = Utilities.createIconThumbnail(resources.getDrawable(id), mContext);
+ icon = Utilities.createIconThumbnail(resources.getDrawable(id), mContext,
+ false);
mIcons.put(resource, icon);
} catch (Exception e) {
// Ignore
diff --git a/src/com/android/launcher2/LiveFolderIcon.java b/src/com/android/launcher2/LiveFolderIcon.java
index 1876f2e0c..d281a64e8 100644
--- a/src/com/android/launcher2/LiveFolderIcon.java
+++ b/src/com/android/launcher2/LiveFolderIcon.java
@@ -41,8 +41,8 @@ public class LiveFolderIcon extends FolderIcon {
final Resources resources = launcher.getResources();
Drawable d = folderInfo.icon;
if (d == null) {
- d = Utilities.createIconThumbnail(
- resources.getDrawable(R.drawable.ic_launcher_folder), launcher);
+ d = Utilities.createIconThumbnail(resources.getDrawable(R.drawable.ic_launcher_folder),
+ launcher, false);
folderInfo.filtered = true;
}
icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null);
diff --git a/src/com/android/launcher2/UserFolderInfo.java b/src/com/android/launcher2/UserFolderInfo.java
index 40ec9e183..75b19eec6 100644
--- a/src/com/android/launcher2/UserFolderInfo.java
+++ b/src/com/android/launcher2/UserFolderInfo.java
@@ -43,7 +43,7 @@ class UserFolderInfo extends FolderInfo {
}
/**
- * Remove an app or shortcut
+ * Remove an app or shortcut. Does not change the DB.
*
* @param item
*/
diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java
index 9e715d1b7..53e42e3cf 100644
--- a/src/com/android/launcher2/Utilities.java
+++ b/src/com/android/launcher2/Utilities.java
@@ -78,82 +78,101 @@ final class Utilities {
* The size of the thumbnail is defined by the dimension
* android.R.dimen.launcher_application_icon_size.
*
- * This method is not thread-safe and should be invoked on the UI thread only.
- *
* @param icon The icon to get a thumbnail of.
* @param context The application's context.
+ * @param forceBitmap If this is true, the drawable will always be redrawn
+ * into a new bitmap if it isn't already a BitmapDrawable or a
+ * FastBitmapDrawable.
*
* @return A thumbnail for the specified icon or the icon itself if the
* thumbnail could not be created.
*/
- static Drawable createIconThumbnail(Drawable icon, Context context) {
- if (sIconWidth == -1) {
- final Resources resources = context.getResources();
- sIconWidth = sIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
- }
-
- int width = sIconWidth;
- int height = sIconHeight;
-
- float scale = 1.0f;
- if (icon instanceof PaintDrawable) {
- PaintDrawable painter = (PaintDrawable) icon;
- painter.setIntrinsicWidth(width);
- painter.setIntrinsicHeight(height);
- } else if (icon instanceof BitmapDrawable) {
- // Ensure the bitmap has a density.
- BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
- Bitmap bitmap = bitmapDrawable.getBitmap();
- if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
- bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
+ static Drawable createIconThumbnail(Drawable icon, Context context, boolean forceBitmap) {
+ synchronized (sCanvas) { // we share the statics :-(
+ if (sIconWidth == -1) {
+ final Resources resources = context.getResources();
+ sIconWidth = (int)resources.getDimension(android.R.dimen.app_icon_size);
+ sIconHeight = sIconWidth;
}
- }
- int iconWidth = icon.getIntrinsicWidth();
- int iconHeight = icon.getIntrinsicHeight();
- if (width > 0 && height > 0) {
- if (width < iconWidth || height < iconHeight || scale != 1.0f) {
- final float ratio = (float) iconWidth / iconHeight;
-
- if (iconWidth > iconHeight) {
- height = (int) (width / ratio);
- } else if (iconHeight > iconWidth) {
- width = (int) (height * ratio);
+ int width = sIconWidth;
+ int height = sIconHeight;
+
+ float scale = 1.0f;
+ if (icon instanceof PaintDrawable) {
+ PaintDrawable painter = (PaintDrawable) icon;
+ painter.setIntrinsicWidth(width);
+ painter.setIntrinsicHeight(height);
+ } else if (icon instanceof BitmapDrawable) {
+ // Ensure the bitmap has a density.
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+ Bitmap bitmap = bitmapDrawable.getBitmap();
+ if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
+ bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
}
-
- final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
- Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
- final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
- final Canvas canvas = sCanvas;
- canvas.setBitmap(thumb);
- // Copy the old bounds to restore them later
- // If we were to do oldBounds = icon.getBounds(),
- // the call to setBounds() that follows would
- // change the same instance and we would lose the
- // old bounds
- sOldBounds.set(icon.getBounds());
- final int x = (sIconWidth - width) / 2;
- final int y = (sIconHeight - height) / 2;
- icon.setBounds(x, y, x + width, y + height);
- icon.draw(canvas);
- icon.setBounds(sOldBounds);
- icon = new FastBitmapDrawable(thumb);
- } else if (iconWidth < width && iconHeight < height) {
+ }
+ int iconWidth = icon.getIntrinsicWidth();
+ int iconHeight = icon.getIntrinsicHeight();
+
+ if (iconWidth > 0 && iconWidth > 0) {
+ if (width < iconWidth || height < iconHeight || scale != 1.0f) {
+ final float ratio = (float) iconWidth / iconHeight;
+
+ if (iconWidth > iconHeight) {
+ height = (int) (width / ratio);
+ } else if (iconHeight > iconWidth) {
+ width = (int) (height * ratio);
+ }
+
+ final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
+ Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+ final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
+ final Canvas canvas = sCanvas;
+ canvas.setBitmap(thumb);
+ // Copy the old bounds to restore them later
+ // If we were to do oldBounds = icon.getBounds(),
+ // the call to setBounds() that follows would
+ // change the same instance and we would lose the
+ // old bounds
+ sOldBounds.set(icon.getBounds());
+ final int x = (sIconWidth - width) / 2;
+ final int y = (sIconHeight - height) / 2;
+ icon.setBounds(x, y, x + width, y + height);
+ icon.draw(canvas);
+ icon.setBounds(sOldBounds);
+ icon = new FastBitmapDrawable(thumb);
+ } else if (iconWidth < width && iconHeight < height) {
+ final Bitmap.Config c = Bitmap.Config.ARGB_8888;
+ final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
+ final Canvas canvas = sCanvas;
+ canvas.setBitmap(thumb);
+ sOldBounds.set(icon.getBounds());
+ final int x = (width - iconWidth) / 2;
+ final int y = (height - iconHeight) / 2;
+ icon.setBounds(x, y, x + iconWidth, y + iconHeight);
+ icon.draw(canvas);
+ icon.setBounds(sOldBounds);
+ icon = new FastBitmapDrawable(thumb);
+ }
+ }
+
+ if (forceBitmap) {
+ // no intrinsic size --> use default size
+ int w = sIconWidth;
+ int h = sIconHeight;
final Bitmap.Config c = Bitmap.Config.ARGB_8888;
- final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
+ final Bitmap thumb = Bitmap.createBitmap(roundToPow2(w), roundToPow2(h), c);
final Canvas canvas = sCanvas;
canvas.setBitmap(thumb);
sOldBounds.set(icon.getBounds());
- final int x = (width - iconWidth) / 2;
- final int y = (height - iconHeight) / 2;
- icon.setBounds(x, y, x + iconWidth, y + iconHeight);
+ icon.setBounds(0, 0, w, h);
icon.draw(canvas);
icon.setBounds(sOldBounds);
icon = new FastBitmapDrawable(thumb);
}
- }
- return icon;
+ return icon;
+ }
}
/**
@@ -161,8 +180,6 @@ final class Utilities {
* The size of the thumbnail is defined by the dimension
* android.R.dimen.launcher_application_icon_size.
*
- * This method is not thread-safe and should be invoked on the UI thread only.
- *
* @param bitmap The bitmap to get a thumbnail of.
* @param context The application's context.
*
@@ -170,42 +187,44 @@ final class Utilities {
* thumbnail could not be created.
*/
static Bitmap createBitmapThumbnail(Bitmap bitmap, Context context) {
- if (sIconWidth == -1) {
- final Resources resources = context.getResources();
- sIconWidth = sIconHeight = (int) resources.getDimension(
- android.R.dimen.app_icon_size);
- }
+ synchronized (sCanvas) { // we share the statics :-(
+ if (sIconWidth == -1) {
+ final Resources resources = context.getResources();
+ sIconWidth = sIconHeight = (int) resources.getDimension(
+ android.R.dimen.app_icon_size);
+ }
- int width = sIconWidth;
- int height = sIconHeight;
+ int width = sIconWidth;
+ int height = sIconHeight;
- final int bitmapWidth = bitmap.getWidth();
- final int bitmapHeight = bitmap.getHeight();
+ final int bitmapWidth = bitmap.getWidth();
+ final int bitmapHeight = bitmap.getHeight();
- if (width > 0 && height > 0 && (width < bitmapWidth || height < bitmapHeight)) {
- final float ratio = (float) bitmapWidth / bitmapHeight;
+ if (width > 0 && height > 0 && (width < bitmapWidth || height < bitmapHeight)) {
+ final float ratio = (float) bitmapWidth / bitmapHeight;
- if (bitmapWidth > bitmapHeight) {
- height = (int) (width / ratio);
- } else if (bitmapHeight > bitmapWidth) {
- width = (int) (height * ratio);
+ if (bitmapWidth > bitmapHeight) {
+ height = (int) (width / ratio);
+ } else if (bitmapHeight > bitmapWidth) {
+ width = (int) (height * ratio);
+ }
+
+ final Bitmap.Config c = (width == sIconWidth && height == sIconHeight) ?
+ bitmap.getConfig() : Bitmap.Config.ARGB_8888;
+ final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
+ final Canvas canvas = sCanvas;
+ final Paint paint = sPaint;
+ canvas.setBitmap(thumb);
+ paint.setDither(false);
+ paint.setFilterBitmap(true);
+ sBounds.set((sIconWidth - width) / 2, (sIconHeight - height) / 2, width, height);
+ sOldBounds.set(0, 0, bitmapWidth, bitmapHeight);
+ canvas.drawBitmap(bitmap, sOldBounds, sBounds, paint);
+ return thumb;
}
- final Bitmap.Config c = (width == sIconWidth && height == sIconHeight) ?
- bitmap.getConfig() : Bitmap.Config.ARGB_8888;
- final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
- final Canvas canvas = sCanvas;
- final Paint paint = sPaint;
- canvas.setBitmap(thumb);
- paint.setDither(false);
- paint.setFilterBitmap(true);
- sBounds.set((sIconWidth - width) / 2, (sIconHeight - height) / 2, width, height);
- sOldBounds.set(0, 0, bitmapWidth, bitmapHeight);
- canvas.drawBitmap(bitmap, sOldBounds, sBounds, paint);
- return thumb;
+ return bitmap;
}
-
- return bitmap;
}
static class BubbleText {
@@ -261,7 +280,6 @@ final class Utilities {
mFirstLineY = (int)(leading + ascent + 0.5f);
mLineHeight = (int)(leading + ascent + descent + 0.5f);
- roundToPow2(64);
mBitmapWidth = roundToPow2((int)(mBubbleRect.width() + 0.5f));
mBitmapHeight = roundToPow2((int)((MAX_LINES * mLineHeight) + leading + 0.5f));
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 759deb642..8b0048368 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.ComponentName;
import android.content.res.TypedArray;
+import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.RectF;
import android.graphics.Rect;
@@ -100,7 +101,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
private int[] mTempEstimate = new int[2];
private boolean mAllowLongPress;
- private boolean mLocked;
private int mTouchSlop;
private int mMaximumVelocity;
@@ -642,10 +642,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- Log.d(Launcher.LOG_TAG, "Workspace onIntercept " + ev + " mLocked=" + mLocked
- + " mLauncher.isDrawerDown()=" + mLauncher.isDrawerDown());
- if (mLocked || !mLauncher.isDrawerDown()) {
- Log.d(Launcher.LOG_TAG, "returning false");
+ if (mLauncher.isWorkspaceLocked() || !mLauncher.isDrawerDown()) {
return false; // We don't want the events. Let them fall through to the all apps view.
}
@@ -755,9 +752,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
@Override
public boolean onTouchEvent(MotionEvent ev) {
- Log.d(Launcher.LOG_TAG, "Workspace onTouchEvent " + ev);
-
- if (mLocked || !mLauncher.isDrawerDown()) {
+ if (mLauncher.isWorkspaceLocked() || !mLauncher.isDrawerDown()) {
return false; // We don't want the events. Let them fall through to the all apps view.
}
@@ -990,8 +985,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
cellLayout.onDropChild(view, mTargetCell);
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
- final LauncherModel model = Launcher.getModel();
- model.addDesktopItem(info);
LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
}
@@ -1088,7 +1081,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
mDragController.removeDropTarget((DropTarget)mDragInfo.cell);
}
final Object tag = mDragInfo.cell.getTag();
- Launcher.getModel().removeDesktopItem((ItemInfo) tag);
}
} else {
if (mDragInfo != null) {
@@ -1187,24 +1179,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
/**
- * Unlocks the SlidingDrawer so that touch events are processed.
- *
- * @see #lock()
- */
- public void unlock() {
- mLocked = false;
- }
-
- /**
- * Locks the SlidingDrawer so that touch events are ignores.
- *
- * @see #unlock()
- */
- public void lock() {
- mLocked = true;
- }
-
- /**
* @return True is long presses are still allowed for the current touch
*/
public boolean allowLongPress() {
@@ -1221,7 +1195,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
void removeShortcutsForPackage(String packageName) {
final ArrayList<View> childrenToRemove = new ArrayList<View>();
- final LauncherModel model = Launcher.getModel();
final int count = getChildCount();
for (int i = 0; i < count; i++) {
@@ -1244,7 +1217,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
if (Intent.ACTION_MAIN.equals(intent.getAction()) &&
name != null && packageName.equals(name.getPackageName())) {
- model.removeDesktopItem(info);
LauncherModel.deleteItemFromDatabase(mLauncher, info);
childrenToRemove.add(view);
}
@@ -1293,6 +1265,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
void updateShortcutsForPackage(String packageName) {
+ final PackageManager pm = mLauncher.getPackageManager();
+
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final CellLayout layout = (CellLayout) getChildAt(i);
@@ -1311,11 +1285,10 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
Intent.ACTION_MAIN.equals(intent.getAction()) && name != null &&
packageName.equals(name.getPackageName())) {
- final Drawable icon = Launcher.getModel().getApplicationInfoIcon(
- mLauncher.getPackageManager(), info);
+ final Drawable icon = AppInfoCache.getIconDrawable(pm, info);
if (icon != null && icon != info.icon) {
info.icon.setCallback(null);
- info.icon = Utilities.createIconThumbnail(icon, mContext);
+ info.icon = Utilities.createIconThumbnail(icon, mContext, false);
info.filtered = true;
((TextView) view).setCompoundDrawablesWithIntrinsicBounds(null,
info.icon, null, null);