diff options
author | Joe Onorato <joeo@android.com> | 2010-02-18 15:31:52 -0800 |
---|---|---|
committer | Joe Onorato <joeo@android.com> | 2010-02-18 17:09:55 -0800 |
commit | 75fd1ec46da7708bd46183da7999ec891d63140d (patch) | |
tree | fb1745879c5acaa3efbf86e28662a3e2ef0a2a8e /src | |
parent | b8fc9e7df69db4b1647ef780f5620836c86f70ea (diff) | |
download | android_packages_apps_Trebuchet-75fd1ec46da7708bd46183da7999ec891d63140d.tar.gz android_packages_apps_Trebuchet-75fd1ec46da7708bd46183da7999ec891d63140d.tar.bz2 android_packages_apps_Trebuchet-75fd1ec46da7708bd46183da7999ec891d63140d.zip |
DO NOT MERGE - Use the froyo launcher2 in mr3, except for a few unbundling things that can't be merged back.
Diffstat (limited to 'src')
31 files changed, 1232 insertions, 1642 deletions
diff --git a/src/com/android/launcher2/ActivityPicker.java b/src/com/android/launcher2/ActivityPicker.java deleted file mode 100644 index b6da08e4b..000000000 --- a/src/com/android/launcher2/ActivityPicker.java +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Copyright (C) 2009 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 com.android.internal.app.AlertActivity; -import com.android.internal.app.AlertController; - -import android.app.Activity; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.Intent.ShortcutIconResource; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PaintFlagsDrawFilter; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.PaintDrawable; -import android.os.Bundle; -import android.os.Parcelable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.TextView; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Displays a list of all activities matching the incoming - * {@link android.content.Intent#EXTRA_INTENT} query, along with any injected items. - */ -public class ActivityPicker extends AlertActivity implements - DialogInterface.OnClickListener, DialogInterface.OnCancelListener { - - /** - * Adapter of items that are displayed in this dialog. - */ - private PickAdapter mAdapter; - - /** - * Base {@link android.content.Intent} used when building list. - */ - private Intent mBaseIntent; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - final Intent intent = getIntent(); - - // Read base intent from extras, otherwise assume default - Parcelable parcel = intent.getParcelableExtra(Intent.EXTRA_INTENT); - if (parcel instanceof Intent) { - mBaseIntent = (Intent) parcel; - } else { - mBaseIntent = new Intent(Intent.ACTION_MAIN, null); - mBaseIntent.addCategory(Intent.CATEGORY_DEFAULT); - } - - // Create dialog parameters - AlertController.AlertParams params = mAlertParams; - params.mOnClickListener = this; - params.mOnCancelListener = this; - - // Use custom title if provided, otherwise default window title - if (intent.hasExtra(Intent.EXTRA_TITLE)) { - params.mTitle = intent.getStringExtra(Intent.EXTRA_TITLE); - } else { - params.mTitle = getTitle(); - } - - // Build list adapter of pickable items - List<PickAdapter.Item> items = getItems(); - mAdapter = new PickAdapter(this, items); - params.mAdapter = mAdapter; - - setupAlert(); - } - - /** - * Handle clicking of dialog item by passing back - * {@link #getIntentForPosition(int)} in {@link #setResult(int, android.content.Intent)}. - */ - public void onClick(DialogInterface dialog, int which) { - Intent intent = getIntentForPosition(which); - setResult(Activity.RESULT_OK, intent); - finish(); - } - - /** - * Handle canceled dialog by passing back {@link android.app.Activity#RESULT_CANCELED}. - */ - public void onCancel(DialogInterface dialog) { - setResult(Activity.RESULT_CANCELED); - finish(); - } - - /** - * Build the specific {@link android.content.Intent} for a given list position. Convenience - * method that calls through to {@link PickAdapter.Item#getIntent(android.content.Intent)}. - */ - protected Intent getIntentForPosition(int position) { - PickAdapter.Item item = (PickAdapter.Item) mAdapter.getItem(position); - return item.getIntent(mBaseIntent); - } - - /** - * Build and return list of items to be shown in dialog. Default - * implementation mixes activities matching {@link #mBaseIntent} from - * {@link #putIntentItems(android.content.Intent, java.util.List)} with any injected items from - * {@link android.content.Intent#EXTRA_SHORTCUT_NAME}. Override this method in subclasses to - * change the items shown. - */ - protected List<PickAdapter.Item> getItems() { - PackageManager packageManager = getPackageManager(); - List<PickAdapter.Item> items = new ArrayList<PickAdapter.Item>(); - - // Add any injected pick items - final Intent intent = getIntent(); - ArrayList<String> labels = - intent.getStringArrayListExtra(Intent.EXTRA_SHORTCUT_NAME); - ArrayList<ShortcutIconResource> icons = - intent.getParcelableArrayListExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE); - - if (labels != null && icons != null && labels.size() == icons.size()) { - for (int i = 0; i < labels.size(); i++) { - String label = labels.get(i); - Drawable icon = null; - - try { - // Try loading icon from requested package - ShortcutIconResource iconResource = icons.get(i); - Resources res = packageManager.getResourcesForApplication( - iconResource.packageName); - icon = res.getDrawable(res.getIdentifier( - iconResource.resourceName, null, null)); - } catch (NameNotFoundException e) { - // Ignore - } - - items.add(new PickAdapter.Item(this, label, icon)); - } - } - - // Add any intent items if base was given - if (mBaseIntent != null) { - putIntentItems(mBaseIntent, items); - } - - return items; - } - - /** - * Fill the given list with any activities matching the base {@link android.content.Intent}. - */ - protected void putIntentItems(Intent baseIntent, List<PickAdapter.Item> items) { - PackageManager packageManager = getPackageManager(); - List<ResolveInfo> list = packageManager.queryIntentActivities(baseIntent, - 0 /* no flags */); - Collections.sort(list, new ResolveInfo.DisplayNameComparator(packageManager)); - - final int listSize = list.size(); - for (int i = 0; i < listSize; i++) { - ResolveInfo resolveInfo = list.get(i); - items.add(new PickAdapter.Item(this, packageManager, resolveInfo)); - } - } - - /** - * Adapter which shows the set of activities that can be performed for a - * given {@link android.content.Intent}. - */ - protected static class PickAdapter extends BaseAdapter { - - /** - * Item that appears in a {@link PickAdapter} list. - */ - public static class Item { - protected static IconResizer sResizer; - - protected IconResizer getResizer(Context context) { - if (sResizer == null) { - sResizer = new IconResizer(context); - } - return sResizer; - } - - CharSequence label; - Drawable icon; - String packageName; - String className; - Bundle extras; - - /** - * Create a list item from given label and icon. - */ - Item(Context context, CharSequence label, Drawable icon) { - this.label = label; - this.icon = getResizer(context).createIconThumbnail(icon); - } - - /** - * Create a list item and fill it with details from the given - * {@link android.content.pm.ResolveInfo} object. - */ - Item(Context context, PackageManager pm, ResolveInfo resolveInfo) { - label = resolveInfo.loadLabel(pm); - if (label == null && resolveInfo.activityInfo != null) { - label = resolveInfo.activityInfo.name; - } - - icon = getResizer(context).createIconThumbnail(resolveInfo.loadIcon(pm)); - packageName = resolveInfo.activityInfo.applicationInfo.packageName; - className = resolveInfo.activityInfo.name; - } - - Intent getIntent(Intent baseIntent) { - Intent intent = new Intent(baseIntent); - if (packageName != null && className != null) { - // Valid package and class, so fill details as normal intent - intent.setClassName(packageName, className); - if (extras != null) { - intent.putExtras(extras); - } - } else { - // No valid package or class, so treat as shortcut with label - intent.setAction(Intent.ACTION_CREATE_SHORTCUT); - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, label); - } - return intent; - } - } - - private final LayoutInflater mInflater; - - private List<Item> mItems; - private int mLayoutRes = R.layout.pick_item; - - /** - * Create an adapter for the given items. - */ - public PickAdapter(Context context, List<Item> items) { - mInflater = (LayoutInflater) - context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mItems = items; - } - - /** - * {@inheritDoc} - */ - public int getCount() { - return mItems.size(); - } - - /** - * {@inheritDoc} - */ - public Object getItem(int position) { - return mItems.get(position); - } - - /** - * {@inheritDoc} - */ - public long getItemId(int position) { - return position; - } - - /** - * {@inheritDoc} - */ - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = mInflater.inflate(mLayoutRes, parent, false); - } - - Item item = (Item) getItem(position); - TextView textView = (TextView) convertView; - textView.setText(item.label); - textView.setCompoundDrawablesWithIntrinsicBounds(item.icon, null, null, null); - - return convertView; - } - } - - /** - * Utility class to resize icons to match default icon size. Code is mostly - * borrowed from Launcher. - */ - private static class IconResizer { - private int mIconWidth = -1; - private int mIconHeight = -1; - - private final Rect mOldBounds = new Rect(); - private Canvas mCanvas = new Canvas(); - private Resources mResources; - - public IconResizer(Context context) { - mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, - Paint.FILTER_BITMAP_FLAG)); - - mResources = context.getResources(); - mIconWidth = mIconHeight = (int) mResources.getDimension( - android.R.dimen.app_icon_size); - } - - /** - * 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. - * - * This method is not thread-safe and should be invoked on the UI thread only. - * - * @param icon The icon to get a thumbnail of. - * - * @return A thumbnail for the specified icon or the icon itself if the - * thumbnail could not be created. - */ - public Drawable createIconThumbnail(Drawable icon) { - int width = mIconWidth; - int height = mIconHeight; - - if (icon == null) { - return null; - } - - final int iconWidth = icon.getIntrinsicWidth(); - final int iconHeight = icon.getIntrinsicHeight(); - - if (icon instanceof PaintDrawable) { - PaintDrawable painter = (PaintDrawable) icon; - painter.setIntrinsicWidth(width); - painter.setIntrinsicHeight(height); - } - - if (width > 0 && height > 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(mIconWidth, mIconHeight, c); - final Canvas canvas = mCanvas; - 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 - mOldBounds.set(icon.getBounds()); - final int x = (mIconWidth - width) / 2; - final int y = (mIconHeight - height) / 2; - icon.setBounds(x, y, x + width, y + height); - icon.draw(canvas); - icon.setBounds(mOldBounds); - icon = new BitmapDrawable(mResources, thumb); - } else if (iconWidth < width && iconHeight < height) { - final Bitmap.Config c = Bitmap.Config.ARGB_8888; - final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c); - final Canvas canvas = mCanvas; - canvas.setBitmap(thumb); - mOldBounds.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(mOldBounds); - icon = new BitmapDrawable(mResources, thumb); - } - } - - return icon; - } - } -} diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java index 561b34597..9d4c5b02a 100644 --- a/src/com/android/launcher2/AllAppsList.java +++ b/src/com/android/launcher2/AllAppsList.java @@ -17,25 +17,13 @@ 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; @@ -46,18 +34,23 @@ class AllAppsList { public static final int DEFAULT_APPLICATIONS_NUMBER = 42; /** The list off all apps. */ - public ArrayList<ApplicationInfo> data = new ArrayList(DEFAULT_APPLICATIONS_NUMBER); + public ArrayList<ApplicationInfo> data = + new ArrayList<ApplicationInfo>(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); + public ArrayList<ApplicationInfo> added = + new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER); /** The list of apps that have been removed since the last notify() call. */ - public ArrayList<ApplicationInfo> removed = new ArrayList(); + public ArrayList<ApplicationInfo> removed = new ArrayList<ApplicationInfo>(); /** The list of apps that have been modified since the last notify() call. */ - public ArrayList<ApplicationInfo> modified = new ArrayList(); + public ArrayList<ApplicationInfo> modified = new ArrayList<ApplicationInfo>(); + + private IconCache mIconCache; /** * Boring constructor. */ - public AllAppsList() { + public AllAppsList(IconCache iconCache) { + mIconCache = iconCache; } /** @@ -92,9 +85,8 @@ class AllAppsList { 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); + ApplicationInfo item = new ApplicationInfo(info, mIconCache); data.add(item); added.add(item); } @@ -106,7 +98,7 @@ class AllAppsList { */ public void removePackage(String packageName) { final List<ApplicationInfo> data = this.data; - for (int i=data.size()-1; i>=0; i--) { + 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())) { @@ -115,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. */ @@ -126,13 +118,13 @@ class AllAppsList { 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--) { + 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); + mIconCache.remove(component); data.remove(i); } } @@ -140,19 +132,19 @@ 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++) { + 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); + 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/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java index 13da32915..336f117d1 100644 --- a/src/com/android/launcher2/AllAppsView.java +++ b/src/com/android/launcher2/AllAppsView.java @@ -114,8 +114,10 @@ public class AllAppsView extends RSSurfaceView private boolean mShouldGainFocus; + private boolean mHaveSurface = false; private boolean mZoomDirty = false; private boolean mAnimateNextZoom; + private float mNextZoom; private float mZoom; private float mPosX; private float mVelocity; @@ -125,20 +127,19 @@ public class AllAppsView extends RSSurfaceView public static final int ALLOC_PARAMS = 0; public static final int ALLOC_STATE = 1; public static final int ALLOC_ICON_IDS = 3; + public static final int ALLOC_LABEL_IDS = 4; + public static final int ALLOC_VP_CONSTANTS = 5; public static final int COLUMNS_PER_PAGE = 4; public static final int ROWS_PER_PAGE = 4; - public static final int ICON_TEXTURE_WIDTH_PX = 128; - public static final int ICON_TEXTURE_HEIGHT_PX = 128; + public static final int ICON_WIDTH_PX = 64; + public static final int ICON_TEXTURE_WIDTH_PX = 74; + public static final int SELECTION_TEXTURE_WIDTH_PX = 74 + 20; - public int SCREEN_WIDTH_PX; - public int SCREEN_HEIGHT_PX; - - public void recompute(int w, int h) { - SCREEN_WIDTH_PX = 480; - SCREEN_HEIGHT_PX = 800; - } + public static final int ICON_HEIGHT_PX = 64; + public static final int ICON_TEXTURE_HEIGHT_PX = 74; + public static final int SELECTION_TEXTURE_HEIGHT_PX = 74 + 20; } public AllAppsView(Context context, AttributeSet attrs) { @@ -158,9 +159,14 @@ public class AllAppsView extends RSSurfaceView mRS = createRenderScript(true); } + /** + * Note that this implementation prohibits this view from ever being reattached. + */ @Override protected void onDetachedFromWindow() { destroyRenderScript(); + mRS.mMessageCallback = null; + mRS = null; } /** @@ -185,9 +191,12 @@ public class AllAppsView extends RSSurfaceView @Override public void surfaceDestroyed(SurfaceHolder holder) { super.surfaceDestroyed(holder); - mRollo.mHasSurface = false; // Without this, we leak mMessageCallback which leaks the context. mRS.mMessageCallback = null; + // We may lose any callbacks that are pending, so make sure that we re-sync that + // on the next surfaceChanged. + mZoomDirty = true; + mHaveSurface = false; } @Override @@ -196,9 +205,10 @@ public class AllAppsView extends RSSurfaceView super.surfaceChanged(holder, format, w, h); + mHaveSurface = true; + if (mRollo == null) { mRollo = new RolloRS(); - mRollo.mHasSurface = true; mRollo.init(getResources(), w, h); if (mAllAppsList != null) { mRollo.setApps(mAllAppsList); @@ -207,17 +217,34 @@ public class AllAppsView extends RSSurfaceView gainFocus(); mShouldGainFocus = false; } - } else { - mRollo.mHasSurface = true; } mRollo.dirtyCheck(); mRollo.resize(w, h); - mRS.mMessageCallback = mMessageProc = new AAMessage(); + if (mRS != null) { + mRS.mMessageCallback = mMessageProc = new AAMessage(); + } Resources res = getContext().getResources(); int barHeight = (int)res.getDimension(R.dimen.button_bar_height); + + if (mRollo.mUniformAlloc != null) { + float tf[] = new float[] {72.f, 72.f, + 120.f, 120.f, 0.f, 0.f, + 120.f, 680.f, + (2.f / 480.f), 0, -((float)w / 2) - 0.25f, -380.25f}; + if (w > h) { + tf[6] = 40.f; + tf[7] = h - 40.f; + tf[9] = 1.f; + tf[10] = -((float)w / 2) - 0.25f; + tf[11] = -((float)h / 2) - 0.25f; + } + + mRollo.mUniformAlloc.data(tf); + } + //long endTime = SystemClock.uptimeMillis(); //Log.d(TAG, "surfaceChanged took " + (endTime-startTime) + "ms"); } @@ -267,7 +294,7 @@ public class AllAppsView extends RSSurfaceView } if (gainFocus) { - if (mRollo != null && mRollo.mHasSurface) { + if (mRollo != null) { gainFocus(); } else { mShouldGainFocus = true; @@ -402,15 +429,19 @@ public class AllAppsView extends RSSurfaceView break; } case KeyEvent.KEYCODE_DPAD_LEFT: - if (currentPageCol > 0) { - newSelection = currentSelection - 1; + if (mLastSelection != SELECTION_HOME) { + if (currentPageCol > 0) { + newSelection = currentSelection - 1; + } } handled = true; break; case KeyEvent.KEYCODE_DPAD_RIGHT: - if ((currentPageCol < Defines.COLUMNS_PER_PAGE - 1) && - (currentSelection < iconCount - 1)) { - newSelection = currentSelection + 1; + if (mLastSelection != SELECTION_HOME) { + if ((currentPageCol < Defines.COLUMNS_PER_PAGE - 1) && + (currentSelection < iconCount - 1)) { + newSelection = currentSelection + 1; + } } handled = true; break; @@ -567,8 +598,7 @@ public class AllAppsView extends RSSurfaceView && mCurrentIconIndex >= 0 && mCurrentIconIndex < mAllAppsList.size()) { ApplicationInfo app = mAllAppsList.get(mCurrentIconIndex); - Bitmap bmp = Utilities.extractIconFromTexture(app.iconBitmap, getContext()); - + Bitmap bmp = app.iconBitmap; final int w = bmp.getWidth(); final int h = bmp.getHeight(); @@ -576,9 +606,10 @@ public class AllAppsView extends RSSurfaceView int screenX = mMotionDownRawX - (w / 2); int screenY = mMotionDownRawY - h; + int left = (mDefines.ICON_TEXTURE_WIDTH_PX - mDefines.ICON_WIDTH_PX) / 2; + int top = (mDefines.ICON_TEXTURE_HEIGHT_PX - mDefines.ICON_HEIGHT_PX) / 2; mDragController.startDrag(bmp, screenX, screenY, 0, 0, w, h, this, app, DragController.DRAG_ACTION_COPY); - bmp.recycle(); mLauncher.closeAllApps(true); } @@ -636,10 +667,13 @@ public class AllAppsView extends RSSurfaceView */ public void zoom(float zoom, boolean animate) { cancelLongPress(); - if (mRollo == null || !mRollo.mHasSurface) { + mNextZoom = zoom; + mAnimateNextZoom = animate; + // if we do setZoom while we don't have a surface, we won't + // get the callbacks that actually set mZoom. + if (mRollo == null || !mHaveSurface) { mZoomDirty = true; mZoom = zoom; - mAnimateNextZoom = animate; return; } else { mRollo.setZoom(zoom, animate); @@ -655,6 +689,11 @@ public class AllAppsView extends RSSurfaceView } public void setApps(ArrayList<ApplicationInfo> list) { + if (mRS == null) { + // We've been removed from the window. Don't bother with all this. + return; + } + mAllAppsList = list; if (mRollo != null) { mRollo.setApps(list); @@ -667,6 +706,10 @@ public class AllAppsView extends RSSurfaceView // Not done loading yet. We'll find out about it later. return; } + if (mRS == null) { + // We've been removed from the window. Don't bother with all this. + return; + } final int N = list.size(); if (mRollo != null) { @@ -769,16 +812,16 @@ public class AllAppsView extends RSSurfaceView private Script.Invokable mInvokeSetZoom; private ProgramStore mPSIcons; - private ProgramStore mPSText; - private ProgramFragment mPFColor; private ProgramFragment mPFTexMip; + private ProgramFragment mPFTexMipAlpha; private ProgramFragment mPFTexNearest; private ProgramVertex mPV; - private ProgramVertex mPVOrtho; + private ProgramVertex mPVCurve; private SimpleMesh mMesh; - private SimpleMesh mMesh2; private ProgramVertex.MatrixAllocation mPVA; + private Allocation mUniformAlloc; + private Allocation mHomeButtonNormal; private Allocation mHomeButtonFocused; private Allocation mHomeButtonPressed; @@ -786,6 +829,10 @@ public class AllAppsView extends RSSurfaceView private Allocation[] mIcons; private int[] mIconIds; private Allocation mAllocIconIds; + + private Allocation[] mLabels; + private int[] mLabelIds; + private Allocation mAllocLabelIds; private Allocation mSelectedIcon; private int[] mTouchYBorders; @@ -794,9 +841,6 @@ public class AllAppsView extends RSSurfaceView private Bitmap mSelectionBitmap; private Canvas mSelectionCanvas; - boolean mHasSurface = false; - private boolean mAppsDirty = true; - Params mParams; State mState; @@ -856,11 +900,9 @@ public class AllAppsView extends RSSurfaceView mRes = res; mWidth = width; mHeight = height; - mDefines.recompute(width, height); initProgramVertex(); initProgramFragment(); initProgramStore(); - initMesh(); initGl(); initData(); initTouchState(); @@ -868,41 +910,19 @@ public class AllAppsView extends RSSurfaceView } public void initMesh() { - SimpleMesh.TriangleMeshBuilder tm = new SimpleMesh.TriangleMeshBuilder(mRS, 3, - SimpleMesh.TriangleMeshBuilder.TEXTURE_0 | SimpleMesh.TriangleMeshBuilder.COLOR); - - float y = 0; - float z = 0; - for (int ct=0; ct < 200; ct++) { - float angle = 0; - float maxAngle = 3.14f * 0.16f; - float l = 1.f; - - l = 1 - ((ct-7) * 0.10f); - if (ct > 7) { - angle = maxAngle * (ct - 7) * 0.2f; - angle = Math.min(angle, maxAngle); - } - l = Math.max(0.4f, l); - l = Math.min(1.0f, l); - - y += 0.1f * Math.cos(angle); - z += 0.1f * Math.sin(angle); - - float t = 0.1f * ct; - float ds = 0.08f; - tm.setColor(l, l, l, 0.99f); - tm.setTexture(ds, t); - tm.addVertex(-0.5f, y, z); - tm.setTexture(1 - ds, t); - tm.addVertex(0.5f, y, z); + SimpleMesh.TriangleMeshBuilder tm = new SimpleMesh.TriangleMeshBuilder(mRS, 2, 0); + + for (int ct=0; ct < 16; ct++) { + float pos = (1.f / (16.f - 1)) * ct; + tm.addVertex(0.0f, pos); + tm.addVertex(1.0f, pos); } - for (int ct=0; ct < (200 * 2 - 2); ct+= 2) { + for (int ct=0; ct < (16 * 2 - 2); ct+= 2) { tm.addTriangle(ct, ct+1, ct+2); tm.addTriangle(ct+1, ct+3, ct+2); } - mMesh2 = tm.create(); - mMesh2.setName("SMMesh"); + mMesh = tm.create(); + mMesh.setName("SMCell"); } void resize(int w, int h) { @@ -921,12 +941,80 @@ public class AllAppsView extends RSSurfaceView mPV.setName("PV"); mPV.bindAllocation(mPVA); - //pva = new ProgramVertex.MatrixAllocation(mRS); - //pva.setupOrthoWindow(mWidth, mHeight); - //pvb.setTextureMatrixEnable(true); - //mPVOrtho = pvb.create(); - //mPVOrtho.setName("PVOrtho"); - //mPVOrtho.bindAllocation(pva); + Element.Builder eb = new Element.Builder(mRS); + eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 2), "ImgSize"); + eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "Position"); + eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 2), "BendPos"); + eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 4), "ScaleOffset"); + Element e = eb.create(); + + mUniformAlloc = Allocation.createSized(mRS, e, 1); + + initMesh(); + ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(mRS); + String t = new String("void main() {\n" + + // Animation + " float ani = UNI_Position.z;\n" + + + " float bendY1 = UNI_BendPos.x;\n" + + " float bendY2 = UNI_BendPos.y;\n" + + " float bendAngle = 47.0 * (3.14 / 180.0);\n" + + " float bendDistance = bendY1 * 0.4;\n" + + " float distanceDimLevel = 0.6;\n" + + + " float bendStep = (bendAngle / bendDistance) * (bendAngle * 0.5);\n" + + " float aDy = cos(bendAngle);\n" + + " float aDz = sin(bendAngle);\n" + + + " float scale = (2.0 / 480.0);\n" + + " float x = UNI_Position.x + UNI_ImgSize.x * (1.0 - ani) * (ATTRIB_position.x - 0.5);\n" + + " float ys= UNI_Position.y + UNI_ImgSize.y * (1.0 - ani) * ATTRIB_position.y;\n" + + " float y = 0.0;\n" + + " float z = 0.0;\n" + + " float lum = 1.0;\n" + + + " float cv = min(ys, bendY1 - bendDistance) - (bendY1 - bendDistance);\n" + + " y += cv * aDy;\n" + + " z += -cv * aDz;\n" + + " cv = clamp(ys, bendY1 - bendDistance, bendY1) - bendY1;\n" + // curve range + " lum += cv / bendDistance * distanceDimLevel;\n" + + " y += cv * cos(cv * bendStep);\n" + + " z += cv * sin(cv * bendStep);\n" + + + " cv = max(ys, bendY2 + bendDistance) - (bendY2 + bendDistance);\n" + + " y += cv * aDy;\n" + + " z += cv * aDz;\n" + + " cv = clamp(ys, bendY2, bendY2 + bendDistance) - bendY2;\n" + + " lum -= cv / bendDistance * distanceDimLevel;\n" + + " y += cv * cos(cv * bendStep);\n" + + " z += cv * sin(cv * bendStep);\n" + + + " y += clamp(ys, bendY1, bendY2);\n" + + + " vec4 pos;\n" + + " pos.x = (x + UNI_ScaleOffset.z) * UNI_ScaleOffset.x;\n" + + " pos.y = (y + UNI_ScaleOffset.w) * UNI_ScaleOffset.x;\n" + + " pos.z = z * UNI_ScaleOffset.x;\n" + + " pos.w = 1.0;\n" + + + " pos.x *= 1.0 + ani * 4.0;\n" + + " pos.y *= 1.0 + ani * 4.0;\n" + + " pos.z -= ani * 1.5;\n" + + " lum *= 1.0 - ani;\n" + + + " gl_Position = UNI_MVP * pos;\n" + + " varColor.rgba = vec4(lum, lum, lum, 1.0);\n" + + " varTex0.xy = ATTRIB_position;\n" + + " varTex0.y = 1.0 - varTex0.y;\n" + + " varTex0.zw = vec2(0.0, 0.0);\n" + + "}\n"); + sb.setShader(t); + sb.addConstant(mUniformAlloc.getType()); + sb.addInput(mMesh.getVertexType(0).getElement()); + mPVCurve = sb.create(); + mPVCurve.setName("PVCurve"); + mPVCurve.bindAllocation(mPVA); + mPVCurve.bindConstants(mUniformAlloc, 1); mRS.contextBindProgramVertex(mPV); } @@ -934,7 +1022,7 @@ public class AllAppsView extends RSSurfaceView private void initProgramFragment() { Sampler.Builder sb = new Sampler.Builder(mRS); sb.setMin(Sampler.Value.LINEAR_MIP_LINEAR); - sb.setMag(Sampler.Value.LINEAR); + sb.setMag(Sampler.Value.NEAREST); sb.setWrapS(Sampler.Value.CLAMP); sb.setWrapT(Sampler.Value.CLAMP); Sampler linear = sb.create(); @@ -944,9 +1032,6 @@ public class AllAppsView extends RSSurfaceView Sampler nearest = sb.create(); ProgramFragment.Builder bf = new ProgramFragment.Builder(mRS); - mPFColor = bf.create(); - mPFColor.setName("PFColor"); - bf.setTexture(ProgramFragment.Builder.EnvMode.MODULATE, ProgramFragment.Builder.Format.RGBA, 0); mPFTexMip = bf.create(); @@ -956,6 +1041,13 @@ public class AllAppsView extends RSSurfaceView mPFTexNearest = bf.create(); mPFTexNearest.setName("PFTexNearest"); mPFTexNearest.bindSampler(nearest, 0); + + bf.setTexture(ProgramFragment.Builder.EnvMode.MODULATE, + ProgramFragment.Builder.Format.ALPHA, 0); + mPFTexMipAlpha = bf.create(); + mPFTexMipAlpha.setName("PFTexMipAlpha"); + mPFTexMipAlpha.bindSampler(linear, 0); + } private void initProgramStore() { @@ -967,10 +1059,6 @@ public class AllAppsView extends RSSurfaceView ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA); mPSIcons = bs.create(); mPSIcons.setName("PSIcons"); - - //bs.setDitherEnable(false); - //mPSText = bs.create(); - //mPSText.setName("PSText"); } private void initGl() { @@ -1008,8 +1096,8 @@ public class AllAppsView extends RSSurfaceView mParams.save(); mState.save(); - mSelectionBitmap = Bitmap.createBitmap(Defines.ICON_TEXTURE_WIDTH_PX, - Defines.ICON_TEXTURE_HEIGHT_PX, Bitmap.Config.ARGB_8888); + mSelectionBitmap = Bitmap.createBitmap(Defines.SELECTION_TEXTURE_WIDTH_PX, + Defines.SELECTION_TEXTURE_HEIGHT_PX, Bitmap.Config.ARGB_8888); mSelectionCanvas = new Canvas(mSelectionBitmap); setApps(null); @@ -1020,11 +1108,12 @@ public class AllAppsView extends RSSurfaceView private void initRs() { ScriptC.Builder sb = new ScriptC.Builder(mRS); - sb.setScript(mRes, R.raw.rollo3); + sb.setScript(mRes, R.raw.allapps); sb.setRoot(true); sb.addDefines(mDefines); sb.setType(mParams.mType, "params", Defines.ALLOC_PARAMS); sb.setType(mState.mType, "state", Defines.ALLOC_STATE); + sb.setType(mUniformAlloc.getType(), "vpConstants", Defines.ALLOC_VP_CONSTANTS); mInvokeMove = sb.addInvokable("move"); mInvokeFling = sb.addInvokable("fling"); mInvokeMoveTo = sb.addInvokable("moveTo"); @@ -1035,22 +1124,15 @@ public class AllAppsView extends RSSurfaceView mScript.bindAllocation(mParams.mAlloc, Defines.ALLOC_PARAMS); mScript.bindAllocation(mState.mAlloc, Defines.ALLOC_STATE); mScript.bindAllocation(mAllocIconIds, Defines.ALLOC_ICON_IDS); + mScript.bindAllocation(mAllocLabelIds, Defines.ALLOC_LABEL_IDS); + mScript.bindAllocation(mUniformAlloc, Defines.ALLOC_VP_CONSTANTS); mRS.contextBindRootScript(mScript); } void dirtyCheck() { - if (mHasSurface) { - if (mAppsDirty && mAllAppsList != null) { - for (int i=0; i < mState.iconCount; i++) { - uploadAppIcon(i, mAllAppsList.get(i)); - } - saveAppsList(); - mAppsDirty = false; - } - if (mZoomDirty) { - setZoom(mZoom, mAnimateNextZoom); - } + if (mZoomDirty) { + setZoom(mNextZoom, mAnimateNextZoom); } } @@ -1065,21 +1147,18 @@ public class AllAppsView extends RSSurfaceView mIconIds = new int[allocCount]; mAllocIconIds = Allocation.createSized(mRS, Element.USER_I32(mRS), allocCount); + mLabels = new Allocation[count]; + mLabelIds = new int[allocCount]; + mAllocLabelIds = Allocation.createSized(mRS, Element.USER_I32(mRS), allocCount); + Element ie8888 = Element.RGBA_8888(mRS); mState.iconCount = count; - long before = SystemClock.uptimeMillis(); for (int i=0; i < mState.iconCount; i++) { createAppIconAllocations(i, list.get(i)); } - long after = SystemClock.uptimeMillis(); - //Log.d(TAG, "createAppIconAllocations took " + (after-before) + "ms"); - if (mHasSurface) { - for (int i=0; i < mState.iconCount; i++) { - uploadAppIcon(i, list.get(i)); - } - } else { - mRollo.mAppsDirty = true; + for (int i=0; i < mState.iconCount; i++) { + uploadAppIcon(i, list.get(i)); } saveAppsList(); } @@ -1098,29 +1177,13 @@ public class AllAppsView extends RSSurfaceView } } - private void frameBitmapAllocMips(Allocation alloc, int w, int h) { - int black[] = new int[w > h ? w : h]; - Allocation.Adapter2D a = alloc.createAdapter2D(); - int mip = 0; - while (w > 1 || h > 1) { - a.subData(0, 0, 1, h, black); - a.subData(w-1, 0, 1, h, black); - a.subData(0, 0, w, 1, black); - a.subData(0, h-1, w, 1, black); - mip++; - w = (w + 1) >> 1; - h = (h + 1) >> 1; - a.setConstraint(Dimension.LOD, mip); - } - a.subData(0, 0, 1, 1, black); - } - private void createAppIconAllocations(int index, ApplicationInfo item) { - Bitmap bitmap = item.iconBitmap; - mIcons[index] = Allocation.createFromBitmap(mRS, bitmap, Element.RGBA_8888(mRS), true); - frameBitmapAllocMips(mIcons[index], bitmap.getWidth(), bitmap.getHeight()); - + mIcons[index] = Allocation.createFromBitmap(mRS, item.iconBitmap, + Element.RGBA_8888(mRS), true); + mLabels[index] = Allocation.createFromBitmap(mRS, item.titleBitmap, + Element.A_8(mRS), true); mIconIds[index] = mIcons[index].getID(); + mLabelIds[index] = mLabels[index].getID(); } private void uploadAppIcon(int index, ApplicationInfo item) { @@ -1131,6 +1194,7 @@ public class AllAppsView extends RSSurfaceView + " item=" + item); } mIcons[index].uploadToTexture(0); + mLabels[index].uploadToTexture(0); } /** @@ -1142,13 +1206,21 @@ public class AllAppsView extends RSSurfaceView int[] iconIds = new int[count]; mAllocIconIds = Allocation.createSized(mRS, Element.USER_I32(mRS), count); + Allocation[] labels = new Allocation[count]; + int[] labelIds = new int[count]; + mAllocLabelIds = Allocation.createSized(mRS, Element.USER_I32(mRS), count); + final int oldCount = mRollo.mState.iconCount; System.arraycopy(mIcons, 0, icons, 0, oldCount); System.arraycopy(mIconIds, 0, iconIds, 0, oldCount); + System.arraycopy(mLabels, 0, labels, 0, oldCount); + System.arraycopy(mLabelIds, 0, labelIds, 0, oldCount); mIcons = icons; mIconIds = iconIds; + mLabels = labels; + mLabelIds = labelIds; } /** @@ -1160,15 +1232,11 @@ public class AllAppsView extends RSSurfaceView System.arraycopy(mIcons, index, mIcons, dest, count); System.arraycopy(mIconIds, index, mIconIds, dest, count); + System.arraycopy(mLabels, index, mLabels, dest, count); + System.arraycopy(mLabelIds, index, mLabelIds, dest, count); createAppIconAllocations(index, item); - - if (mHasSurface) { - uploadAppIcon(index, item); - } else { - mAppsDirty = true; - } - + uploadAppIcon(index, item); mRollo.mState.iconCount++; } @@ -1181,12 +1249,16 @@ public class AllAppsView extends RSSurfaceView System.arraycopy(mIcons, src, mIcons, index, count); System.arraycopy(mIconIds, src, mIconIds, index, count); + System.arraycopy(mLabels, src, mLabels, index, count); + System.arraycopy(mLabelIds, src, mLabelIds, index, count); mRollo.mState.iconCount--; final int last = mState.iconCount; mIcons[last] = null; mIconIds[last] = 0; + mLabels[last] = null; + mLabelIds[last] = 0; } /** @@ -1196,9 +1268,11 @@ public class AllAppsView extends RSSurfaceView mRS.contextBindRootScript(null); mAllocIconIds.data(mIconIds); + mAllocLabelIds.data(mLabelIds); if (mScript != null) { // this happens when we init it mScript.bindAllocation(mAllocIconIds, Defines.ALLOC_ICON_IDS); + mScript.bindAllocation(mAllocLabelIds, Defines.ALLOC_LABEL_IDS); } mState.save(); @@ -1208,7 +1282,9 @@ public class AllAppsView extends RSSurfaceView if (mInvokeResetWAR != null) { mInvokeResetWAR.execute(); } - mRS.contextBindRootScript(mScript); + if (mScript != null) { + mRS.contextBindRootScript(mScript); + } } void initTouchState() { @@ -1313,7 +1389,7 @@ public class AllAppsView extends RSSurfaceView ApplicationInfo info = mAllAppsList.get(index); Bitmap selectionBitmap = mSelectionBitmap; - Utilities.drawSelectedAllAppsBitmap(mSelectionCanvas, selectionBitmap, + Utilities.drawSelectedAllAppsBitmap(mSelectionCanvas, selectionBitmap.getWidth(), selectionBitmap.getHeight(), pressed == SELECTED_PRESSED, info.iconBitmap); @@ -1368,10 +1444,12 @@ public class AllAppsView extends RSSurfaceView Log.d(TAG, "mRollo.mIconIds.length=" + mIconIds.length); } Log.d(TAG, "mRollo.mIconIds=" + Arrays.toString(mIconIds)); + if (mLabelIds != null) { + Log.d(TAG, "mRollo.mLabelIds.length=" + mLabelIds.length); + } + Log.d(TAG, "mRollo.mLabelIds=" + Arrays.toString(mLabelIds)); Log.d(TAG, "mRollo.mTouchXBorders=" + Arrays.toString(mTouchXBorders)); Log.d(TAG, "mRollo.mTouchYBorders=" + Arrays.toString(mTouchYBorders)); - Log.d(TAG, "mRollo.mHasSurface=" + mHasSurface); - Log.d(TAG, "mRollo.mAppsDirty=" + mAppsDirty); Log.d(TAG, "mRollo.mState.newPositionX=" + mState.newPositionX); Log.d(TAG, "mRollo.mState.newTouchDown=" + mState.newTouchDown); Log.d(TAG, "mRollo.mState.flingVelocity=" + mState.flingVelocity); diff --git a/src/com/android/launcher2/AppInfoCache.java b/src/com/android/launcher2/AppInfoCache.java deleted file mode 100644 index e81168ede..000000000 --- a/src/com/android/launcher2/AppInfoCache.java +++ /dev/null @@ -1,180 +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<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, - 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; - } - - // TODO: turn this on in froyo, not enough time for testing in mr3 - //if (application.iconBitmap != null) { - // application.iconBitmap.recycle(); - //} - application.iconBitmap = Utilities.createAllAppsBitmap( - info.activityInfo.loadIcon(packageManager), - application.title.toString(), bubble, context); - } -} - diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java index ae0e219a0..f50b88930 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 { @@ -37,53 +38,47 @@ class ApplicationInfo extends ItemInfo { CharSequence title; /** - * The intent used to start the application. + * A bitmap of the application's text in the bubble. */ - Intent intent; + Bitmap titleBitmap; /** - * The application icon. + * The intent used to start the application. */ - Drawable icon; + Intent intent; /** - * What we show in all apps, including the text. + * 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; + + ApplicationInfo() { + itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT; + } /** - * If isShortcut=true and customIcon=false, this contains a reference to the - * shortcut icon as an application's resource. + * Must not hold the Context. */ - Intent.ShortcutIconResource iconResource; + public ApplicationInfo(ResolveInfo info, IconCache iconCache) { + this.componentName = new ComponentName( + info.activityInfo.applicationInfo.packageName, + info.activityInfo.name); - ApplicationInfo() { - itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT; + 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; } /** @@ -102,51 +97,20 @@ class ApplicationInfo extends ItemInfo { } @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<ApplicationInfo> list) { Log.d(tag, label + " size=" + list.size()); for (ApplicationInfo info: list) { - Log.d(tag, " title=\"" + info.title + "\" icon=" + info.icon - + " iconBitmap=" + info.iconBitmap + " filtered=" + info.filtered - + " customIcon=" + info.customIcon); + Log.d(tag, " title=\"" + info.title + "\" titleBitmap=" + info.titleBitmap + + " iconBitmap=" + info.iconBitmap); } } + + public ShortcutInfo makeShortcut() { + return new ShortcutInfo(this); + } } diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index 6970875ef..9bf9a465b 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -565,8 +565,11 @@ public class CellLayout extends ViewGroup { if (lp.dropped) { lp.dropped = false; + final int[] cellXY = mCellXY; + getLocationOnScreen(cellXY); mWallpaperManager.sendWallpaperCommand(getWindowToken(), "android.home.drop", - childLeft + lp.width / 2, childTop + lp.height / 2, 0, null); + cellXY[0] + childLeft + lp.width / 2, + cellXY[1] + childTop + lp.height / 2, 0, null); } } } diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java index ec4bc534c..fabeb4a3b 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/DragController.java b/src/com/android/launcher2/DragController.java index 590ca6927..daabbcc4c 100644 --- a/src/com/android/launcher2/DragController.java +++ b/src/com/android/launcher2/DragController.java @@ -18,25 +18,18 @@ package com.android.launcher2; import android.content.Context; import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.os.IBinder; import android.os.Handler; import android.os.Vibrator; -import android.os.SystemClock; -import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; -import android.view.ViewGroup; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; -import android.widget.FrameLayout; -import android.widget.ImageView; import java.util.ArrayList; @@ -44,6 +37,7 @@ import java.util.ArrayList; * Class for initiating a drag within a view or across multiple views. */ public class DragController { + @SuppressWarnings({"UnusedDeclaration"}) private static final String TAG = "Launcher.DragController"; /** Indicates the drag is a move. */ @@ -113,6 +107,8 @@ public class DragController { /** The view that will be scrolled when dragging to the left and right edges of the screen. */ private View mScrollView; + private View mMoveTarget; + private DragScroller mDragScroller; private int mScrollState = SCROLL_OUTSIDE_ZONE; private ScrollRunnable mScrollRunnable = new ScrollRunnable(); @@ -147,7 +143,6 @@ public class DragController { * Used to create a new DragLayer from XML. * * @param context The application's context. - * @param attrs The attribtues set containing the Workspace's customization values. */ public DragController(Context context) { mContext = context; @@ -159,7 +154,7 @@ public class DragController { * * @param v The view that is being dragged * @param source An object representing where the drag originated - * @param info The data associated with the object that is being dragged + * @param dragInfo The data associated with the object that is being dragged * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or * {@link #DRAG_ACTION_COPY} */ @@ -195,7 +190,7 @@ public class DragController { * @param textureWidth The width of the region inside b to use. * @param textureHeight The height of the region inside b to use. * @param source An object representing where the drag originated - * @param info The data associated with the object that is being dragged + * @param dragInfo The data associated with the object that is being dragged * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or * {@link #DRAG_ACTION_COPY} */ @@ -275,6 +270,7 @@ public class DragController { * || super.dispatchKeyEvent(event); * </pre> */ + @SuppressWarnings({"UnusedDeclaration"}) public boolean dispatchKeyEvent(KeyEvent event) { return mDragging; } @@ -343,6 +339,17 @@ public class DragController { } /** + * Sets the view that should handle move events. + */ + void setMoveTarget(View view) { + mMoveTarget = view; + } + + public boolean dispatchUnhandledMove(View focused, int direction) { + return mMoveTarget != null && mMoveTarget.dispatchUnhandledMove(focused, direction); + } + + /** * Call this from a drag source view. */ public boolean onTouchEvent(MotionEvent ev) { @@ -377,7 +384,7 @@ public class DragController { // Drop on someone? final int[] coordinates = mCoordinatesTemp; - DropTarget dropTarget = findDropTarget((int) screenX, (int) screenY, coordinates); + DropTarget dropTarget = findDropTarget(screenX, screenY, coordinates); if (dropTarget != null) { if (mLastDropTarget == dropTarget) { dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1], diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java index 7ae98917d..c68320764 100644 --- a/src/com/android/launcher2/DragLayer.java +++ b/src/com/android/launcher2/DragLayer.java @@ -18,9 +18,9 @@ package com.android.launcher2; import android.content.Context; import android.util.AttributeSet; -import android.util.Log; import android.view.MotionEvent; import android.view.KeyEvent; +import android.view.View; import android.widget.FrameLayout; /** @@ -57,4 +57,9 @@ public class DragLayer extends FrameLayout { public boolean onTouchEvent(MotionEvent ev) { return mDragController.onTouchEvent(ev); } + + @Override + public boolean dispatchUnhandledMove(View focused, int direction) { + return mDragController.dispatchUnhandledMove(focused, direction); + } } diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java index 7a86273e6..248712ed3 100644 --- a/src/com/android/launcher2/DragView.java +++ b/src/com/android/launcher2/DragView.java @@ -37,7 +37,7 @@ import android.view.WindowManagerImpl; public class DragView extends View implements TweenCallback { // Number of pixels to add to the dragged item for scaling. Should be even for pixel alignment. - private static final int DRAG_SCALE = 24; + private static final int DRAG_SCALE = 40; private Bitmap mBitmap; private Paint mPaint; diff --git a/src/com/android/launcher2/FastBitmapDrawable.java b/src/com/android/launcher2/FastBitmapDrawable.java index db2c01c4f..850535e67 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 4f66ad052..7c35f7997 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 85fc3a754..826336c9f 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 000000000..855d91431 --- /dev/null +++ b/src/com/android/launcher2/IconCache.java @@ -0,0 +1,140 @@ +/* + * 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<ComponentName, CacheEntry> mCache = + new HashMap<ComponentName, CacheEntry>(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); + if (entry.titleBitmap == null) { + entry.titleBitmap = mBubble.createTextBitmap(entry.title.toString()); + } + + 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(); + + mCache.put(componentName, entry); + + entry.title = info.loadLabel(mPackageManager).toString(); + if (entry.title == null) { + entry.title = info.activityInfo.name; + } + entry.icon = Utilities.createIconBitmap( + info.activityInfo.loadIcon(mPackageManager), mContext); + } + return entry; + } +} + diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java index 45ff24e17..9a2f73fcd 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 f04880ddd..ca2ea86c8 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 7a4e2bc2c..2a6fd56f5 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -19,7 +19,6 @@ package com.android.launcher2; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; -import android.app.ISearchManager; import android.app.SearchManager; import android.app.StatusBarManager; import android.app.WallpaperManager; @@ -43,16 +42,11 @@ import android.graphics.Rect; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.graphics.drawable.ColorDrawable; -import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Parcelable; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemProperties; -import android.provider.ContactsContract; import android.provider.LiveFolders; -import android.telephony.PhoneNumberUtils; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -67,6 +61,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.View.OnLongClickListener; +import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.TextView; @@ -99,6 +94,8 @@ public final class Launcher extends Activity private static final int WALLPAPER_SCREENS_SPAN = 2; private static final int MENU_GROUP_ADD = 1; + private static final int MENU_GROUP_WALLPAPER = MENU_GROUP_ADD + 1; + private static final int MENU_ADD = Menu.FIRST + 1; private static final int MENU_WALLPAPER_SETTINGS = MENU_ADD + 1; private static final int MENU_SEARCH = MENU_WALLPAPER_SETTINGS + 1; @@ -197,6 +194,7 @@ public final class Launcher extends Activity private Bundle mSavedInstanceState; private LauncherModel mModel; + private IconCache mIconCache; private ArrayList<ItemInfo> mDesktopItems = new ArrayList<ItemInfo>(); private static HashMap<Long, FolderInfo> mFolders = new HashMap<Long, FolderInfo>(); @@ -204,13 +202,13 @@ public final class Launcher extends Activity private ImageView mPreviousView; private ImageView mNextView; - private boolean mUtsTestMode; - @Override 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(); @@ -279,7 +277,7 @@ public final class Launcher extends Activity localeConfiguration.mnc = mnc; writeConfiguration(this, localeConfiguration); - AppInfoCache.flush(); + mIconCache.flush(); } } @@ -411,7 +409,6 @@ public final class Launcher extends Activity super.onResume(); mPaused = false; - mUtsTestMode = SystemProperties.getInt("persist.sys.uts-test-mode", 0) == 1; if (mRestoring) { mWorkspaceLoading = true; @@ -454,6 +451,27 @@ public final class Launcher extends Activity return null; } + // We can't hide the IME if it was forced open. So don't bother + /* + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + + if (hasFocus) { + final InputMethodManager inputManager = (InputMethodManager) + getSystemService(Context.INPUT_METHOD_SERVICE); + WindowManager.LayoutParams lp = getWindow().getAttributes(); + inputManager.hideSoftInputFromWindow(lp.token, 0, new android.os.ResultReceiver(new + android.os.Handler()) { + protected void onReceiveResult(int resultCode, Bundle resultData) { + Log.d(TAG, "ResultReceiver got resultCode=" + resultCode); + } + }); + Log.d(TAG, "called hideSoftInputFromWindow from onWindowFocusChanged"); + } + } + */ + private boolean acceptFilter() { final InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); @@ -462,10 +480,6 @@ public final class Launcher extends Activity @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (mUtsTestMode) { - return handleUtsTestModeKeyDown(keyCode, event); - } - boolean handled = super.onKeyDown(keyCode, event); if (!handled && acceptFilter() && keyCode != KeyEvent.KEYCODE_ENTER) { boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb, @@ -481,50 +495,9 @@ public final class Launcher extends Activity } } - return handled; - } - - public boolean handleUtsTestModeKeyDown(int keyCode, KeyEvent event) { - Log.d(TAG, "UTS-TEST-MODE"); - boolean handled = super.onKeyDown(keyCode, event); - if (!handled && acceptFilter() && keyCode != KeyEvent.KEYCODE_ENTER) { - boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb, - keyCode, event); - if (gotKey && mDefaultKeySsb != null && mDefaultKeySsb.length() > 0) { - // something usable has been typed - dispatch it now. - final String str = mDefaultKeySsb.toString(); - - boolean isDialable = true; - final int count = str.length(); - for (int i = 0; i < count; i++) { - if (!PhoneNumberUtils.isReallyDialable(str.charAt(i))) { - isDialable = false; - break; - } - } - Intent intent; - if (isDialable) { - intent = new Intent(Intent.ACTION_DIAL, Uri.fromParts("tel", str, null)); - } else { - intent = new Intent(ContactsContract.Intents.UI.FILTER_CONTACTS_ACTION); - intent.putExtra(ContactsContract.Intents.UI.FILTER_TEXT_EXTRA_KEY, str); - } - - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - - try { - startActivity(intent); - } catch (android.content.ActivityNotFoundException ex) { - // Oh well... no one knows how to filter/dial. Life goes on. - } - - mDefaultKeySsb.clear(); - mDefaultKeySsb.clearSpans(); - Selection.setSelection(mDefaultKeySsb, 0); - - return true; - } + // Eat the long press event so the keyboard doesn't come up. + if (keyCode == KeyEvent.KEYCODE_MENU && event.isLongPress()) { + return true; } return handled; @@ -603,6 +576,7 @@ public final class Launcher extends Activity mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace); final Workspace workspace = mWorkspace; + workspace.setHapticFeedbackEnabled(false); DeleteZone deleteZone = (DeleteZone) dragLayer.findViewById(R.id.delete_zone); mDeleteZone = deleteZone; @@ -610,6 +584,7 @@ public final class Launcher extends Activity mHandleView = (HandleView) findViewById(R.id.all_apps_button); mHandleView.setLauncher(this); mHandleView.setOnClickListener(this); + mHandleView.setOnLongClickListener(this); mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen); mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen); @@ -634,6 +609,7 @@ public final class Launcher extends Activity dragController.setDragScoller(workspace); dragController.setDragListener(deleteZone); dragController.setScrollView(dragLayer); + dragController.setMoveTarget(workspace); // The order here is bottom to top. dragController.addDropTarget(workspace); @@ -661,7 +637,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); } @@ -675,18 +651,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); @@ -704,39 +674,17 @@ public final class Launcher extends Activity cellInfo.screen = mWorkspace.getCurrentScreen(); if (!findSingleSlot(cellInfo)) return; - final ApplicationInfo info = infoFromApplicationIntent(context, data); - if (info != null) { - mWorkspace.addApplicationShortcut(info, cellInfo, isWorkspaceLocked()); - } - } + final ShortcutInfo info = mModel.getShortcutInfo(context.getPackageManager(), + data, context); - 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 | + if (info != null) { + 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; } /** @@ -749,7 +697,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); @@ -816,61 +764,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); - Bitmap bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON); - - Drawable icon = null; - boolean filtered = false; - boolean customIcon = false; - ShortcutIconResource iconResource = null; - - if (bitmap != null) { - icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail(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(); @@ -987,7 +880,6 @@ public final class Launcher extends Activity mModel.stopLoader(); unbindDesktopItems(); - AppInfoCache.unbindDrawables(); getContentResolver().unregisterContentObserver(mWidgetObserver); @@ -1079,10 +971,11 @@ public final class Launcher extends Activity } super.onCreateOptionsMenu(menu); + menu.add(MENU_GROUP_ADD, MENU_ADD, 0, R.string.menu_add) .setIcon(android.R.drawable.ic_menu_add) .setAlphabeticShortcut('A'); - menu.add(0, MENU_WALLPAPER_SETTINGS, 0, R.string.menu_wallpaper) + menu.add(MENU_GROUP_WALLPAPER, MENU_WALLPAPER_SETTINGS, 0, R.string.menu_wallpaper) .setIcon(android.R.drawable.ic_menu_gallery) .setAlphabeticShortcut('W'); menu.add(0, MENU_SEARCH, 0, R.string.menu_search) @@ -1107,8 +1000,22 @@ public final class Launcher extends Activity public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - mMenuAddInfo = mWorkspace.findAllVacantCells(null); - menu.setGroupEnabled(MENU_GROUP_ADD, mMenuAddInfo != null && mMenuAddInfo.valid); + // If all apps is animating, don't show the menu, because we don't know + // which one to show. + if (mAllAppsGrid.isVisible() && !mAllAppsGrid.isOpaque()) { + return false; + } + + // Only show the add and wallpaper options when we're not in all apps. + boolean visible = !mAllAppsGrid.isOpaque(); + menu.setGroupVisible(MENU_GROUP_ADD, visible); + menu.setGroupVisible(MENU_GROUP_WALLPAPER, visible); + + // Disable add if the workspace is full. + if (visible) { + mMenuAddInfo = mWorkspace.findAllVacantCells(null); + menu.setGroupEnabled(MENU_GROUP_ADD, mMenuAddInfo != null && mMenuAddInfo.valid); + } return true; } @@ -1276,7 +1183,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); @@ -1298,8 +1204,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(); @@ -1451,9 +1356,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( @@ -1542,14 +1447,21 @@ public final class Launcher extends Activity if (!isAllAppsVisible()) { mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - showPreviousPreview(v); + showPreviews(v); } return true; case R.id.next_screen: if (!isAllAppsVisible()) { mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - showNextPreview(v); + showPreviews(v); + } + return true; + case R.id.all_apps_button: + if (!isAllAppsVisible()) { + mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + showPreviews(v); } return true; } @@ -1574,6 +1486,8 @@ public final class Launcher extends Activity if (cellInfo.valid) { // User long pressed on empty space mWorkspace.setAllowLongPress(false); + mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); showAddDialog(cellInfo); } } else { @@ -1612,29 +1526,19 @@ public final class Launcher extends Activity v.setTag(null); } - private void showPreviousPreview(View anchor) { - int current = mWorkspace.getCurrentScreen(); - if (current <= 0) return; - + private void showPreviews(View anchor) { showPreviews(anchor, 0, mWorkspace.getChildCount()); } - private void showNextPreview(View anchor) { - int current = mWorkspace.getCurrentScreen(); - if (current >= mWorkspace.getChildCount() - 1) return; - - showPreviews(anchor, 0, mWorkspace.getChildCount()); - } - private void showPreviews(final View anchor, int start, int end) { - Resources resources = getResources(); + final Resources resources = getResources(); + final Workspace workspace = mWorkspace; - Workspace workspace = mWorkspace; CellLayout cell = ((CellLayout) workspace.getChildAt(start)); float max = workspace.getChildCount(); - Rect r = new Rect(); + final Rect r = new Rect(); resources.getDrawable(R.drawable.preview_background).getPadding(r); int extraW = (int) ((r.left + r.right) * max); int extraH = r.top + r.bottom; @@ -1665,10 +1569,10 @@ public final class Launcher extends Activity ImageView image = new ImageView(this); cell = (CellLayout) workspace.getChildAt(i); - Bitmap bitmap = Bitmap.createBitmap((int) sWidth, (int) sHeight, + final Bitmap bitmap = Bitmap.createBitmap((int) sWidth, (int) sHeight, Bitmap.Config.ARGB_8888); - - Canvas c = new Canvas(bitmap); + + final Canvas c = new Canvas(bitmap); c.scale(scale, scale); c.translate(-cell.getLeftPadding(), -cell.getTopPadding()); cell.dispatchDraw(c); @@ -1686,8 +1590,8 @@ public final class Launcher extends Activity bitmaps.add(bitmap); } - - PopupWindow p = new PopupWindow(this); + + final PopupWindow p = new PopupWindow(this); p.setContentView(preview); p.setWidth((int) (sWidth * count + extraW)); p.setHeight((int) (sHeight + extraH)); @@ -1731,10 +1635,6 @@ public final class Launcher extends Activity } } - View getDrawerHandle() { - return mHandleView; - } - Workspace getWorkspace() { return mWorkspace; } @@ -1885,22 +1785,14 @@ public final class Launcher extends Activity return mAllAppsGrid.isVisible(); } - boolean isAllAppsOpaque() { - return mAllAppsGrid.isOpaque(); - } - void showAllApps(boolean animated) { mAllAppsGrid.zoom(1.0f, animated); - //mWorkspace.hide(); - - mWorkspace.startFading(false); mAllAppsGrid.setFocusable(true); mAllAppsGrid.requestFocus(); // TODO: fade these two too mDeleteZone.setVisibility(View.GONE); - //mHandleView.setVisibility(View.GONE); } /** @@ -1943,13 +1835,6 @@ public final class Launcher extends Activity mAllAppsGrid.zoom(0.0f, animated); mAllAppsGrid.setFocusable(false); mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus(); - mWorkspace.startFading(true); - - // TODO: fade these two too - /* - mDeleteZone.setVisibility(View.VISIBLE); - mHandleView.setVisibility(View.VISIBLE); - */ } } @@ -2162,7 +2047,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; @@ -2304,7 +2189,7 @@ public final class Launcher extends Activity */ public void bindPackageRemoved(String packageName, ArrayList<ApplicationInfo> apps) { removeDialog(DIALOG_CREATE_SHORTCUT); - mWorkspace.removeShortcutsForPackage(packageName); + mWorkspace.removeItemsForPackage(packageName); mAllAppsGrid.removeApps(apps); } diff --git a/src/com/android/launcher2/LauncherAppWidgetInfo.java b/src/com/android/launcher2/LauncherAppWidgetInfo.java index 25db72bed..a28973bc4 100644 --- a/src/com/android/launcher2/LauncherAppWidgetInfo.java +++ b/src/com/android/launcher2/LauncherAppWidgetInfo.java @@ -25,7 +25,8 @@ import android.content.ContentValues; class LauncherAppWidgetInfo extends ItemInfo { /** - * Identifier for this widget when talking with {@link AppWidgetManager} for updates. + * Identifier for this widget when talking with + * {@link android.appwidget.AppWidgetManager} for updates. */ int appWidgetId; diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java index 9b6352433..183dbf571 100644 --- a/src/com/android/launcher2/LauncherApplication.java +++ b/src/com/android/launcher2/LauncherApplication.java @@ -18,7 +18,6 @@ package com.android.launcher2; import android.app.Application; import android.content.ContentResolver; -import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; @@ -26,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() { @@ -38,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); @@ -80,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 97fa554c2..43daa9c0e 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -16,20 +16,27 @@ package com.android.launcher2; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; +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; +import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.res.Resources; 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; import android.os.SystemClock; @@ -60,7 +67,10 @@ public class LauncherModel extends BroadcastReceiver { private boolean mBeforeFirstLoad = true; private WeakReference<Callbacks> mCallbacks; - private AllAppsList mAllAppsList = new AllAppsList(); + private AllAppsList mAllAppsList; + private IconCache mIconCache; + + private Bitmap mDefaultIcon; public interface Callbacks { public int getCurrentWorkspaceScreen(); @@ -75,8 +85,17 @@ public class LauncherModel extends BroadcastReceiver { public void bindPackageRemoved(String packageName, ArrayList<ApplicationInfo> 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); } /** @@ -318,7 +337,7 @@ public class LauncherModel extends BroadcastReceiver { removed = mAllAppsList.removed; mAllAppsList.removed = new ArrayList<ApplicationInfo>(); for (ApplicationInfo info: removed) { - AppInfoCache.remove(info.intent.getComponent()); + mIconCache.remove(info.intent.getComponent()); } } if (mAllAppsList.modified.size() > 0) { @@ -602,6 +621,8 @@ public class LauncherModel extends BroadcastReceiver { final Context context = mContext; final ContentResolver contentResolver = context.getContentResolver(); final PackageManager manager = context.getPackageManager(); + final AppWidgetManager widgets = AppWidgetManager.getInstance(context); + final boolean isSafeMode = manager.isSafeMode(); /* TODO if (mLocaleChanged) { @@ -613,6 +634,8 @@ public class LauncherModel extends BroadcastReceiver { mAppWidgets.clear(); mFolders.clear(); + final ArrayList<Long> itemsToRemove = new ArrayList<Long>(); + final Cursor c = contentResolver.query( LauncherSettings.Favorites.CONTENT_URI, null, null, null, null); @@ -649,7 +672,7 @@ public class LauncherModel extends BroadcastReceiver { final int displayModeIndex = c.getColumnIndexOrThrow( LauncherSettings.Favorites.DISPLAY_MODE); - ApplicationInfo info; + ShortcutInfo info; String intentDescription; Widget widgetInfo; LauncherAppWidgetInfo appWidgetInfo; @@ -672,15 +695,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) { @@ -734,40 +757,50 @@ public class LauncherModel extends BroadcastReceiver { break; case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: - id = c.getLong(idIndex); - LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(mFolders, id); + Uri uri = Uri.parse(c.getString(uriIndex)); - 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 - } - } - - 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(context, c, iconTypeIndex, iconPackageIndex, - iconResourceIndex, liveFolderInfo); + // Make sure the live folder exists + final ProviderInfo providerInfo = + context.getPackageManager().resolveContentProvider( + uri.getAuthority(), 0); - switch (container) { - case LauncherSettings.Favorites.CONTAINER_DESKTOP: - mItems.add(liveFolderInfo); - break; + if (providerInfo == null && !isSafeMode) { + itemsToRemove.add(id); + } else { + LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(mFolders, 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 + } + } + + liveFolderInfo.title = c.getString(titleIndex); + liveFolderInfo.id = id; + liveFolderInfo.uri = uri; + container = c.getInt(containerIndex); + liveFolderInfo.container = container; + liveFolderInfo.screen = c.getInt(screenIndex); + liveFolderInfo.cellX = c.getInt(cellXIndex); + liveFolderInfo.cellY = c.getInt(cellYIndex); + liveFolderInfo.baseIntent = intent; + liveFolderInfo.displayMode = c.getInt(displayModeIndex); + + loadLiveFolderIcon(context, c, iconTypeIndex, iconPackageIndex, + iconResourceIndex, liveFolderInfo); + + switch (container) { + case LauncherSettings.Favorites.CONTAINER_DESKTOP: + mItems.add(liveFolderInfo); + break; + } + mFolders.put(liveFolderInfo.id, liveFolderInfo); } - mFolders.put(liveFolderInfo.id, liveFolderInfo); break; case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH: @@ -792,23 +825,33 @@ public class LauncherModel extends BroadcastReceiver { 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); + id = c.getLong(idIndex); - container = c.getInt(containerIndex); - if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { - Log.e(TAG, "Widget found where container " - + "!= CONTAINER_DESKTOP -- ignoring!"); - continue; + final AppWidgetProviderInfo provider = + widgets.getAppWidgetInfo(appWidgetId); + + if (!isSafeMode && (provider == null || provider.provider == null || + provider.provider.getPackageName() == null)) { + itemsToRemove.add(id); + } else { + appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId); + appWidgetInfo.id = id; + appWidgetInfo.screen = c.getInt(screenIndex); + appWidgetInfo.cellX = c.getInt(cellXIndex); + appWidgetInfo.cellY = c.getInt(cellYIndex); + appWidgetInfo.spanX = c.getInt(spanXIndex); + appWidgetInfo.spanY = c.getInt(spanYIndex); + + 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); + + mAppWidgets.add(appWidgetInfo); } - appWidgetInfo.container = c.getInt(containerIndex); - - mAppWidgets.add(appWidgetInfo); break; } } catch (Exception e) { @@ -818,6 +861,25 @@ public class LauncherModel extends BroadcastReceiver { } finally { c.close(); } + + if (itemsToRemove.size() > 0) { + ContentProviderClient client = contentResolver.acquireContentProviderClient( + LauncherSettings.Favorites.CONTENT_URI); + // Remove dead items + for (long id : itemsToRemove) { + if (DEBUG_LOADERS) { + Log.d(TAG, "Removed id = " + id); + } + // Don't notify content observers + try { + client.delete(LauncherSettings.Favorites.getContentUri(id, false), + null, null); + } catch (RemoteException e) { + Log.w(TAG, "Could not remove id = " + id); + } + } + } + if (DEBUG_LOADERS) { Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms"); } @@ -945,9 +1007,7 @@ public class LauncherModel extends BroadcastReceiver { return; } - final Context context = mContext; - final PackageManager packageManager = context.getPackageManager(); - + final PackageManager packageManager = mContext.getPackageManager(); final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0); synchronized (mLock) { @@ -958,10 +1018,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<N && !mStopped; i++) { // This builds the icon bitmaps. - mAllAppsList.add(AppInfoCache.cache(apps.get(i), context, bubble)); + mAllAppsList.add(new ApplicationInfo(apps.get(i), mIconCache)); } Collections.sort(mAllAppsList.data, APP_NAME_COMPARATOR); Collections.sort(mAllAppsList.added, APP_NAME_COMPARATOR); @@ -976,7 +1035,7 @@ public class LauncherModel extends BroadcastReceiver { private void bindAllApps() { synchronized (mLock) { final ArrayList<ApplicationInfo> results - = (ArrayList<ApplicationInfo>)mAllAppsList.data.clone(); + = (ArrayList<ApplicationInfo>) mAllAppsList.data.clone(); // We're adding this now, so clear out this so we don't re-send them. mAllAppsList.added = new ArrayList<ApplicationInfo>(); mHandler.post(new Runnable() { @@ -991,7 +1050,7 @@ public class LauncherModel extends BroadcastReceiver { if (DEBUG_LOADERS) { Log.d(TAG, "bound app " + count + " icons in " - + (SystemClock.uptimeMillis()-t) + "ms"); + + (SystemClock.uptimeMillis() - t) + "ms"); } } }); @@ -1022,9 +1081,9 @@ public class LauncherModel extends BroadcastReceiver { } /** - * Make an ApplicationInfo object for an application. + * Make an ShortcutInfo object for a sortcut that is an application. */ - private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent, + public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) { final ResolveInfo resolveInfo = manager.resolveActivity(intent, 0); @@ -1032,26 +1091,26 @@ public class LauncherModel extends BroadcastReceiver { return null; } - final ApplicationInfo info = new ApplicationInfo(); + final ShortcutInfo info = new ShortcutInfo(); final ActivityInfo activityInfo = resolveInfo.activityInfo; - info.icon = Utilities.createIconThumbnail(activityInfo.loadIcon(manager), context); + info.setIcon(mIconCache.getIcon(intent.getComponent(), resolveInfo)); if (info.title == null || info.title.length() == 0) { info.title = activityInfo.loadLabel(manager); } if (info.title == null) { - info.title = ""; + info.title = activityInfo.name; } info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; return info; } /** - * Make an ApplicationInfo object for a sortcut + * Make an ShortcutInfo object for a shortcut that isn't an application. */ - private static ApplicationInfo getApplicationInfoShortcut(Cursor c, Context context, + private ShortcutInfo getShortcutInfo(Cursor c, Context context, int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) { - final ApplicationInfo info = new ApplicationInfo(); + final ShortcutInfo info = new ShortcutInfo(); info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; int iconType = c.getInt(iconTypeIndex); @@ -1063,9 +1122,9 @@ public class LauncherModel extends BroadcastReceiver { try { Resources resources = packageManager.getResourcesForApplication(packageName); final int id = resources.getIdentifier(resourceName, null, null); - info.icon = Utilities.createIconThumbnail(resources.getDrawable(id), context); + info.setIcon(Utilities.createIconBitmap(resources.getDrawable(id), context)); } catch (Exception e) { - info.icon = packageManager.getDefaultActivityIcon(); + info.setIcon(getDefaultIcon()); } info.iconResource = new Intent.ShortcutIconResource(); info.iconResource.packageName = packageName; @@ -1076,23 +1135,74 @@ public class LauncherModel extends BroadcastReceiver { byte[] data = c.getBlob(iconIndex); try { Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); - info.icon = new FastBitmapDrawable( - Utilities.createBitmapThumbnail(bitmap, context)); + info.setIcon(bitmap); } catch (Exception e) { - packageManager = context.getPackageManager(); - info.icon = packageManager.getDefaultActivityIcon(); + info.setIcon(getDefaultIcon()); } - info.filtered = true; info.customIcon = true; break; default: - info.icon = context.getPackageManager().getDefaultActivityIcon(); + info.setIcon(getDefaultIcon()); info.customIcon = false; break; } return info; } + ShortcutInfo addShortcut(Context context, Intent data, + CellLayout.CellInfo cellInfo, boolean notify) { + + final ShortcutInfo info = infoFromShortcutIntent(context, data); + addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, + cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify); + + return info; + } + + private ShortcutInfo 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); + + Bitmap icon = null; + boolean filtered = false; + boolean customIcon = false; + ShortcutIconResource iconResource = null; + + if (bitmap != null && bitmap instanceof Bitmap) { + icon = Utilities.createIconBitmap(new FastBitmapDrawable((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 = Utilities.createIconBitmap(resources.getDrawable(id), context); + } catch (Exception e) { + Log.w(TAG, "Could not load shortcut icon: " + extra); + } + } + } + + if (icon == null) { + icon = getDefaultIcon(); + } + + final ShortcutInfo info = new ShortcutInfo(); + info.setIcon(icon); + info.title = name; + info.intent = intent; + info.customIcon = customIcon; + info.iconResource = iconResource; + + return info; + } + private static void loadLiveFolderIcon(Context context, Cursor c, int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) { @@ -1105,18 +1215,21 @@ public class LauncherModel extends BroadcastReceiver { try { Resources resources = packageManager.getResourcesForApplication(packageName); final int id = resources.getIdentifier(resourceName, null, null); - liveFolderInfo.icon = resources.getDrawable(id); + liveFolderInfo.icon = Utilities.createIconBitmap(resources.getDrawable(id), + context); } catch (Exception e) { - liveFolderInfo.icon = - context.getResources().getDrawable(R.drawable.ic_launcher_folder); + liveFolderInfo.icon = Utilities.createIconBitmap( + context.getResources().getDrawable(R.drawable.ic_launcher_folder), + context); } 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); + liveFolderInfo.icon = Utilities.createIconBitmap( + context.getResources().getDrawable(R.drawable.ic_launcher_folder), + context); } } diff --git a/src/com/android/launcher2/LauncherProvider.java b/src/com/android/launcher2/LauncherProvider.java index c3ceefdd3..62c19df9f 100644 --- a/src/com/android/launcher2/LauncherProvider.java +++ b/src/com/android/launcher2/LauncherProvider.java @@ -32,9 +32,12 @@ import android.content.pm.PackageManager; import android.content.pm.ActivityInfo; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; import android.database.sqlite.SQLiteQueryBuilder; import android.database.Cursor; import android.database.SQLException; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.util.Log; import android.util.Xml; import android.util.AttributeSet; @@ -58,7 +61,7 @@ public class LauncherProvider extends ContentProvider { private static final String DATABASE_NAME = "launcher.db"; - private static final int DATABASE_VERSION = 6; + private static final int DATABASE_VERSION = 8; static final String AUTHORITY = "com.android.launcher2.settings"; @@ -382,7 +385,15 @@ public class LauncherProvider extends ContentProvider { version = 6; } } - + + if (version < 8) { + // Version 8 (froyo) has the icons all normalized. This should + // already be the case in practice, but we now rely on it and don't + // resample the images each time. + normalizeIcons(db); + version = 8; + } + if (version != DATABASE_VERSION) { Log.w(TAG, "Destroying all old data."); db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES); @@ -457,10 +468,64 @@ public class LauncherProvider extends ContentProvider { return true; } + private void normalizeIcons(SQLiteDatabase db) { + Log.d(TAG, "normalizing icons"); + + db.beginTransaction(); + Cursor c = null; + try { + boolean logged = false; + final ContentValues values = new ContentValues(); + final ContentResolver cr = mContext.getContentResolver(); + final SQLiteStatement update = db.compileStatement("UPDATE favorites " + + "SET icon=? WHERE _id=?"); + + c = db.rawQuery("SELECT _id, icon FROM favorites WHERE iconType=" + + Favorites.ICON_TYPE_BITMAP, null); + + final int idIndex = c.getColumnIndexOrThrow(Favorites._ID); + final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON); + + while (c.moveToNext()) { + long id = c.getLong(idIndex); + byte[] data = c.getBlob(iconIndex); + try { + Bitmap bitmap = Utilities.resampleIconBitmap( + BitmapFactory.decodeByteArray(data, 0, data.length), + mContext); + if (bitmap != null) { + update.bindLong(1, id); + data = ItemInfo.flattenBitmap(bitmap); + if (data != null) { + update.bindBlob(2, data); + update.execute(); + } + bitmap.recycle(); + bitmap = null; + } + } catch (Exception e) { + if (!logged) { + Log.e(TAG, "Failed normalizing icon " + id, e); + } else { + Log.e(TAG, "Also failed normalizing icon " + id); + } + logged = true; + } + } + } catch (SQLException ex) { + Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex); + } finally { + db.endTransaction(); + if (c != null) { + c.close(); + } + } + + } + /** * Upgrade existing clock and photo frame widgets into their new widget - * equivalents. This method allocates appWidgetIds, and then hands off to - * LauncherAppWidgetBinder to finish the actual binding. + * equivalents. */ private void convertWidgets(SQLiteDatabase db) { final int[] bindSources = new int[] { diff --git a/src/com/android/launcher2/LauncherSettings.java b/src/com/android/launcher2/LauncherSettings.java index a438d47cb..9c685ceaa 100644 --- a/src/com/android/launcher2/LauncherSettings.java +++ b/src/com/android/launcher2/LauncherSettings.java @@ -91,8 +91,7 @@ class LauncherSettings { } /** - * Favorites. When changing these values, be sure to update - * {@link com.android.settings.LauncherAppWidgetBinder} as needed. + * Favorites. */ static final class Favorites implements BaseLauncherColumns { /** diff --git a/src/com/android/launcher2/LiveFolderAdapter.java b/src/com/android/launcher2/LiveFolderAdapter.java index b0e9eff1f..58b43e33a 100644 --- a/src/com/android/launcher2/LiveFolderAdapter.java +++ b/src/com/android/launcher2/LiveFolderAdapter.java @@ -141,7 +141,12 @@ class LiveFolderAdapter extends CursorAdapter { if (icon == null) { final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); - icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail(bitmap, mContext)); + final Bitmap resampled = Utilities.resampleIconBitmap(bitmap, mContext); + if (bitmap != resampled) { + // If we got back a different object, we don't need the old one any more. + bitmap.recycle(); + } + icon = new FastBitmapDrawable(resampled); mCustomIcons.put(holder.id, new SoftReference<Drawable>(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 55f100cce..f80928bd4 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 5b1217c15..7d0a0f58f 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 000000000..cb73ac05b --- /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<ShortcutInfo> 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 index 129103af0..212b5d62d 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<ApplicationInfo> { +public class ShortcutsAdapter extends ArrayAdapter<ShortcutInfo> { private final LayoutInflater mInflater; private final PackageManager mPackageManager; + private final IconCache mIconCache; - public ApplicationsAdapter(Context context, ArrayList<ApplicationInfo> apps) { + public ShortcutsAdapter(Context context, ArrayList<ShortcutInfo> 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 16fe6160c..148949217 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<ApplicationInfo>) 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<ApplicationInfo> adapter = - (ArrayAdapter<ApplicationInfo>) 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 75b19eec6..0b8841c10 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<ApplicationInfo> contents = new ArrayList<ApplicationInfo>(); + ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>(); 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 2dfba4317..fbe489ec5 100644 --- a/src/com/android/launcher2/Utilities.java +++ b/src/com/android/launcher2/Utilities.java @@ -22,7 +22,6 @@ import android.graphics.drawable.PaintDrawable; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; -import android.graphics.MaskFilter; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.graphics.PixelFormat; @@ -52,15 +51,10 @@ final class Utilities { private static int sIconTextureWidth = -1; private static int sIconTextureHeight = -1; - private static int sTitleMargin = -1; - private static float sBlurRadius = -1; - private static Rect sIconTextureRect; - private static final Paint sPaint = new Paint(); private static final Paint sBlurPaint = new Paint(); private static final Paint sGlowColorPressedPaint = new Paint(); private static final Paint sGlowColorFocusedPaint = new Paint(); - private static final Paint sEmptyPaint = new Paint(); private static final Rect sBounds = new Rect(); private static final Rect sOldBounds = new Rect(); private static final Canvas sCanvas = new Canvas(); @@ -91,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; @@ -179,8 +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, String title, BubbleText bubble, - Context context) { + static Bitmap createIconBitmap(Drawable icon, Context context) { synchronized (sCanvas) { // we share the statics :-( if (sIconWidth == -1) { initStatics(context); @@ -222,8 +134,8 @@ final class Utilities { } // no intrinsic size --> use default size - final int textureWidth = sIconTextureWidth; - final int textureHeight = sIconTextureHeight; + int textureWidth = sIconTextureWidth; + int textureHeight = sIconTextureHeight; final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight, Bitmap.Config.ARGB_8888); @@ -231,7 +143,7 @@ final class Utilities { canvas.setBitmap(bitmap); final int left = (textureWidth-width) / 2; - final int top = sIconTextureRect.top; + final int top = (textureHeight-height) / 2; if (false) { // draw a big box for the icon for debugging @@ -247,34 +159,12 @@ final class Utilities { icon.draw(canvas); icon.setBounds(sOldBounds); - if (title != null) { - bubble.drawText(canvas, title); - } - return bitmap; } } - static Bitmap extractIconFromTexture(Bitmap src, Context context) { - synchronized (sCanvas) { // we share the statics :-( - if (sIconWidth == -1) { - initStatics(context); - } - final Bitmap bitmap = Bitmap.createBitmap(sIconWidth, sIconHeight, - Bitmap.Config.ARGB_8888); - final Canvas canvas = sCanvas; - canvas.setBitmap(bitmap); - - Rect r = new Rect(0, 0, sIconWidth, sIconHeight); - canvas.drawColor(0, PorterDuff.Mode.CLEAR); - canvas.drawBitmap(src, sIconTextureRect, r, sEmptyPaint); - - return bitmap; - } - } - - static void drawSelectedAllAppsBitmap(Canvas dest, Bitmap destBitmap, - int destWidth, int destHeight, boolean pressed, Bitmap src) { + static void drawSelectedAllAppsBitmap(Canvas dest, int destWidth, int destHeight, + boolean pressed, Bitmap src) { synchronized (sCanvas) { // we share the statics :-( if (sIconWidth == -1) { // We can't have gotten to here without src being initialized, which @@ -284,14 +174,12 @@ final class Utilities { } dest.drawColor(0, PorterDuff.Mode.CLEAR); - dest.drawBitmap(src, sIconTextureRect, sIconTextureRect, sEmptyPaint); int[] xy = new int[2]; - Bitmap mask = destBitmap.extractAlpha(sBlurPaint, xy); + Bitmap mask = src.extractAlpha(sBlurPaint, xy); float px = (destWidth - src.getWidth()) / 2; float py = (destHeight - src.getHeight()) / 2; - dest.drawColor(0, PorterDuff.Mode.CLEAR); dest.drawBitmap(mask, px + xy[0], py + xy[1], pressed ? sGlowColorPressedPaint : sGlowColorFocusedPaint); @@ -310,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; } } @@ -368,13 +218,7 @@ final class Utilities { final float density = metrics.density; sIconWidth = sIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size); - sIconTextureWidth = sIconTextureHeight = roundToPow2(sIconWidth); - - sTitleMargin = (int)(1 * density); - sBlurRadius = 5 * density; - final int left = (sIconTextureWidth-sIconWidth)/2; - final int top = (int)(sBlurRadius) + 1; - sIconTextureRect = new Rect(left, top, left+sIconWidth, top+sIconHeight); + sIconTextureWidth = sIconTextureHeight = sIconWidth + 2; sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL)); sGlowColorPressedPaint.setColor(0xffffc300); @@ -385,79 +229,75 @@ final class Utilities { static class BubbleText { private static final int MAX_LINES = 2; - private TextPaint mTextPaint; - private float mBubblePadding; - private RectF mBubbleRect = new RectF(); + private final TextPaint mTextPaint; - private float mTextWidth; - private int mLeading; - private int mFirstLineY; - private int mLineHeight; + private final float mBubblePadding; + private final RectF mBubbleRect = new RectF(); - private int mBitmapWidth; - private int mBitmapHeight; + private final float mTextWidth; + private final int mLeading; + private final int mFirstLineY; + private final int mLineHeight; - BubbleText(Context context) { - synchronized (sCanvas) { // we share the statics :-( - if (sIconWidth == -1) { - initStatics(context); - } - final Resources resources = context.getResources(); - - final float scale = resources.getDisplayMetrics().density; - - final float paddingLeft = 5.0f * scale; - final float paddingRight = 5.0f * scale; - final float cellWidth = resources.getDimension(R.dimen.workspace_cell_width); - final float bubbleWidth = cellWidth - paddingLeft - paddingRight; - mBubblePadding = 3.0f * scale; - - RectF bubbleRect = mBubbleRect; - bubbleRect.left = 0; - bubbleRect.top = 0; - bubbleRect.right = (int)(bubbleWidth+0.5f); - - mTextWidth = bubbleWidth - mBubblePadding - mBubblePadding; - - Paint rectPaint = new Paint(); - rectPaint.setColor(0xff000000); - rectPaint.setAntiAlias(true); - - TextPaint textPaint = mTextPaint = new TextPaint(); - textPaint.setTypeface(Typeface.DEFAULT); - textPaint.setTextSize(13*scale); - //textPaint.setColor(0xff00ff00); - textPaint.setColor(0xffffffff); - textPaint.setAntiAlias(true); - if (TEXT_BURN) { - textPaint.setShadowLayer(8, 0, 0, 0xff000000); - } + private final int mBitmapWidth; + private final int mBitmapHeight; + private final int mDensity; - final int iconTop = (int)(sBlurRadius) + 1; - final int iconBottom = iconTop + sIconHeight; + BubbleText(Context context) { + final Resources resources = context.getResources(); + + final DisplayMetrics metrics = resources.getDisplayMetrics(); + final float scale = metrics.density; + mDensity = metrics.densityDpi; + + final float paddingLeft = 5.0f * scale; + final float paddingRight = 5.0f * scale; + final float cellWidth = resources.getDimension(R.dimen.title_texture_width); + final float bubbleWidth = cellWidth - paddingLeft - paddingRight; + mBubblePadding = 3.0f * scale; + + RectF bubbleRect = mBubbleRect; + bubbleRect.left = 0; + bubbleRect.top = 0; + bubbleRect.right = (int) cellWidth; + + mTextWidth = bubbleWidth - mBubblePadding - mBubblePadding; + + TextPaint textPaint = mTextPaint = new TextPaint(); + textPaint.setTypeface(Typeface.DEFAULT); + textPaint.setTextSize(13*scale); + textPaint.setColor(0xffffffff); + textPaint.setAntiAlias(true); + if (TEXT_BURN) { + textPaint.setShadowLayer(8, 0, 0, 0xff000000); + } - float ascent = -textPaint.ascent(); - float descent = textPaint.descent(); - float leading = -1.0f;//(ascent+descent) * 0.1f; - mLeading = (int)(leading + 0.5f); - mFirstLineY = (int)(iconBottom + sTitleMargin + ascent + 0.5f); - mLineHeight = (int)(leading + ascent + descent + 0.5f); + float ascent = -textPaint.ascent(); + float descent = textPaint.descent(); + float leading = 0.0f;//(ascent+descent) * 0.1f; + mLeading = (int)(leading + 0.5f); + mFirstLineY = (int)(leading + ascent + 0.5f); + mLineHeight = (int)(leading + ascent + descent + 0.5f); - mBitmapWidth = roundToPow2((int)(mBubbleRect.width() + 0.5f)); - mBitmapHeight = roundToPow2((int)((MAX_LINES * mLineHeight) + leading + 0.5f)); + mBitmapWidth = (int)(mBubbleRect.width() + 0.5f); + mBitmapHeight = roundToPow2((int)((MAX_LINES * mLineHeight) + leading + 0.5f)); - mBubbleRect.offsetTo((mBitmapWidth-mBubbleRect.width())/2, 0); + mBubbleRect.offsetTo((mBitmapWidth-mBubbleRect.width())/2, 0); - if (false) { - Log.d(TAG, "mBitmapWidth=" + mBitmapWidth + " mBitmapHeight=" - + mBitmapHeight + " w=" + ((int)(mBubbleRect.width() + 0.5f)) - + " h=" + ((int)((MAX_LINES * mLineHeight) + leading + 0.5f))); - } + if (false) { + Log.d(TAG, "mBitmapWidth=" + mBitmapWidth + " mBitmapHeight=" + + mBitmapHeight + " w=" + ((int)(mBubbleRect.width() + 0.5f)) + + " h=" + ((int)((MAX_LINES * mLineHeight) + leading + 0.5f))); } } - void drawText(Canvas c, String text) { + /** You own the bitmap after this and you must call recycle on it. */ + Bitmap createTextBitmap(String text) { + Bitmap b = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ALPHA_8); + b.setDensity(mDensity); + Canvas c = new Canvas(b); + StaticLayout layout = new StaticLayout(text, mTextPaint, (int)mTextWidth, Alignment.ALIGN_CENTER, 1, 0, true); int lineCount = layout.getLineCount(); @@ -472,12 +312,14 @@ final class Utilities { for (int i=0; i<lineCount; i++) { //int x = (int)((mBubbleRect.width() - layout.getLineMax(i)) / 2.0f); //int y = mFirstLineY + (i * mLineHeight); + final String lineText = text.substring(layout.getLineStart(i), layout.getLineEnd(i)); int x = (int)(mBubbleRect.left - + ((mBubbleRect.width() - layout.getLineMax(i)) / 2.0f)); + + ((mBubbleRect.width() - mTextPaint.measureText(lineText)) * 0.5f)); int y = mFirstLineY + (i * mLineHeight); - c.drawText(text.substring(layout.getLineStart(i), layout.getLineEnd(i)), - x, y, mTextPaint); + c.drawText(lineText, x, y, mTextPaint); } + + return b; } private int height(int lineCount) { diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 9e32dd563..b93965b1c 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -17,19 +17,21 @@ package com.android.launcher2; import android.app.WallpaperManager; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.Intent; import android.content.ComponentName; +import android.content.pm.ProviderInfo; import android.content.res.TypedArray; import android.content.pm.PackageManager; import android.graphics.Canvas; -import android.graphics.RectF; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Parcelable; import android.os.Parcel; import android.util.AttributeSet; -import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; @@ -88,6 +90,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private OnLongClickListener mLongClickListener; private Launcher mLauncher; + private IconCache mIconCache; private DragController mDragController; /** @@ -103,16 +106,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private int mTouchSlop; private int mMaximumVelocity; - final Rect mDrawerBounds = new Rect(); - final Rect mClipBounds = new Rect(); - int mDrawerContentHeight; - int mDrawerContentWidth; - private Drawable mPreviousIndicator; private Drawable mNextIndicator; - private boolean mFading = true; - /** * Used to inflate the Workspace from XML. * @@ -147,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(); @@ -246,27 +245,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } /** - * Returns how many screens there are. - */ - int getScreenCount() { - return getChildCount(); - } - - /** - * Computes a bounding rectangle for a range of cells - * - * @param cellX X coordinate of upper left corner expressed as a cell position - * @param cellY Y coordinate of upper left corner expressed as a cell position - * @param cellHSpan Width in cells - * @param cellVSpan Height in cells - * @param rect Rectnagle into which to put the results - */ - public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF rect) { - ((CellLayout)getChildAt(mCurrentScreen)).cellToRect(cellX, cellY, - cellHSpan, cellVSpan, rect); - } - - /** * Sets the current screen. * * @param currentScreen @@ -275,6 +253,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag if (!mScroller.isFinished()) mScroller.abortAnimation(); clearVacantCache(); mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1)); + mPreviousIndicator.setLevel(mCurrentScreen); + mNextIndicator.setLevel(mCurrentScreen); scrollTo(mCurrentScreen * getWidth(), 0); invalidate(); } @@ -386,56 +366,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag mVacantCache = null; } } - - /** - * Returns the coordinate of a vacant cell for the current screen. - */ - boolean getVacantCell(int[] vacant, int spanX, int spanY) { - CellLayout group = (CellLayout) getChildAt(mCurrentScreen); - if (group != null) { - return group.getVacantCell(vacant, spanX, spanY); - } - return false; - } - - /** - * Adds the specified child in the current screen. The position and dimension of - * the child are defined by x, y, spanX and spanY. - * - * @param child The child to add in one of the workspace's screens. - * @param spanX The number of cells spanned horizontally by the child. - * @param spanY The number of cells spanned vertically by the child. - */ - void fitInCurrentScreen(View child, int spanX, int spanY) { - fitInScreen(child, mCurrentScreen, spanX, spanY); - } - - /** - * Adds the specified child in the specified screen. The position and dimension of - * the child are defined by x, y, spanX and spanY. - * - * @param child The child to add in one of the workspace's screens. - * @param screen The screen in which to add the child. - * @param spanX The number of cells spanned horizontally by the child. - * @param spanY The number of cells spanned vertically by the child. - */ - void fitInScreen(View child, int screen, int spanX, int spanY) { - if (screen < 0 || screen >= getChildCount()) { - throw new IllegalStateException("The screen must be >= 0 and < " + getChildCount()); - } - - final CellLayout group = (CellLayout) getChildAt(screen); - boolean vacant = group.getVacantCell(mTempCell, spanX, spanY); - if (vacant) { - group.addView(child, - new CellLayout.LayoutParams(mTempCell[0], mTempCell[1], spanX, spanY)); - child.setHapticFeedbackEnabled(false); - child.setOnLongClickListener(mLongClickListener); - if (child instanceof DropTarget) { - mDragController.addDropTarget((DropTarget)child); - } - } - } /** * Registers the specified listener on each screen contained in this workspace. @@ -477,60 +407,17 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } } - public void startFading(boolean dest) { - mFading = dest; - invalidate(); - } - @Override protected void dispatchDraw(Canvas canvas) { - /* - final boolean allAppsOpaque = mLauncher.isAllAppsOpaque(); - if (mFading == allAppsOpaque) { - invalidate(); - } else { - mFading = !allAppsOpaque; - } - if (allAppsOpaque) { - // If the launcher is up, draw black. - canvas.drawARGB(0xff, 0, 0, 0); - return; - } - */ - boolean restore = false; int restoreCount = 0; - // For the fade. If view gets setAlpha(), use that instead. - float scale = mScale; - if (scale < 0.999f) { - int sx = mScrollX; - - int alpha = (scale < 0.5f) ? (int)(255 * 2 * scale) : 255; - - restoreCount = canvas.saveLayerAlpha(sx, 0, sx+getWidth(), getHeight(), alpha, - Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); - restore = true; - - if (scale < 0.999f) { - int w = getWidth(); - w += 2 * mCurrentScreen * w; - int dx = w/2; - int h = getHeight(); - int dy = (h/2) - (h/4); - canvas.translate(dx, dy); - canvas.scale(scale, scale); - canvas.translate(-dx, -dy); - } - } - // ViewGroup.dispatchDraw() supports many features we don't need: // clip to padding, layout animation, animation listener, disappearing // children, etc. The following implementation attempts to fast-track // the drawing dispatch by drawing only what we know needs to be drawn. - boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN - && scale > 0.999f; + boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN; // If we are not scrolling or flinging, draw only the current screen if (fastDraw) { drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime()); @@ -555,12 +442,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } } - private float mScale = 1.0f; - public void setScale(float scale) { - mScale = scale; - invalidate(); - } - protected void onAttachedToWindow() { super.onAttachedToWindow(); mDragController.setWindowToken(getWindowToken()); @@ -772,12 +653,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag case MotionEvent.ACTION_UP: if (mTouchState != TOUCH_STATE_SCROLLING) { - final CellLayout currentScreen = (CellLayout)getChildAt(mCurrentScreen); if (!currentScreen.lastDownOnOccupiedCell()) { + getLocationOnScreen(mTempCell); // Send a tap to the wallpaper if the last down was on empty space mWallpaperManager.sendWallpaperCommand(getWindowToken(), - "android.wallpaper.tap", (int) ev.getX(), (int) ev.getY(), 0, null); + "android.wallpaper.tap", + mTempCell[0] + (int) ev.getX(), + mTempCell[1] + (int) ev.getY(), 0, null); } } @@ -970,6 +853,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag final int delta = newX - mScrollX; final int duration = screenDelta * 300; awakenScrollBars(duration); + + if (!mScroller.isFinished()) mScroller.abortAnimation(); mScroller.startScroll(mScrollX, 0, delta, 0, duration); invalidate(); } @@ -1010,11 +895,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]; @@ -1080,10 +965,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((ApplicationInfo)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, @@ -1215,16 +1099,19 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag public void scrollLeft() { clearVacantCache(); - if (mNextScreen == INVALID_SCREEN && mCurrentScreen > 0 && mScroller.isFinished()) { - snapToScreen(mCurrentScreen - 1); + if (mScroller.isFinished()) { + if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1); + } else { + if (mNextScreen > 0) snapToScreen(mNextScreen - 1); } } public void scrollRight() { clearVacantCache(); - if (mNextScreen == INVALID_SCREEN && mCurrentScreen < getChildCount() -1 && - mScroller.isFinished()) { - snapToScreen(mCurrentScreen + 1); + if (mScroller.isFinished()) { + if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1); + } else { + if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1); } } @@ -1314,74 +1201,105 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag mAllowLongPress = allowLongPress; } - void removeShortcutsForPackage(String packageName) { - final ArrayList<View> childrenToRemove = new ArrayList<View>(); + void removeItemsForPackage(final String packageName) { final int count = getChildCount(); + final PackageManager manager = getContext().getPackageManager(); + final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext()); for (int i = 0; i < count; i++) { final CellLayout layout = (CellLayout) getChildAt(i); - int childCount = layout.getChildCount(); - - childrenToRemove.clear(); - for (int j = 0; j < childCount; j++) { - final View view = layout.getChildAt(j); - Object tag = view.getTag(); - - if (tag instanceof ApplicationInfo) { - final ApplicationInfo info = (ApplicationInfo) tag; - // We need to check for ACTION_MAIN otherwise getComponent() might - // return null for some shortcuts (for instance, for shortcuts to - // web pages.) - final Intent intent = info.intent; - final ComponentName name = intent.getComponent(); - - if (Intent.ACTION_MAIN.equals(intent.getAction()) && - name != null && packageName.equals(name.getPackageName())) { - LauncherModel.deleteItemFromDatabase(mLauncher, info); - childrenToRemove.add(view); + // Avoid ANRs by treating each screen separately + post(new Runnable() { + public void run() { + final ArrayList<View> childrenToRemove = new ArrayList<View>(); + childrenToRemove.clear(); + + int childCount = layout.getChildCount(); + for (int j = 0; j < childCount; j++) { + final View view = layout.getChildAt(j); + Object tag = view.getTag(); + + if (tag instanceof ShortcutInfo) { + final ShortcutInfo info = (ShortcutInfo) tag; + // We need to check for ACTION_MAIN otherwise getComponent() might + // return null for some shortcuts (for instance, for shortcuts to + // web pages.) + final Intent intent = info.intent; + final ComponentName name = intent.getComponent(); + + if (Intent.ACTION_MAIN.equals(intent.getAction()) && + name != null && packageName.equals(name.getPackageName())) { + // TODO: This should probably be done on a worker thread + LauncherModel.deleteItemFromDatabase(mLauncher, info); + childrenToRemove.add(view); + } + } else if (tag instanceof UserFolderInfo) { + final UserFolderInfo info = (UserFolderInfo) tag; + final ArrayList<ShortcutInfo> contents = info.contents; + final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1); + final int contentsCount = contents.size(); + boolean removedFromFolder = false; + + for (int k = 0; k < contentsCount; k++) { + final ShortcutInfo appInfo = contents.get(k); + final Intent intent = appInfo.intent; + final ComponentName name = intent.getComponent(); + + if (Intent.ACTION_MAIN.equals(intent.getAction()) && + name != null && packageName.equals(name.getPackageName())) { + toRemove.add(appInfo); + // TODO: This should probably be done on a worker thread + LauncherModel.deleteItemFromDatabase(mLauncher, appInfo); + removedFromFolder = true; + } + } + + contents.removeAll(toRemove); + if (removedFromFolder) { + final Folder folder = getOpenFolder(); + if (folder != null) folder.notifyDataSetChanged(); + } + } else if (tag instanceof LiveFolderInfo) { + final LiveFolderInfo info = (LiveFolderInfo) tag; + final Uri uri = info.uri; + final ProviderInfo providerInfo = manager.resolveContentProvider( + uri.getAuthority(), 0); + + if (providerInfo == null || + packageName.equals(providerInfo.packageName)) { + // TODO: This should probably be done on a worker thread + LauncherModel.deleteItemFromDatabase(mLauncher, info); + childrenToRemove.add(view); + } + } else if (tag instanceof LauncherAppWidgetInfo) { + final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag; + final AppWidgetProviderInfo provider = + widgets.getAppWidgetInfo(info.appWidgetId); + if (provider == null || + packageName.equals(provider.provider.getPackageName())) { + // TODO: This should probably be done on a worker thread + LauncherModel.deleteItemFromDatabase(mLauncher, info); + childrenToRemove.add(view); + } + } } - } else if (tag instanceof UserFolderInfo) { - final UserFolderInfo info = (UserFolderInfo) tag; - final ArrayList<ApplicationInfo> contents = info.contents; - final ArrayList<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>(1); - final int contentsCount = contents.size(); - boolean removedFromFolder = false; - - for (int k = 0; k < contentsCount; k++) { - final ApplicationInfo appInfo = contents.get(k); - final Intent intent = appInfo.intent; - final ComponentName name = intent.getComponent(); - - if (Intent.ACTION_MAIN.equals(intent.getAction()) && - name != null && packageName.equals(name.getPackageName())) { - toRemove.add(appInfo); - LauncherModel.deleteItemFromDatabase(mLauncher, appInfo); - removedFromFolder = true; + + childCount = childrenToRemove.size(); + for (int j = 0; j < childCount; j++) { + View child = childrenToRemove.get(j); + layout.removeViewInLayout(child); + if (child instanceof DropTarget) { + mDragController.removeDropTarget((DropTarget)child); } } - - contents.removeAll(toRemove); - if (removedFromFolder) { - final Folder folder = getOpenFolder(); - if (folder != null) folder.notifyDataSetChanged(); + + if (childCount > 0) { + layout.requestLayout(); + layout.invalidate(); } } - } - - childCount = childrenToRemove.size(); - for (int j = 0; j < childCount; j++) { - View child = childrenToRemove.get(j); - layout.removeViewInLayout(child); - if (child instanceof DropTarget) { - mDragController.removeDropTarget((DropTarget)child); - } - } - - if (childCount > 0) { - layout.requestLayout(); - layout.invalidate(); - } + }); } } @@ -1395,8 +1313,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.) @@ -1406,14 +1324,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); } } } @@ -1465,11 +1378,4 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } }; } - - void show() { - setVisibility(VISIBLE); - } - - void hide() { - } } |