From 0589f0f66ce498512c6ee47482c649d88294c9d0 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Mon, 8 Feb 2010 13:44:00 -0800 Subject: [PATCH] Split ApplicationInfo into ApplicationInfo which is used for AllAppsView and ShortcutInfo which is used for the workspace. Consolidate the three icon resampling functions into one. Ensure that the icons stored in LauncherProvider are the right size, so we don't have to resample them each time we load them. --- res/layout-land/workspace_screen.xml | 4 +- res/layout-port/workspace_screen.xml | 2 +- src/com/android/launcher2/AllAppsList.java | 20 +- src/com/android/launcher2/AppInfoCache.java | 177 ------------------ .../android/launcher2/ApplicationInfo.java | 91 +++------ src/com/android/launcher2/DeleteZone.java | 4 +- .../android/launcher2/FastBitmapDrawable.java | 4 + src/com/android/launcher2/Folder.java | 10 +- src/com/android/launcher2/FolderIcon.java | 10 +- src/com/android/launcher2/IconCache.java | 138 ++++++++++++++ .../launcher2/InstallShortcutReceiver.java | 3 +- src/com/android/launcher2/ItemInfo.java | 31 +-- src/com/android/launcher2/Launcher.java | 129 +++---------- .../launcher2/LauncherApplication.java | 18 +- src/com/android/launcher2/LauncherModel.java | 133 +++++++++---- .../android/launcher2/LauncherProvider.java | 67 ++++++- .../android/launcher2/LiveFolderAdapter.java | 10 +- src/com/android/launcher2/LiveFolderIcon.java | 11 +- src/com/android/launcher2/LiveFolderInfo.java | 8 +- src/com/android/launcher2/ShortcutInfo.java | 159 ++++++++++++++++ ...ionsAdapter.java => ShortcutsAdapter.java} | 19 +- src/com/android/launcher2/UserFolder.java | 17 +- src/com/android/launcher2/UserFolderInfo.java | 6 +- src/com/android/launcher2/Utilities.java | 131 +------------ src/com/android/launcher2/Workspace.java | 41 ++-- 25 files changed, 633 insertions(+), 610 deletions(-) delete mode 100644 src/com/android/launcher2/AppInfoCache.java create mode 100644 src/com/android/launcher2/IconCache.java create mode 100644 src/com/android/launcher2/ShortcutInfo.java rename src/com/android/launcher2/{ApplicationsAdapter.java => ShortcutsAdapter.java} (73%) diff --git a/res/layout-land/workspace_screen.xml b/res/layout-land/workspace_screen.xml index 5349aa4b35..2483f51593 100644 --- a/res/layout-land/workspace_screen.xml +++ b/res/layout-land/workspace_screen.xml @@ -23,8 +23,8 @@ launcher:cellWidth="@dimen/workspace_cell_width" launcher:cellHeight="@dimen/workspace_cell_height" - launcher:longAxisStartPadding="@dimen/button_bar_height" - launcher:longAxisEndPadding="@dimen/button_bar_height" + launcher:longAxisStartPadding="65dip" + launcher:longAxisEndPadding="65dip" launcher:shortAxisStartPadding="0dip" launcher:shortAxisEndPadding="0dip" launcher:shortAxisCells="4" diff --git a/res/layout-port/workspace_screen.xml b/res/layout-port/workspace_screen.xml index 522d345cf4..b43375b148 100644 --- a/res/layout-port/workspace_screen.xml +++ b/res/layout-port/workspace_screen.xml @@ -23,7 +23,7 @@ launcher:cellWidth="@dimen/workspace_cell_width" launcher:cellHeight="@dimen/workspace_cell_height" - launcher:longAxisStartPadding="0dip" + launcher:longAxisStartPadding="8dip" launcher:longAxisEndPadding="@dimen/button_bar_height" launcher:shortAxisStartPadding="0dip" launcher:shortAxisEndPadding="0dip" diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java index 00e9ea8813..9d4c5b02a8 100644 --- a/src/com/android/launcher2/AllAppsList.java +++ b/src/com/android/launcher2/AllAppsList.java @@ -44,10 +44,13 @@ class AllAppsList { /** The list of apps that have been modified since the last notify() call. */ public ArrayList modified = new ArrayList(); + private IconCache mIconCache; + /** * Boring constructor. */ - public AllAppsList() { + public AllAppsList(IconCache iconCache) { + mIconCache = iconCache; } /** @@ -82,9 +85,8 @@ class AllAppsList { final List 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); + ApplicationInfo item = new ApplicationInfo(info, mIconCache); data.add(item); added.add(item); } @@ -105,9 +107,9 @@ class AllAppsList { } } // This is more aggressive than it needs to be. - AppInfoCache.flush(); + mIconCache.flush(); } - + /** * Add and remove icons for this package which has been updated. */ @@ -122,7 +124,7 @@ class AllAppsList { if (packageName.equals(component.getPackageName())) { if (!findActivity(matches, component)) { removed.add(applicationInfo); - AppInfoCache.remove(component); + mIconCache.remove(component); data.remove(i); } } @@ -130,7 +132,6 @@ class AllAppsList { // 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); @@ -138,11 +139,12 @@ class AllAppsList { info.activityInfo.applicationInfo.packageName, info.activityInfo.name); if (applicationInfo == null) { - applicationInfo = AppInfoCache.cache(info, context, bubble); + applicationInfo = new ApplicationInfo(info, mIconCache); data.add(applicationInfo); added.add(applicationInfo); } else { - AppInfoCache.update(info, applicationInfo, context, bubble); + mIconCache.remove(applicationInfo.componentName); + mIconCache.getTitleAndIcon(applicationInfo, info); modified.add(applicationInfo); } } diff --git a/src/com/android/launcher2/AppInfoCache.java b/src/com/android/launcher2/AppInfoCache.java deleted file mode 100644 index a2d98307ff..0000000000 --- a/src/com/android/launcher2/AppInfoCache.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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 sCache = - new HashMap(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, - Utilities.BubbleText bubble) { - synchronized (sCache) { - updateTitleAndIcon(info, applicationInfo, context, bubble); - - 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) { - if (cached.icon == null) { - cached.icon = resolveInfo.activityInfo.loadIcon(packageManager); - } - 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()) { - if (appInfo.icon != null) { - 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; - } - - application.iconBitmap = Utilities.createAllAppsBitmap( - info.activityInfo.loadIcon(packageManager), context); - - application.titleBitmap = bubble.createTextBitmap(application.title.toString()); - } -} - diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java index 0fe84e7318..f50b88930e 100644 --- a/src/com/android/launcher2/ApplicationInfo.java +++ b/src/com/android/launcher2/ApplicationInfo.java @@ -18,7 +18,9 @@ package com.android.launcher2; import android.content.ComponentName; import android.content.ContentValues; +import android.content.Context; import android.content.Intent; +import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.util.Log; @@ -26,8 +28,7 @@ import android.util.Log; import java.util.ArrayList; /** - * Represents a launchable application. An application is made of a name (or title), - * an intent and an icon. + * Represents an app in AllAppsView. */ class ApplicationInfo extends ItemInfo { @@ -46,49 +47,38 @@ class ApplicationInfo extends ItemInfo { */ Intent intent; - /** - * The application icon. - */ - Drawable icon; - /** * A bitmap version of the application icon. */ Bitmap iconBitmap; - /** - * When set to true, indicates that the icon has been resized. - */ - boolean filtered; + ComponentName componentName; - /** - * Indicates whether the icon comes from an application's resource (if false) - * or from a custom Bitmap (if true.) - */ - boolean customIcon; - - /** - * If isShortcut=true and customIcon=false, this contains a reference to the - * shortcut icon as an application's resource. - */ - Intent.ShortcutIconResource iconResource; ApplicationInfo() { itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT; } + + /** + * Must not hold the Context. + */ + public ApplicationInfo(ResolveInfo info, IconCache iconCache) { + this.componentName = new ComponentName( + info.activityInfo.applicationInfo.packageName, + info.activityInfo.name); + + this.container = ItemInfo.NO_ID; + this.setActivity(componentName, + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + iconCache.getTitleAndIcon(this, info); + } public ApplicationInfo(ApplicationInfo info) { super(info); + componentName = info.componentName; title = info.title.toString(); intent = new Intent(info.intent); - if (info.iconResource != null) { - iconResource = new Intent.ShortcutIconResource(); - iconResource.packageName = info.iconResource.packageName; - iconResource.resourceName = info.iconResource.resourceName; - } - icon = info.icon; - filtered = info.filtered; - customIcon = info.customIcon; } /** @@ -106,52 +96,21 @@ class ApplicationInfo extends ItemInfo { itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION; } - @Override - void onAddToDatabase(ContentValues values) { - super.onAddToDatabase(values); - - String titleStr = title != null ? title.toString() : null; - values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr); - - String uri = intent != null ? intent.toUri(0) : null; - values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri); - - if (customIcon) { - values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE, - LauncherSettings.BaseLauncherColumns.ICON_TYPE_BITMAP); - Bitmap bitmap = ((FastBitmapDrawable) icon).getBitmap(); - writeBitmap(values, bitmap); - } else { - values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE, - LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE); - if (iconResource != null) { - values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE, - iconResource.packageName); - values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE, - iconResource.resourceName); - } - } - } - @Override public String toString() { return title.toString(); } - @Override - void unbind() { - super.unbind(); - icon.setCallback(null); - } - - public static void dumpApplicationInfoList(String tag, String label, ArrayList list) { Log.d(tag, label + " size=" + list.size()); for (ApplicationInfo info: list) { Log.d(tag, " title=\"" + info.title + "\" titleBitmap=" + info.titleBitmap - + " icon=" + info.icon + " iconBitmap=" + info.iconBitmap - + " filtered=" + info.filtered + " customIcon=" + info.customIcon); + + " iconBitmap=" + info.iconBitmap); } } + + public ShortcutInfo makeShortcut() { + return new ShortcutInfo(this); + } } diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java index ec4bc534c9..fabeb4a3bd 100644 --- a/src/com/android/launcher2/DeleteZone.java +++ b/src/com/android/launcher2/DeleteZone.java @@ -101,9 +101,9 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. if (source instanceof UserFolder) { final UserFolder userFolder = (UserFolder) source; final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo(); - // item must be an ApplicationInfo otherwise it couldn't have been in the folder + // Item must be a ShortcutInfo otherwise it couldn't have been in the folder // in the first place. - userFolderInfo.remove((ApplicationInfo)item); + userFolderInfo.remove((ShortcutInfo)item); } } if (item instanceof UserFolderInfo) { diff --git a/src/com/android/launcher2/FastBitmapDrawable.java b/src/com/android/launcher2/FastBitmapDrawable.java index db2c01c4f8..850535e670 100644 --- a/src/com/android/launcher2/FastBitmapDrawable.java +++ b/src/com/android/launcher2/FastBitmapDrawable.java @@ -67,6 +67,10 @@ class FastBitmapDrawable extends Drawable { return mBitmap.getHeight(); } + public void setBitmap(Bitmap b) { + mBitmap = b; + } + public Bitmap getBitmap() { return mBitmap; } diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java index 4f66ad0520..7c35f7997a 100644 --- a/src/com/android/launcher2/Folder.java +++ b/src/com/android/launcher2/Folder.java @@ -46,7 +46,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL /** * Which item is being dragged */ - protected ApplicationInfo mDragItem; + protected ShortcutInfo mDragItem; private boolean mCloneInfo; /** @@ -74,7 +74,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL } public void onItemClick(AdapterView parent, View v, int position, long id) { - ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position); + ShortcutInfo app = (ShortcutInfo) parent.getItemAtPosition(position); mLauncher.startActivitySafely(app.intent); } @@ -93,9 +93,9 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL return false; } - ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position); + ShortcutInfo app = (ShortcutInfo) parent.getItemAtPosition(position); if (mCloneInfo) { - app = new ApplicationInfo(app); + app = new ShortcutInfo(app); } mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY); @@ -118,7 +118,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL /** * Sets the adapter used to populate the content area. The adapter must only - * contains ApplicationInfo items. + * contains ShortcutInfo items. * * @param adapter The list of applications to display in the folder. */ diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java index 85fc3a7547..826336c9f3 100644 --- a/src/com/android/launcher2/FolderIcon.java +++ b/src/com/android/launcher2/FolderIcon.java @@ -48,7 +48,6 @@ 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); icon.mCloseIcon = d; icon.mOpenIcon = resources.getDrawable(R.drawable.ic_launcher_folder_open); icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null); @@ -77,8 +76,13 @@ public class FolderIcon extends BubbleTextView implements DropTarget { public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, DragView dragView, Object dragInfo) { - final ApplicationInfo item = (ApplicationInfo) dragInfo; - // TODO: update open folder that is looking at this data + ShortcutInfo item; + if (dragInfo instanceof ApplicationInfo) { + // Came from all apps -- make a copy + item = ((ApplicationInfo)dragInfo).makeShortcut(); + } else { + item = (ShortcutInfo)dragInfo; + } mInfo.add(item); LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0); } diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java new file mode 100644 index 0000000000..847cab72e5 --- /dev/null +++ b/src/com/android/launcher2/IconCache.java @@ -0,0 +1,138 @@ +/* + * 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 IconCache { + private static final String TAG = "Launcher.IconCache"; + + private static final int INITIAL_ICON_CACHE_CAPACITY = 50; + + private static class CacheEntry { + public Bitmap icon; + public String title; + public Bitmap titleBitmap; + } + + private LauncherApplication mContext; + private PackageManager mPackageManager; + private Utilities.BubbleText mBubble; + private final HashMap mCache = + new HashMap(INITIAL_ICON_CACHE_CAPACITY); + + public IconCache(LauncherApplication context) { + mContext = context; + mPackageManager = context.getPackageManager(); + mBubble = new Utilities.BubbleText(context); + } + + /** + * Remove any records for the supplied ComponentName. + */ + public void remove(ComponentName componentName) { + synchronized (mCache) { + mCache.remove(componentName); + } + } + + /** + * Empty out the cache. + */ + public void flush() { + synchronized (mCache) { + mCache.clear(); + } + } + + /** + * Fill in "application" with the icon and label for "info." + */ + public void getTitleAndIcon(ApplicationInfo application, ResolveInfo info) { + synchronized (mCache) { + CacheEntry entry = cacheLocked(application.componentName, info); + + application.title = entry.title; + application.titleBitmap = entry.titleBitmap; + application.iconBitmap = entry.icon; + } + } + + public Bitmap getIcon(Intent intent) { + final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0); + ComponentName component = intent.getComponent(); + + if (resolveInfo == null || component == null) { + return null; + } + + CacheEntry entry = cacheLocked(component, resolveInfo); + return entry.icon; + } + + public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo) { + if (resolveInfo == null || component == null) { + return null; + } + + CacheEntry entry = cacheLocked(component, resolveInfo); + return entry.icon; + } + + private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info) { + CacheEntry entry = mCache.get(componentName); + if (entry == null) { + entry = new CacheEntry(); + + entry.title = info.loadLabel(mPackageManager).toString(); + if (entry.title == null) { + entry.title = info.activityInfo.name; + } + entry.titleBitmap = mBubble.createTextBitmap(entry.title.toString()); + entry.icon = Utilities.createIconBitmap( + info.activityInfo.loadIcon(mPackageManager), mContext); + + mCache.put(componentName, entry); + } + return entry; + } +} + diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java index 45ff24e17c..9a2f73fcd4 100644 --- a/src/com/android/launcher2/InstallShortcutReceiver.java +++ b/src/com/android/launcher2/InstallShortcutReceiver.java @@ -63,7 +63,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver { // different places) boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true); if (duplicate || !LauncherModel.shortcutExists(context, name, intent)) { - Launcher.addShortcut(context, data, cell, true); + ((LauncherApplication)context.getApplicationContext()).getModel() + .addShortcut(context, data, cell, true); Toast.makeText(context, context.getString(R.string.shortcut_installed, name), Toast.LENGTH_SHORT).show(); } else { diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java index f04880ddd5..ca2ea86c8a 100644 --- a/src/com/android/launcher2/ItemInfo.java +++ b/src/com/android/launcher2/ItemInfo.java @@ -112,21 +112,26 @@ class ItemInfo { } } + static byte[] flattenBitmap(Bitmap bitmap) { + // Try go guesstimate how much space the icon will take when serialized + // to avoid unnecessary allocations/copies during the write. + int size = bitmap.getWidth() * bitmap.getHeight() * 4; + ByteArrayOutputStream out = new ByteArrayOutputStream(size); + try { + bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); + out.flush(); + out.close(); + return out.toByteArray(); + } catch (IOException e) { + Log.w("Favorite", "Could not write icon"); + return null; + } + } + static void writeBitmap(ContentValues values, Bitmap bitmap) { if (bitmap != null) { - // Try go guesstimate how much space the icon will take when serialized - // to avoid unnecessary allocations/copies during the write. - int size = bitmap.getWidth() * bitmap.getHeight() * 4; - ByteArrayOutputStream out = new ByteArrayOutputStream(size); - try { - bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); - out.flush(); - out.close(); - - values.put(LauncherSettings.Favorites.ICON, out.toByteArray()); - } catch (IOException e) { - Log.w("Favorite", "Could not write icon"); - } + byte[] data = flattenBitmap(bitmap); + values.put(LauncherSettings.Favorites.ICON, data); } } diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 646203c8c0..089e5512bb 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -191,6 +191,7 @@ public final class Launcher extends Activity private Bundle mSavedInstanceState; private LauncherModel mModel; + private IconCache mIconCache; private ArrayList mDesktopItems = new ArrayList(); private static HashMap mFolders = new HashMap(); @@ -202,7 +203,9 @@ public final class Launcher extends Activity protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mModel = ((LauncherApplication)getApplication()).setLauncher(this); + LauncherApplication app = ((LauncherApplication)getApplication()); + mModel = app.setLauncher(this); + mIconCache = app.getIconCache(); mDragController = new DragController(this); mInflater = getLayoutInflater(); @@ -271,7 +274,7 @@ public final class Launcher extends Activity localeConfiguration.mnc = mnc; writeConfiguration(this, localeConfiguration); - AppInfoCache.flush(); + mIconCache.flush(); } } @@ -615,7 +618,7 @@ public final class Launcher extends Activity * * @return A View inflated from R.layout.application. */ - View createShortcut(ApplicationInfo info) { + View createShortcut(ShortcutInfo info) { return createShortcut(R.layout.application, (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), info); } @@ -629,18 +632,12 @@ public final class Launcher extends Activity * * @return A View inflated from layoutResId. */ - View createShortcut(int layoutResId, ViewGroup parent, ApplicationInfo info) { + View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) { TextView favorite = (TextView) mInflater.inflate(layoutResId, parent, false); - if (info.icon == null) { - info.icon = AppInfoCache.getIconDrawable(getPackageManager(), info); - } - if (!info.filtered) { - info.icon = Utilities.createIconThumbnail(info.icon, this); - info.filtered = true; - } - - favorite.setCompoundDrawablesWithIntrinsicBounds(null, info.icon, null, null); + favorite.setCompoundDrawablesWithIntrinsicBounds(null, + new FastBitmapDrawable(info.getIcon(mIconCache)), + null, null); favorite.setText(info.title); favorite.setTag(info); favorite.setOnClickListener(this); @@ -658,39 +655,17 @@ public final class Launcher extends Activity cellInfo.screen = mWorkspace.getCurrentScreen(); if (!findSingleSlot(cellInfo)) return; - final ApplicationInfo info = infoFromApplicationIntent(context, data); + final ShortcutInfo info = mModel.getShortcutInfo(context.getPackageManager(), + data, context); + if (info != null) { - mWorkspace.addApplicationShortcut(info, cellInfo, isWorkspaceLocked()); - } - } - - private static ApplicationInfo infoFromApplicationIntent(Context context, Intent data) { - ComponentName component = data.getComponent(); - PackageManager packageManager = context.getPackageManager(); - ActivityInfo activityInfo = null; - try { - activityInfo = packageManager.getActivityInfo(component, 0 /* no flags */); - } catch (NameNotFoundException e) { - Log.e(TAG, "Couldn't find ActivityInfo for selected application", e); - } - - if (activityInfo != null) { - ApplicationInfo itemInfo = new ApplicationInfo(); - - itemInfo.title = activityInfo.loadLabel(packageManager); - if (itemInfo.title == null) { - itemInfo.title = activityInfo.name; - } - - itemInfo.setActivity(component, Intent.FLAG_ACTIVITY_NEW_TASK | + info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - itemInfo.icon = activityInfo.loadIcon(packageManager); - itemInfo.container = ItemInfo.NO_ID; - - return itemInfo; + info.container = ItemInfo.NO_ID; + mWorkspace.addApplicationShortcut(info, cellInfo, isWorkspaceLocked()); + } else { + Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data); } - - return null; } /** @@ -703,7 +678,7 @@ public final class Launcher extends Activity cellInfo.screen = mWorkspace.getCurrentScreen(); if (!findSingleSlot(cellInfo)) return; - final ApplicationInfo info = addShortcut(this, data, cellInfo, false); + final ShortcutInfo info = mModel.addShortcut(this, data, cellInfo, false); if (!mRestoring) { final View view = createShortcut(info); @@ -770,61 +745,6 @@ public final class Launcher extends Activity return mAppWidgetHost; } - static ApplicationInfo addShortcut(Context context, Intent data, - CellLayout.CellInfo cellInfo, boolean notify) { - - final ApplicationInfo info = infoFromShortcutIntent(context, data); - LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, - cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify); - - return info; - } - - private static ApplicationInfo infoFromShortcutIntent(Context context, Intent data) { - Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); - String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); - Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON); - - Drawable icon = null; - boolean filtered = false; - boolean customIcon = false; - ShortcutIconResource iconResource = null; - - if (bitmap != null && bitmap instanceof Bitmap) { - icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail((Bitmap) bitmap, context)); - filtered = true; - customIcon = true; - } else { - Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE); - if (extra != null && extra instanceof ShortcutIconResource) { - try { - iconResource = (ShortcutIconResource) extra; - final PackageManager packageManager = context.getPackageManager(); - Resources resources = packageManager.getResourcesForApplication( - iconResource.packageName); - final int id = resources.getIdentifier(iconResource.resourceName, null, null); - icon = resources.getDrawable(id); - } catch (Exception e) { - Log.w(TAG, "Could not load shortcut icon: " + extra); - } - } - } - - if (icon == null) { - icon = context.getPackageManager().getDefaultActivityIcon(); - } - - final ApplicationInfo info = new ApplicationInfo(); - info.icon = icon; - info.filtered = filtered; - info.title = name; - info.intent = intent; - info.customIcon = customIcon; - info.iconResource = iconResource; - - return info; - } - void closeSystemDialogs() { getWindow().closeAllPanels(); @@ -936,7 +856,6 @@ public final class Launcher extends Activity mModel.stopLoader(); unbindDesktopItems(); - AppInfoCache.unbindDrawables(); getContentResolver().unregisterContentObserver(mWidgetObserver); @@ -1163,7 +1082,6 @@ public final class Launcher extends Activity String name = data.getStringExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME); Drawable icon = null; - boolean filtered = false; Intent.ShortcutIconResource iconResource = null; Parcelable extra = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON); @@ -1185,8 +1103,7 @@ public final class Launcher extends Activity } final LiveFolderInfo info = new LiveFolderInfo(); - info.icon = icon; - info.filtered = filtered; + info.icon = Utilities.createIconBitmap(icon, context); info.title = name; info.iconResource = iconResource; info.uri = data.getData(); @@ -1338,9 +1255,9 @@ public final class Launcher extends Activity */ public void onClick(View v) { Object tag = v.getTag(); - if (tag instanceof ApplicationInfo) { + if (tag instanceof ShortcutInfo) { // Open shortcut - final Intent intent = ((ApplicationInfo) tag).intent; + final Intent intent = ((ShortcutInfo)tag).intent; int[] pos = new int[2]; v.getLocationOnScreen(pos); intent.setSourceBounds( @@ -2011,7 +1928,7 @@ public final class Launcher extends Activity switch (item.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: - final View shortcut = createShortcut((ApplicationInfo) item); + final View shortcut = createShortcut((ShortcutInfo)item); workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1, false); break; diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java index a72e53a219..183dbf5719 100644 --- a/src/com/android/launcher2/LauncherApplication.java +++ b/src/com/android/launcher2/LauncherApplication.java @@ -25,11 +25,8 @@ import android.os.Handler; import dalvik.system.VMRuntime; public class LauncherApplication extends Application { - public final LauncherModel mModel; - - public LauncherApplication() { - mModel = new LauncherModel(this); - } + public LauncherModel mModel; + public IconCache mIconCache; @Override public void onCreate() { @@ -37,6 +34,9 @@ public class LauncherApplication extends Application { super.onCreate(); + mIconCache = new IconCache(this); + mModel = new LauncherModel(this, mIconCache); + // Register intent receivers IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -79,4 +79,12 @@ public class LauncherApplication extends Application { mModel.initialize(launcher); return mModel; } + + IconCache getIconCache() { + return mIconCache; + } + + LauncherModel getModel() { + return mModel; + } } diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index 7eb240faf0..16e5c3b6ff 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -24,6 +24,7 @@ import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; +import android.content.Intent.ShortcutIconResource; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -34,6 +35,7 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.Parcelable; import android.os.RemoteException; import android.util.Log; import android.os.Process; @@ -65,7 +67,10 @@ public class LauncherModel extends BroadcastReceiver { private boolean mBeforeFirstLoad = true; private WeakReference mCallbacks; - private AllAppsList mAllAppsList = new AllAppsList(); + private AllAppsList mAllAppsList; + private IconCache mIconCache; + + private Bitmap mDefaultIcon; public interface Callbacks { public int getCurrentWorkspaceScreen(); @@ -80,8 +85,17 @@ public class LauncherModel extends BroadcastReceiver { public void bindPackageRemoved(String packageName, ArrayList apps); } - LauncherModel(LauncherApplication app) { + LauncherModel(LauncherApplication app, IconCache iconCache) { mApp = app; + mAllAppsList = new AllAppsList(iconCache); + mIconCache = iconCache; + + mDefaultIcon = Utilities.createIconBitmap( + app.getPackageManager().getDefaultActivityIcon(), app); + } + + public Bitmap getDefaultIcon() { + return Bitmap.createBitmap(mDefaultIcon); } /** @@ -323,7 +337,7 @@ public class LauncherModel extends BroadcastReceiver { removed = mAllAppsList.removed; mAllAppsList.removed = new ArrayList(); for (ApplicationInfo info: removed) { - AppInfoCache.remove(info.intent.getComponent()); + mIconCache.remove(info.intent.getComponent()); } } if (mAllAppsList.modified.size() > 0) { @@ -658,7 +672,7 @@ public class LauncherModel extends BroadcastReceiver { final int displayModeIndex = c.getColumnIndexOrThrow( LauncherSettings.Favorites.DISPLAY_MODE); - ApplicationInfo info; + ShortcutInfo info; String intentDescription; LauncherAppWidgetInfo appWidgetInfo; int container; @@ -680,15 +694,15 @@ public class LauncherModel extends BroadcastReceiver { } if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { - info = getApplicationInfo(manager, intent, context); + info = getShortcutInfo(manager, intent, context); } else { - info = getApplicationInfoShortcut(c, context, iconTypeIndex, + info = getShortcutInfo(c, context, iconTypeIndex, iconPackageIndex, iconResourceIndex, iconIndex); } if (info == null) { - info = new ApplicationInfo(); - info.icon = manager.getDefaultActivityIcon(); + info = new ShortcutInfo(); + info.setIcon(getDefaultIcon()); } if (info != null) { @@ -973,9 +987,7 @@ public class LauncherModel extends BroadcastReceiver { return; } - final Context context = mContext; - final PackageManager packageManager = context.getPackageManager(); - + final PackageManager packageManager = mContext.getPackageManager(); final List apps = packageManager.queryIntentActivities(mainIntent, 0); synchronized (mLock) { @@ -986,10 +998,9 @@ public class LauncherModel extends BroadcastReceiver { long t = SystemClock.uptimeMillis(); int N = apps.size(); - Utilities.BubbleText bubble = new Utilities.BubbleText(context); for (int i=0; i(icon)); } } else if (holder.iconResourceIndex != -1 && holder.iconPackageIndex != -1) { @@ -154,7 +159,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 = new FastBitmapDrawable( + Utilities.createIconBitmap(resources.getDrawable(id), mContext)); 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 55f100cced..f80928bd47 100644 --- a/src/com/android/launcher2/LiveFolderIcon.java +++ b/src/com/android/launcher2/LiveFolderIcon.java @@ -21,7 +21,7 @@ import android.content.res.Resources; import android.util.AttributeSet; import android.view.ViewGroup; import android.view.LayoutInflater; -import android.graphics.drawable.Drawable; +import android.graphics.Bitmap; public class LiveFolderIcon extends FolderIcon { public LiveFolderIcon(Context context, AttributeSet attrs) { @@ -39,13 +39,12 @@ public class LiveFolderIcon extends FolderIcon { LayoutInflater.from(launcher).inflate(resId, group, false); final Resources resources = launcher.getResources(); - Drawable d = folderInfo.icon; - if (d == null) { - d = Utilities.createIconThumbnail(resources.getDrawable(R.drawable.ic_launcher_folder), + Bitmap b = folderInfo.icon; + if (b == null) { + b = Utilities.createIconBitmap(resources.getDrawable(R.drawable.ic_launcher_folder), launcher); - folderInfo.filtered = true; } - icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null); + icon.setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(b), null, null); icon.setText(folderInfo.title); icon.setTag(folderInfo); icon.setOnClickListener(launcher); diff --git a/src/com/android/launcher2/LiveFolderInfo.java b/src/com/android/launcher2/LiveFolderInfo.java index 5b1217c153..7d0a0f58fe 100644 --- a/src/com/android/launcher2/LiveFolderInfo.java +++ b/src/com/android/launcher2/LiveFolderInfo.java @@ -19,6 +19,7 @@ package com.android.launcher2; import android.content.ContentValues; import android.content.Intent; import android.graphics.drawable.Drawable; +import android.graphics.Bitmap; import android.net.Uri; class LiveFolderInfo extends FolderInfo { @@ -41,12 +42,7 @@ class LiveFolderInfo extends FolderInfo { /** * The live folder icon. */ - Drawable icon; - - /** - * When set to true, indicates that the icon has been resized. - */ - boolean filtered; + Bitmap icon; /** * Reference to the live folder icon as an application's resource. diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java new file mode 100644 index 0000000000..cb73ac05bc --- /dev/null +++ b/src/com/android/launcher2/ShortcutInfo.java @@ -0,0 +1,159 @@ +/* + * 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.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.util.Log; + +import java.util.ArrayList; + +/** + * Represents a launchable icon on the workspaces and in folders. + */ +class ShortcutInfo extends ItemInfo { + + /** + * The application name. + */ + CharSequence title; + + /** + * The intent used to start the application. + */ + Intent intent; + + /** + * Indicates whether the icon comes from an application's resource (if false) + * or from a custom Bitmap (if true.) + */ + boolean customIcon; + + /** + * If isShortcut=true and customIcon=false, this contains a reference to the + * shortcut icon as an application's resource. + */ + Intent.ShortcutIconResource iconResource; + + /** + * The application icon. + */ + private Bitmap mIcon; + + ShortcutInfo() { + itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT; + } + + public ShortcutInfo(ShortcutInfo info) { + super(info); + title = info.title.toString(); + intent = new Intent(info.intent); + if (info.iconResource != null) { + iconResource = new Intent.ShortcutIconResource(); + iconResource.packageName = info.iconResource.packageName; + iconResource.resourceName = info.iconResource.resourceName; + } + mIcon = info.mIcon; // TODO: should make a copy here. maybe we don't need this ctor at all + customIcon = info.customIcon; + } + + /** TODO: Remove this. It's only called by ApplicationInfo.makeShortcut. */ + public ShortcutInfo(ApplicationInfo info) { + super(info); + title = info.title.toString(); + intent = new Intent(info.intent); + customIcon = false; + } + + public void setIcon(Bitmap b) { + mIcon = b; + } + + public Bitmap getIcon(IconCache iconCache) { + if (mIcon == null) { + mIcon = iconCache.getIcon(this.intent); + } + return mIcon; + } + + /** + * Creates the application intent based on a component name and various launch flags. + * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}. + * + * @param className the class name of the component representing the intent + * @param launchFlags the launch flags + */ + final void setActivity(ComponentName className, int launchFlags) { + intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.setComponent(className); + intent.setFlags(launchFlags); + itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION; + } + + @Override + void onAddToDatabase(ContentValues values) { + super.onAddToDatabase(values); + + String titleStr = title != null ? title.toString() : null; + values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr); + + String uri = intent != null ? intent.toUri(0) : null; + values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri); + + if (customIcon) { + values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE, + LauncherSettings.BaseLauncherColumns.ICON_TYPE_BITMAP); + Bitmap bitmap = this.mIcon; + writeBitmap(values, bitmap); + } else { + values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE, + LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE); + if (iconResource != null) { + values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE, + iconResource.packageName); + values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE, + iconResource.resourceName); + } + } + } + + @Override + public String toString() { + return title.toString(); + } + + @Override + void unbind() { + super.unbind(); + } + + + public static void dumpShortcutInfoList(String tag, String label, + ArrayList list) { + Log.d(tag, label + " size=" + list.size()); + for (ShortcutInfo info: list) { + Log.d(tag, " title=\"" + info.title + " icon=" + info.mIcon + + " customIcon=" + info.customIcon); + } + } +} + diff --git a/src/com/android/launcher2/ApplicationsAdapter.java b/src/com/android/launcher2/ShortcutsAdapter.java similarity index 73% rename from src/com/android/launcher2/ApplicationsAdapter.java rename to src/com/android/launcher2/ShortcutsAdapter.java index 129103af08..212b5d62d6 100644 --- a/src/com/android/launcher2/ApplicationsAdapter.java +++ b/src/com/android/launcher2/ShortcutsAdapter.java @@ -29,34 +29,29 @@ import java.util.ArrayList; /** * GridView adapter to show the list of applications and shortcuts */ -public class ApplicationsAdapter extends ArrayAdapter { +public class ShortcutsAdapter extends ArrayAdapter { private final LayoutInflater mInflater; private final PackageManager mPackageManager; + private final IconCache mIconCache; - public ApplicationsAdapter(Context context, ArrayList apps) { + public ShortcutsAdapter(Context context, ArrayList apps) { super(context, 0, apps); mPackageManager = context.getPackageManager(); mInflater = LayoutInflater.from(context); + mIconCache = ((LauncherApplication)context.getApplicationContext()).getIconCache(); } @Override public View getView(int position, View convertView, ViewGroup parent) { - final ApplicationInfo info = getItem(position); + final ShortcutInfo info = getItem(position); if (convertView == null) { convertView = mInflater.inflate(R.layout.application_boxed, parent, false); } - if (info.icon == null) { - info.icon = AppInfoCache.getIconDrawable(mPackageManager, info); - } - if (!info.filtered) { - info.icon = Utilities.createIconThumbnail(info.icon, getContext()); - info.filtered = true; - } - final TextView textView = (TextView) convertView; - textView.setCompoundDrawablesWithIntrinsicBounds(null, info.icon, null, null); + textView.setCompoundDrawablesWithIntrinsicBounds(null, + new FastBitmapDrawable(info.getIcon(mIconCache)), null, null); textView.setText(info.title); return convertView; diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java index 16fe6160ce..1489492170 100644 --- a/src/com/android/launcher2/UserFolder.java +++ b/src/com/android/launcher2/UserFolder.java @@ -46,13 +46,14 @@ public class UserFolder extends Folder implements DropTarget { public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, DragView dragView, Object dragInfo) { - ApplicationInfo item = (ApplicationInfo) dragInfo; - if (item.container == NO_ID) { + ShortcutInfo item; + if (dragInfo instanceof ApplicationInfo) { // Came from all apps -- make a copy - item = new ApplicationInfo((ApplicationInfo)item); + item = ((ApplicationInfo)dragInfo).makeShortcut(); + } else { + item = (ShortcutInfo)dragInfo; } - //noinspection unchecked - ((ArrayAdapter) mContent.getAdapter()).add((ApplicationInfo) dragInfo); + ((ShortcutsAdapter)mContent.getAdapter()).add(item); LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0); } @@ -71,16 +72,14 @@ public class UserFolder extends Folder implements DropTarget { @Override public void onDropCompleted(View target, boolean success) { if (success) { - //noinspection unchecked - ArrayAdapter adapter = - (ArrayAdapter) mContent.getAdapter(); + ShortcutsAdapter adapter = (ShortcutsAdapter)mContent.getAdapter(); adapter.remove(mDragItem); } } void bind(FolderInfo info) { super.bind(info); - setContentAdapter(new ApplicationsAdapter(mContext, ((UserFolderInfo) info).contents)); + setContentAdapter(new ShortcutsAdapter(mContext, ((UserFolderInfo) info).contents)); } // When the folder opens, we need to refresh the GridView's selection by diff --git a/src/com/android/launcher2/UserFolderInfo.java b/src/com/android/launcher2/UserFolderInfo.java index 75b19eec66..0b8841c105 100644 --- a/src/com/android/launcher2/UserFolderInfo.java +++ b/src/com/android/launcher2/UserFolderInfo.java @@ -27,7 +27,7 @@ class UserFolderInfo extends FolderInfo { /** * The apps and shortcuts */ - ArrayList contents = new ArrayList(); + ArrayList contents = new ArrayList(); UserFolderInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER; @@ -38,7 +38,7 @@ class UserFolderInfo extends FolderInfo { * * @param item */ - public void add(ApplicationInfo item) { + public void add(ShortcutInfo item) { contents.add(item); } @@ -47,7 +47,7 @@ class UserFolderInfo extends FolderInfo { * * @param item */ - public void remove(ApplicationInfo item) { + public void remove(ShortcutInfo item) { contents.remove(item); } diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java index 30108af0bd..93ff97af82 100644 --- a/src/com/android/launcher2/Utilities.java +++ b/src/com/android/launcher2/Utilities.java @@ -85,87 +85,6 @@ final class Utilities { return bitmap; } - /** - * Returns a Drawable representing the thumbnail of the specified Drawable. - * The size of the thumbnail is defined by the dimension - * android.R.dimen.launcher_application_icon_size. - * - * @param icon The icon to get a thumbnail of. - * @param context The application's context. - * - * @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) { - synchronized (sCanvas) { // we share the statics :-( - if (sIconWidth == -1) { - initStatics(context); - } - - int width = sIconWidth; - int height = sIconHeight; - - 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()); - } - } - int iconWidth = icon.getIntrinsicWidth(); - int iconHeight = icon.getIntrinsicHeight(); - - if (iconWidth > 0 && iconHeight > 0) { - if (width < iconWidth || height < iconHeight) { - 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); - } - } - - return icon; - } - } - static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff }; static int sColorIndex = 0; @@ -173,7 +92,7 @@ final class Utilities { * Returns a bitmap suitable for the all apps view. The bitmap will be a power * of two sized ARGB_8888 bitmap that can be used as a gl texture. */ - static Bitmap createAllAppsBitmap(Drawable icon, Context context) { + static Bitmap createIconBitmap(Drawable icon, Context context) { synchronized (sCanvas) { // we share the statics :-( if (sIconWidth == -1) { initStatics(context); @@ -279,55 +198,17 @@ final class Utilities { * @return A thumbnail for the specified bitmap or the bitmap itself if the * thumbnail could not be created. */ - static Bitmap createBitmapThumbnail(Bitmap bitmap, Context context) { + static Bitmap resampleIconBitmap(Bitmap bitmap, Context context) { synchronized (sCanvas) { // we share the statics :-( if (sIconWidth == -1) { initStatics(context); } - int width = sIconWidth; - int height = sIconHeight; - - final int bitmapWidth = bitmap.getWidth(); - final int bitmapHeight = bitmap.getHeight(); - - if (width > 0 && height > 0) { - if (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); - } - - 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; - } else if (bitmapWidth < width || bitmapHeight < height) { - final Bitmap.Config c = 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); - canvas.drawBitmap(bitmap, (sIconWidth - bitmapWidth) / 2, - (sIconHeight - bitmapHeight) / 2, paint); - return thumb; - } + if (bitmap.getWidth() == sIconWidth && bitmap.getHeight() == sIconHeight) { + return bitmap; + } else { + return createIconBitmap(new BitmapDrawable(bitmap), context); } - - return bitmap; } } diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 2c95beea85..1d2d75e51b 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -90,6 +90,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private OnLongClickListener mLongClickListener; private Launcher mLauncher; + private IconCache mIconCache; private DragController mDragController; /** @@ -142,9 +143,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag * Initializes various states for this workspace. */ private void initWorkspace() { - mScroller = new Scroller(getContext()); + Context context = getContext(); + mScroller = new Scroller(context); mCurrentScreen = mDefaultScreen; Launcher.setScreen(mCurrentScreen); + LauncherApplication app = (LauncherApplication)context.getApplicationContext(); + mIconCache = app.getIconCache(); final ViewConfiguration configuration = ViewConfiguration.get(getContext()); mTouchSlop = configuration.getScaledTouchSlop(); @@ -880,11 +884,11 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } } - void addApplicationShortcut(ApplicationInfo info, CellLayout.CellInfo cellInfo) { + void addApplicationShortcut(ShortcutInfo info, CellLayout.CellInfo cellInfo) { addApplicationShortcut(info, cellInfo, false); } - void addApplicationShortcut(ApplicationInfo info, CellLayout.CellInfo cellInfo, + void addApplicationShortcut(ShortcutInfo info, CellLayout.CellInfo cellInfo, boolean insertAtFirst) { final CellLayout layout = (CellLayout) getChildAt(cellInfo.screen); final int[] result = new int[2]; @@ -950,10 +954,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: if (info.container == NO_ID) { // Came from all apps -- make a copy - info = new ApplicationInfo((ApplicationInfo) info); + info = new ShortcutInfo((ShortcutInfo)info); } - view = mLauncher.createShortcut(R.layout.application, cellLayout, - (ApplicationInfo) info); + view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo)info); break; case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, @@ -1183,8 +1186,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag final View view = layout.getChildAt(j); Object tag = view.getTag(); - if (tag instanceof ApplicationInfo) { - final ApplicationInfo info = (ApplicationInfo) tag; + if (tag instanceof ShortcutInfo) { + final ShortcutInfo info = (ShortcutInfo) tag; // We need to check for ACTION_MAIN otherwise getComponent() might // return null for some shortcuts (for instance, for shortcuts to // web pages.) @@ -1199,14 +1202,13 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } } else if (tag instanceof UserFolderInfo) { final UserFolderInfo info = (UserFolderInfo) tag; - final ArrayList contents = info.contents; - final ArrayList toRemove = - new ArrayList(1); + final ArrayList contents = info.contents; + final ArrayList toRemove = new ArrayList(1); final int contentsCount = contents.size(); boolean removedFromFolder = false; for (int k = 0; k < contentsCount; k++) { - final ApplicationInfo appInfo = contents.get(k); + final ShortcutInfo appInfo = contents.get(k); final Intent intent = appInfo.intent; final ComponentName name = intent.getComponent(); @@ -1277,8 +1279,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag for (int j = 0; j < childCount; j++) { final View view = layout.getChildAt(j); Object tag = view.getTag(); - if (tag instanceof ApplicationInfo) { - ApplicationInfo info = (ApplicationInfo) tag; + if (tag instanceof ShortcutInfo) { + ShortcutInfo info = (ShortcutInfo)tag; // We need to check for ACTION_MAIN otherwise getComponent() might // return null for some shortcuts (for instance, for shortcuts to // web pages.) @@ -1288,14 +1290,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag Intent.ACTION_MAIN.equals(intent.getAction()) && name != null && packageName.equals(name.getPackageName())) { - final Drawable icon = AppInfoCache.getIconDrawable(pm, info); - if (icon != null && icon != info.icon) { - info.icon.setCallback(null); - info.icon = Utilities.createIconThumbnail(icon, mContext); - info.filtered = true; - ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(null, - info.icon, null, null); - } + info.setIcon(mIconCache.getIcon(info.intent)); + ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(null, + new FastBitmapDrawable(info.getIcon(mIconCache)), null, null); } } }