diff options
author | Danesh Mondegarian <daneshm90@gmail.com> | 2013-09-02 15:21:30 -0700 |
---|---|---|
committer | Danesh Mondegarian <daneshm90@gmail.com> | 2013-09-08 18:53:30 -0700 |
commit | e576f6e7887b063d1b6d9a2052eedd4cc7c014ee (patch) | |
tree | 492d8f44a6881ba1e84e77f67e2bd6d7c78e2012 /src/com | |
parent | 98ff0fc540dd6f515af3bee058518efcad11b494 (diff) | |
download | android_packages_apps_Trebuchet-e576f6e7887b063d1b6d9a2052eedd4cc7c014ee.tar.gz android_packages_apps_Trebuchet-e576f6e7887b063d1b6d9a2052eedd4cc7c014ee.tar.bz2 android_packages_apps_Trebuchet-e576f6e7887b063d1b6d9a2052eedd4cc7c014ee.zip |
Trebuchet : Support for custom icons per shortcut
Allows user to assign custom icons from icon packs to individual
homescreen shortcuts.
Change-Id: I6613b5f3e6517485a6f83aa5f6769e22bb7f18dc
Diffstat (limited to 'src/com')
-rw-r--r-- | src/com/cyanogenmod/trebuchet/BubbleTextView.java | 13 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/Folder.java | 20 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/IconCache.java | 15 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/IconPackHelper.java | 201 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/IconPickerActivity.java | 151 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/Launcher.java | 95 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/LauncherModel.java | 57 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/LauncherProvider.java | 9 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/LauncherSettings.java | 2 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/ShortcutInfo.java | 19 | ||||
-rw-r--r-- | src/com/cyanogenmod/trebuchet/preference/Preferences.java | 2 |
11 files changed, 491 insertions, 93 deletions
diff --git a/src/com/cyanogenmod/trebuchet/BubbleTextView.java b/src/com/cyanogenmod/trebuchet/BubbleTextView.java index 8a48b1645..511e63150 100644 --- a/src/com/cyanogenmod/trebuchet/BubbleTextView.java +++ b/src/com/cyanogenmod/trebuchet/BubbleTextView.java @@ -162,14 +162,21 @@ public class BubbleTextView extends TextView implements ShortcutInfo.ShortcutLis } @Override - public void onTitleChanged(CharSequence title) { + public void onTitleChanged(ShortcutInfo item) { if (mTextVisible) { - setText(title); + setText(item.title); } else { - mVisibleText = title; + mVisibleText = item.title; } } + @Override + public void onIconChanged(ShortcutInfo item) { + setCompoundDrawablesWithIntrinsicBounds(null, + new FastBitmapDrawable(item.getIcon(null)), + null, null); + } + /** * Draw this BubbleTextView into the given Canvas. * diff --git a/src/com/cyanogenmod/trebuchet/Folder.java b/src/com/cyanogenmod/trebuchet/Folder.java index 6d3a2f64d..0b8410c40 100644 --- a/src/com/cyanogenmod/trebuchet/Folder.java +++ b/src/com/cyanogenmod/trebuchet/Folder.java @@ -22,6 +22,7 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.content.Context; import android.content.res.Resources; +import android.graphics.Bitmap; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -47,6 +48,7 @@ import android.widget.TextView; import android.widget.Toast; import com.cyanogenmod.trebuchet.FolderInfo.FolderListener; +import com.cyanogenmod.trebuchet.ShortcutInfo.ShortcutListener; import com.cyanogenmod.trebuchet.preference.PreferencesProvider; import java.util.ArrayList; @@ -58,7 +60,7 @@ import java.util.Comparator; */ public class Folder extends LinearLayout implements DragSource, View.OnClickListener, View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener, - View.OnFocusChangeListener { + View.OnFocusChangeListener, ShortcutListener { private static final String TAG = "Trebuchet.Folder"; protected DragController mDragController; @@ -1128,6 +1130,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList findAndSetEmptyCells(item); } createAndAddShortcut(item); + item.setListener(this); if (!(item instanceof LiveFolderItemInfo)) { LauncherModel.addOrMoveItemInDatabase( mLauncher, item, mInfo.id, 0, item.cellX, item.cellY); @@ -1209,4 +1212,19 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList startEditingFolderName(); } } + + @Override + public void onTitleChanged(ShortcutInfo item) { + TextView textView = (TextView) getViewForInfo(item); + textView.setText(item.title); + } + + @Override + public void onIconChanged(ShortcutInfo item) { + TextView textView = (TextView) getViewForInfo(item); + textView.setCompoundDrawablesWithIntrinsicBounds(null, + new FastBitmapDrawable(item.getIcon(mIconCache)), null, null); + mInfo.itemsChanged(); + } + } diff --git a/src/com/cyanogenmod/trebuchet/IconCache.java b/src/com/cyanogenmod/trebuchet/IconCache.java index 7f4b13594..204c29780 100644 --- a/src/com/cyanogenmod/trebuchet/IconCache.java +++ b/src/com/cyanogenmod/trebuchet/IconCache.java @@ -109,7 +109,13 @@ public class IconCache { } public Drawable getFullResIcon(ActivityInfo info) { - + int iconId = 0; + if (mIconPackHelper != null && mIconPackHelper.isIconPackLoaded()) { + iconId = mIconPackHelper.getResourceIdForActivityIcon(info); + if (iconId != 0) { + return getFullResIcon(mIconPackHelper.getIconPackResources(), iconId); + } + } Resources resources; try { resources = mPackageManager.getResourcesForApplication( @@ -118,13 +124,6 @@ public class IconCache { resources = null; } if (resources != null) { - int iconId = 0; - if (mIconPackHelper != null && mIconPackHelper.isIconPackLoaded()) { - iconId = mIconPackHelper.getResourceIdForActivityIcon(info); - if (iconId != 0) { - return getFullResIcon(mIconPackHelper.getIconPackResources(), iconId); - } - } iconId = info.getIconResource(); if (iconId != 0) { return getFullResIcon(resources, iconId); diff --git a/src/com/cyanogenmod/trebuchet/IconPackHelper.java b/src/com/cyanogenmod/trebuchet/IconPackHelper.java index 228ea2c88..ed44c250e 100644 --- a/src/com/cyanogenmod/trebuchet/IconPackHelper.java +++ b/src/com/cyanogenmod/trebuchet/IconPackHelper.java @@ -2,6 +2,7 @@ package com.cyanogenmod.trebuchet; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -10,6 +11,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; +import android.app.Activity; import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; @@ -68,9 +70,9 @@ public class IconPackHelper { return packages; } - private void loadResourcesFromXmlParser(XmlPullParser parser) throws XmlPullParserException, IOException { + private static void loadResourcesFromXmlParser(XmlPullParser parser, + Map<ComponentName, String> iconPackResources) throws XmlPullParserException, IOException { int eventType = parser.getEventType(); - mIconPackResources.clear(); do { if (eventType != XmlPullParser.START_TAG) { @@ -107,33 +109,89 @@ public class IconPackHelper { } if (name != null) { - mIconPackResources.put(name, drawable); + iconPackResources.put(name, drawable); } } while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT); } - public void loadIconPack(String packageName) { - String defaultIcons = mContext.getResources().getString(R.string.default_iconpack_title); - if (packageName.equals(defaultIcons)) { + private static void loadApplicationResources(Context context, + Map<ComponentName, String> iconPackResources, String packageName) { + Field[] drawableItems = null; + try { + Context appContext = context.createPackageContext(packageName, + Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); + drawableItems = Class.forName(packageName+".R$drawable", + true, appContext.getClassLoader()).getFields(); + } catch (Exception e){ return; } + for (Field f : drawableItems) { + String name = f.getName(); + + String icon = name; + name = name.replaceAll("_", "."); + + ComponentName compName = new ComponentName(name.toLowerCase(), ""); + iconPackResources.put(compName, icon); + + int activityIndex = name.lastIndexOf("."); + if (activityIndex <= 0 || activityIndex == name.length() - 1) { + continue; + } + + String iconPackage = name.substring(0, activityIndex); + if (TextUtils.isEmpty(iconPackage)) { + continue; + } + + String iconActivity = name.substring(activityIndex + 1); + if (TextUtils.isEmpty(iconActivity)) { + continue; + } + + // Store entries as lower case to ensure match + iconPackage = iconPackage.toLowerCase(); + iconActivity = iconActivity.toLowerCase(); + + iconActivity = iconPackage + "." + iconActivity; + compName = new ComponentName(iconPackage, iconActivity); + iconPackResources.put(compName, icon); + } + } + + public void loadIconPack(String packageName) { + mIconPackResources = getIconPackResources(mContext, packageName); Resources res = null; try { res = mContext.getPackageManager().getResourcesForApplication(packageName); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); - return; + } + mLoadedIconPackResource = res; + mLoadedIconPackName = packageName; + } + + public static Map<ComponentName, String> getIconPackResources(Context context, String packageName) { + String defaultIcons = context.getResources().getString(R.string.default_iconpack_title); + if (packageName.equals(defaultIcons)) { + return null; + } + + Resources res = null; + try { + res = context.getPackageManager().getResourcesForApplication(packageName); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return null; } XmlPullParser parser = null; InputStream inputStream = null; + Map<ComponentName, String> iconPackResources = new HashMap<ComponentName, String>(); try { - XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); - inputStream = res.getAssets().open("appfilter.xml"); - parser = factory.newPullParser(); - parser.setInput(inputStream, "UTF-8"); + parser = res.getAssets().openXmlResourceParser("appfilter.xml"); } catch (Exception e) { // Catch any exception since we want to fall back to parsing the xml/ // resource in all cases @@ -145,10 +203,8 @@ public class IconPackHelper { if (parser != null) { try { - loadResourcesFromXmlParser(parser); - mLoadedIconPackResource = res; - mLoadedIconPackName = packageName; - return; + loadResourcesFromXmlParser(parser, iconPackResources); + return iconPackResources; } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { @@ -170,56 +226,60 @@ public class IconPackHelper { int arrayId = res.getIdentifier("theme_iconpack", "array", packageName); if (arrayId == 0) { arrayId = res.getIdentifier("icon_pack", "array", packageName); - if (arrayId == 0) { - return; - } } - String[] iconPack = res.getStringArray(arrayId); - ComponentName compName = null; - mIconPackResources.clear(); - for (String entry : iconPack) { + if (arrayId != 0) { + String[] iconPack = res.getStringArray(arrayId); + ComponentName compName = null; + for (String entry : iconPack) { - if (TextUtils.isEmpty(entry)) { - continue; - } + if (TextUtils.isEmpty(entry)) { + continue; + } - String icon = entry; - entry = entry.replaceAll("_", "."); + String icon = entry; + entry = entry.replaceAll("_", "."); - compName = new ComponentName(entry.toLowerCase(), ""); - mIconPackResources.put(compName, icon); + compName = new ComponentName(entry.toLowerCase(), ""); + iconPackResources.put(compName, icon); - int activityIndex = entry.lastIndexOf("."); - if (activityIndex <= 0 || activityIndex == entry.length() - 1) { - continue; - } + int activityIndex = entry.lastIndexOf("."); + if (activityIndex <= 0 || activityIndex == entry.length() - 1) { + continue; + } - String iconPackage = entry.substring(0, activityIndex); - if (TextUtils.isEmpty(iconPackage)) { - continue; - } + String iconPackage = entry.substring(0, activityIndex); + if (TextUtils.isEmpty(iconPackage)) { + continue; + } - String iconActivity = entry.substring(activityIndex + 1); - if (TextUtils.isEmpty(iconActivity)) { - continue; - } + String iconActivity = entry.substring(activityIndex + 1); + if (TextUtils.isEmpty(iconActivity)) { + continue; + } - // Store entries as lower case to ensure match - iconPackage = iconPackage.toLowerCase(); - iconActivity = iconActivity.toLowerCase(); + // Store entries as lower case to ensure match + iconPackage = iconPackage.toLowerCase(); + iconActivity = iconActivity.toLowerCase(); - iconActivity = iconPackage + "." + iconActivity; - compName = new ComponentName(iconPackage, iconActivity); - mIconPackResources.put(compName, icon); + iconActivity = iconPackage + "." + iconActivity; + compName = new ComponentName(iconPackage, iconActivity); + iconPackResources.put(compName, icon); + } + } else { + loadApplicationResources(context, iconPackResources, packageName); } - mLoadedIconPackResource = res; - mLoadedIconPackName = packageName; + return iconPackResources; } - public static void pickIconPack(final Context context) { + public static void pickIconPack(final Context context, final boolean pickIcon) { final HashMap<CharSequence, String> supportedPackages = getSupportedPackages(context); + if (supportedPackages.isEmpty()) { + Toast.makeText(context, R.string.no_iconpacks_summary, Toast.LENGTH_SHORT).show(); + return; + } + final CharSequence[] dialogEntries = new CharSequence[supportedPackages.size() + 1]; supportedPackages.keySet().toArray(dialogEntries); @@ -249,23 +309,42 @@ public class IconPackHelper { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.dialog_pick_iconpack_title); - builder.setSingleChoiceItems(dialogEntries, selectedIndex, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - CharSequence selectedPackage = dialogEntries[which]; - if (selectedPackage.equals(defaultIcons)) { - PreferencesProvider.Interface.General.setIconPack(context, ""); - } else { - PreferencesProvider.Interface.General.setIconPack(context, supportedPackages.get(selectedPackage)); + if (!pickIcon) { + builder.setSingleChoiceItems(dialogEntries, selectedIndex, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + CharSequence selectedPackage = dialogEntries[which]; + if (selectedPackage.equals(defaultIcons)) { + PreferencesProvider.Interface.General.setIconPack(context, ""); + } else { + PreferencesProvider.Interface.General.setIconPack(context, supportedPackages.get(selectedPackage)); + } + dialog.dismiss(); } - dialog.dismiss(); - } - }); + }); + } else { + builder.setItems(dialogEntries, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + CharSequence selectedPackage = dialogEntries[which]; + Launcher launcherActivity = (Launcher) context; + if (selectedPackage.equals(defaultIcons)) { + launcherActivity.onActivityResult(Launcher.REQUEST_PICK_ICON, Activity.RESULT_OK, null); + } else { + Intent i = new Intent(); + i.setClass(context, IconPickerActivity.class); + i.putExtra("package", supportedPackages.get(selectedPackage)); + launcherActivity.startActivityForResult(i, Launcher.REQUEST_PICK_ICON); + } + dialog.dismiss(); + } + }); + } builder.show(); } boolean isIconPackLoaded() { return mLoadedIconPackResource != null && - mLoadedIconPackName != null; + mLoadedIconPackName != null && + mIconPackResources != null; } private int getResourceIdForDrawable(String resource) { diff --git a/src/com/cyanogenmod/trebuchet/IconPickerActivity.java b/src/com/cyanogenmod/trebuchet/IconPickerActivity.java new file mode 100644 index 000000000..2acc07e4d --- /dev/null +++ b/src/com/cyanogenmod/trebuchet/IconPickerActivity.java @@ -0,0 +1,151 @@ +package com.cyanogenmod.trebuchet; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.Map; + +import android.app.Activity; +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.GridView; +import android.widget.ImageView; + +public class IconPickerActivity extends Activity { + + public static final String SELECTED_RESOURCE_EXTRA = "selected_resource"; + public static final String SELECTED_BITMAP_EXTRA = "bitmap"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ActivityManager activityManager = + (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + int iconSize = activityManager.getLauncherLargeIconSize(); + final String pkgName = getIntent().getStringExtra("package"); + + GridView gridview = new GridView(this); + gridview.setNumColumns(GridView.AUTO_FIT); + gridview.setHorizontalSpacing(40); + gridview.setVerticalSpacing(40); + gridview.setPadding(20, 20, 20, 0); + gridview.setFastScrollEnabled(true); + gridview.setColumnWidth(iconSize); + gridview.setStretchMode(GridView.STRETCH_COLUMN_WIDTH); + + gridview.setAdapter(new ImageAdapter(this, pkgName)); + gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> adapterView, View v, int position, long id) { + Intent in = new Intent(); + DrawableInfo d = (DrawableInfo) adapterView.getAdapter().getItem(position); + in.putExtra(SELECTED_RESOURCE_EXTRA, pkgName + "|" + d.resource_name); + in.putExtra(SELECTED_BITMAP_EXTRA, ((BitmapDrawable)d.drawable.get()).getBitmap()); + setResult(Activity.RESULT_OK, in); + finish(); + } + }); + setContentView(gridview); + } + + public class ImageAdapter extends BaseAdapter { + private Context mContext; + private Resources mResources; + private ArrayList<DrawableInfo> mDrawables = new ArrayList<DrawableInfo>(); + + public class FetchDrawable extends AsyncTask<Integer, Void, Drawable> { + WeakReference<ImageView> mImageView; + + FetchDrawable(ImageView imgView) { + mImageView = new WeakReference<ImageView>(imgView); + } + + @Override + protected Drawable doInBackground(Integer... position) { + DrawableInfo info = getItem(position[0]); + int itemId = info.resource_id; + Drawable d = mResources.getDrawable(itemId); + info.drawable = new WeakReference<Drawable>(d); + return d; + } + + @Override + public void onPostExecute(Drawable result) { + if (mImageView.get() != null) { + mImageView.get().setImageDrawable(result); + } + } + } + + public ImageAdapter(Context c, String pkgName) { + mContext = c; + Map<ComponentName, String> resources = IconPackHelper.getIconPackResources(c, pkgName); + try { + mResources = c.getPackageManager().getResourcesForApplication(pkgName); + LinkedHashSet<String> drawables = new LinkedHashSet<String>(resources.values()); + for (String s : drawables) { + int id = mResources.getIdentifier(s, "drawable", pkgName); + if (id != 0) { + mDrawables.add(new DrawableInfo(s, id)); + } + } + } catch (NameNotFoundException e) { + } + } + + public int getCount() { + return mDrawables.size(); + } + + public DrawableInfo getItem(int position) { + return mDrawables.get(position); + } + + public long getItemId(int position) { + return 0; + } + + public View getView(final int position, View convertView, ViewGroup parent) { + final ImageView imageView; + if (convertView == null) { + imageView = new ImageView(mContext); + imageView.setLayoutParams(new GridView.LayoutParams( + GridView.LayoutParams.WRAP_CONTENT, GridView.LayoutParams.WRAP_CONTENT)); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + } else { + imageView = (ImageView) convertView; + Object tag = imageView.getTag(); + if (tag != null && tag instanceof FetchDrawable) { + ((FetchDrawable) tag).cancel(true); + } + } + FetchDrawable req = new FetchDrawable(imageView); + imageView.setTag(req); + req.execute(position); + return imageView; + } + } + + private class DrawableInfo { + WeakReference<Drawable> drawable; + final String resource_name; + final int resource_id; + DrawableInfo(String n, int i) { + resource_name = n; + resource_id = i; + } + } +} diff --git a/src/com/cyanogenmod/trebuchet/Launcher.java b/src/com/cyanogenmod/trebuchet/Launcher.java index 08e67cc57..dfd27048a 100644 --- a/src/com/cyanogenmod/trebuchet/Launcher.java +++ b/src/com/cyanogenmod/trebuchet/Launcher.java @@ -51,6 +51,7 @@ import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; +import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -99,6 +100,7 @@ import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.InputMethodManager; import android.widget.Advanceable; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.PopupMenu; import android.widget.TextView; @@ -117,6 +119,7 @@ import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -154,9 +157,9 @@ public final class Launcher extends Activity private static final int REQUEST_PICK_SHORTCUT = 7; private static final int REQUEST_PICK_APPWIDGET = 9; private static final int REQUEST_PICK_WALLPAPER = 10; - private static final int REQUEST_CREATE_LIVE_FOLDER = 12; - private static final int REQUEST_BIND_APPWIDGET = 11; + private static final int REQUEST_CREATE_LIVE_FOLDER = 12; + static final int REQUEST_PICK_ICON = 13; static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate"; @@ -335,6 +338,7 @@ public final class Launcher extends Activity private boolean mFullscreenMode; private boolean mWallpaperVisible; + private ImageButton mDialogIcon; private Runnable mBuildLayersRunnable = new Runnable() { public void run() { @@ -679,6 +683,60 @@ public final class Launcher extends Activity addAppWidgetImpl(appWidgetId, mPendingAddInfo, null, mPendingAddWidgetInfo); } return; + } else if (requestCode == REQUEST_PICK_ICON) { + mWaitingForResult = false; + if (resultCode == RESULT_OK) { + if (data == null) { + // Get/Set default icon + String id = (String) mDialogIcon.getTag(); + final PackageManager manager = getPackageManager(); + + final Cursor c = getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, + null, LauncherSettings.Favorites._ID + "=?", new String[]{id}, null); + if (c != null && c.getCount() > 0) { + c.moveToFirst(); + final int itemTypeIndex = c.getColumnIndexOrThrow( + LauncherSettings.Favorites.ITEM_TYPE); + final int titleIndex = c.getColumnIndexOrThrow + (LauncherSettings.Favorites.TITLE); + final int iconTypeIndex = c.getColumnIndexOrThrow( + LauncherSettings.Favorites.ICON_TYPE); + final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON); + final int iconPackageIndex = c.getColumnIndexOrThrow( + LauncherSettings.Favorites.ICON_PACKAGE); + final int iconResourceIndex = c.getColumnIndexOrThrow( + LauncherSettings.Favorites.ICON_RESOURCE); + final int intentIndex = c.getColumnIndexOrThrow + (LauncherSettings.Favorites.INTENT); + String intentDescription = c.getString(intentIndex); + Intent intent = null; + try { + intent = Intent.parseUri(intentDescription, 0); + } catch (URISyntaxException e) { + c.close(); + return; + } + int itemType = c.getInt(itemTypeIndex); + ShortcutInfo info = null; + if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { + info = mModel.getShortcutInfo(manager, intent, this, c, iconIndex, + titleIndex, -1, null); + } else if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { + info = mModel.getShortcutInfo(c, this, iconTypeIndex, + iconPackageIndex, iconResourceIndex, iconIndex, + titleIndex, -1); + } + mDialogIcon.setImageBitmap(info.getIcon(null)); + mDialogIcon.setTag(null); + c.close(); + } + } else { + // Set custom icon from icon pack + mDialogIcon.setImageBitmap((Bitmap) data.getParcelableExtra(IconPickerActivity.SELECTED_BITMAP_EXTRA)); + mDialogIcon.setTag(data.getStringExtra(IconPickerActivity.SELECTED_RESOURCE_EXTRA)); + } + } + return; } boolean delayExitSpringLoadedMode = false; boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET || @@ -1089,8 +1147,16 @@ public final class Launcher extends Activity void updateShortcut(final ShortcutInfo info) { AlertDialog.Builder builder = new AlertDialog.Builder(this); View layout = mInflater.inflate(R.layout.dialog_edit, null); - ImageView icon = (ImageView) layout.findViewById(R.id.dialog_edit_icon); - icon.setImageBitmap(info.getIcon(mIconCache)); + mDialogIcon = (ImageButton) layout.findViewById(R.id.dialog_edit_icon); + mDialogIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + mDialogIcon.setImageBitmap(info.getIcon(mIconCache)); + mDialogIcon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mDialogIcon.setTag(String.valueOf(info.id)); + IconPackHelper.pickIconPack(Launcher.this, true); + } + }); final EditText title = (EditText) layout.findViewById(R.id.dialog_edit_text); title.setText(info.title); builder.setView(layout) @@ -1098,12 +1164,31 @@ public final class Launcher extends Activity .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { - info.setTitle(title.getText()); + if (!info.title.equals(title.getText())) { + info.setTitle(title.getText()); + } + if (mDialogIcon.getTag() != null) { + info.customIconResource = (String) mDialogIcon.getTag(); + Drawable d = mModel.getDrawableForCustomIcon(Launcher.this, info.customIconResource); + if (d != null) { + info.setIcon(Utilities.createIconBitmap(d, Launcher.this)); + } + } else { + info.customIconResource = null; + info.setIcon(((BitmapDrawable)mDialogIcon.getDrawable()).getBitmap()); + } + LauncherModel.updateItemInDatabase(Launcher.this, info); } }) .setNegativeButton(android.R.string.cancel, null); builder.show(); + builder.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + mDialogIcon = null; + } + }); } /** diff --git a/src/com/cyanogenmod/trebuchet/LauncherModel.java b/src/com/cyanogenmod/trebuchet/LauncherModel.java index ba8eb6a63..08efc6fa8 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherModel.java +++ b/src/com/cyanogenmod/trebuchet/LauncherModel.java @@ -36,6 +36,7 @@ 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.os.Environment; import android.os.Handler; @@ -44,6 +45,7 @@ import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; +import android.text.TextUtils; import android.util.Log; import com.cyanogenmod.trebuchet.preference.PreferencesProvider; @@ -1358,6 +1360,8 @@ public class LauncherModel extends BroadcastReceiver { LauncherSettings.Favorites.SPANY); final int receiverPackageIndex = c.getColumnIndexOrThrow( LauncherSettings.Favorites.RECEIVER_COMPONENT); + final int customIconIndex = c.getColumnIndexOrThrow( + LauncherSettings.Favorites.CUSTOM_ICON); ShortcutInfo info; String intentDescription; @@ -1384,11 +1388,11 @@ public class LauncherModel extends BroadcastReceiver { if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { info = getShortcutInfo(manager, intent, context, c, iconIndex, - titleIndex, mLabelCache); + titleIndex, customIconIndex, mLabelCache); } else if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { info = getShortcutInfo(c, context, iconTypeIndex, iconPackageIndex, iconResourceIndex, iconIndex, - titleIndex); + titleIndex, customIconIndex); // App shortcuts that used to be automatically added to Launcher // didn't always have the correct intent flags set, so do that @@ -1404,7 +1408,7 @@ public class LauncherModel extends BroadcastReceiver { } else { info = getShortcutInfo(c, context, iconTypeIndex, iconPackageIndex, iconResourceIndex, iconIndex, - titleIndex); + titleIndex, -1); info.itemType = LauncherSettings.Favorites.ITEM_TYPE_ALLAPPS; if (info.title == null) { info.title = mContext.getString(R.string.all_apps_button_label); @@ -2245,7 +2249,7 @@ public class LauncherModel extends BroadcastReceiver { * doesn't have a Cursor, but */ public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) { - return getShortcutInfo(manager, intent, context, null, -1, -1, null); + return getShortcutInfo(manager, intent, context, null, -1, -1, -1, null); } /** @@ -2254,7 +2258,7 @@ public class LauncherModel extends BroadcastReceiver { * If c is not null, then it will be used to fill in missing data like the title and icon. */ public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context, - Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) { + Cursor c, int iconIndex, int titleIndex, int customIconIndex, HashMap<Object, CharSequence> labelCache) { Bitmap icon = null; final ShortcutInfo info = new ShortcutInfo(); @@ -2315,6 +2319,11 @@ public class LauncherModel extends BroadcastReceiver { icon = getFallbackIcon(); info.usingFallbackIcon = true; } + Bitmap customIcon = getCustomIconFromCursor(c, context, customIconIndex); + if (customIcon != null) { + icon = customIcon; + } + info.setIcon(icon); // from the db @@ -2361,12 +2370,42 @@ public class LauncherModel extends BroadcastReceiver { return items; } + public Drawable getDrawableForCustomIcon(Context context, String customIconResource) { + String[] splitResource = customIconResource.split("\\|"); + String packageName = splitResource[0]; + String resource = splitResource[1]; + PackageManager packageManager = context.getPackageManager(); + Resources resources; + try { + resources = packageManager.getResourcesForApplication(packageName); + int id = resources.getIdentifier(resource, "drawable", packageName); + return mIconCache.getFullResIcon(resources, id); + } catch (NameNotFoundException e) { + } + return null; + } + + private Bitmap getCustomIconFromCursor(Cursor c, Context context, int customIconIndex) { + if (c == null || customIconIndex == -1) { + return null; + } + String customIconResource = c.getString(customIconIndex); + if (!TextUtils.isEmpty(customIconResource)) { + Drawable d = getDrawableForCustomIcon(context, customIconResource); + if (d != null) { + return Utilities.createIconBitmap( + d, context); + } + } + return null; + } + /** * Make an ShortcutInfo object for a shortcut that isn't an application. */ - private ShortcutInfo getShortcutInfo(Cursor c, Context context, + public ShortcutInfo getShortcutInfo(Cursor c, Context context, int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex, - int titleIndex) { + int titleIndex, int customIconIndex) { Bitmap icon = null; final ShortcutInfo info = new ShortcutInfo(); @@ -2420,6 +2459,10 @@ public class LauncherModel extends BroadcastReceiver { info.customIcon = false; break; } + Bitmap customIcon = getCustomIconFromCursor(c, context, customIconIndex); + if (customIcon != null) { + icon = customIcon; + } info.setIcon(icon); return info; } diff --git a/src/com/cyanogenmod/trebuchet/LauncherProvider.java b/src/com/cyanogenmod/trebuchet/LauncherProvider.java index 4805962aa..00220b183 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherProvider.java +++ b/src/com/cyanogenmod/trebuchet/LauncherProvider.java @@ -62,7 +62,7 @@ public class LauncherProvider extends ContentProvider { private static final String DATABASE_NAME = "launcher.db"; - private static final int DATABASE_VERSION = 15; + private static final int DATABASE_VERSION = 16; static final String AUTHORITY = "com.cyanogenmod.trebuchet.settings"; @@ -290,7 +290,8 @@ public class LauncherProvider extends ContentProvider { "iconPackage TEXT," + "iconResource TEXT," + "icon BLOB," + - "receiverComponent TEXT" + + "receiverComponent TEXT," + + "customIcon TEXT" + ");"); // Database was just created, so wipe any previous widgets @@ -439,6 +440,10 @@ public class LauncherProvider extends ContentProvider { version = 15; } + if (oldVersion < 16) { + db.execSQL("ALTER TABLE favorites ADD customIcon TEXT;"); + version = 16; + } if (version != DATABASE_VERSION) { Log.w(TAG, "Destroying all old data."); db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES); diff --git a/src/com/cyanogenmod/trebuchet/LauncherSettings.java b/src/com/cyanogenmod/trebuchet/LauncherSettings.java index f855139b1..aa52d0480 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherSettings.java +++ b/src/com/cyanogenmod/trebuchet/LauncherSettings.java @@ -99,6 +99,8 @@ class LauncherSettings { * <P>Type: BLOB</P> */ static final String ICON = "icon"; + + static final String CUSTOM_ICON = "customIcon"; } /** diff --git a/src/com/cyanogenmod/trebuchet/ShortcutInfo.java b/src/com/cyanogenmod/trebuchet/ShortcutInfo.java index 2924de675..14fd0c0fa 100644 --- a/src/com/cyanogenmod/trebuchet/ShortcutInfo.java +++ b/src/com/cyanogenmod/trebuchet/ShortcutInfo.java @@ -35,6 +35,7 @@ class ShortcutInfo extends ItemInfo { */ Intent intent; + String customIconResource; /** * Indicates whether the title comes from an application's resource (if false) * or from a custom title (if true.) @@ -67,7 +68,8 @@ class ShortcutInfo extends ItemInfo { /** * Title change listener */ - private ShortcutListener mListener; + private ArrayList<ShortcutListener> mListeners = + new ArrayList<ShortcutListener>(); /** * The shortcut folder information @@ -104,6 +106,9 @@ class ShortcutInfo extends ItemInfo { public void setIcon(Bitmap b) { mIcon = b; + for (ShortcutListener i : mListeners) { + i.onIconChanged(this); + } } public Bitmap getIcon(IconCache iconCache) { @@ -136,13 +141,15 @@ class ShortcutInfo extends ItemInfo { public void setTitle(CharSequence title) { this.title = title; this.customTitle = true; - if (mListener != null) { - mListener.onTitleChanged(title); + for (ShortcutListener i : mListeners) { + i.onTitleChanged(this); } } void setListener(ShortcutListener listener) { - mListener = listener; + if (!mListeners.contains(listener) && listener != null) { + mListeners.add(listener); + } } @Override @@ -156,6 +163,7 @@ class ShortcutInfo extends ItemInfo { String uri = intent != null ? intent.toUri(0) : null; values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri); + values.put(LauncherSettings.BaseLauncherColumns.CUSTOM_ICON, customIconResource); if (customIcon) { values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE, LauncherSettings.BaseLauncherColumns.ICON_TYPE_BITMAP); @@ -193,7 +201,8 @@ class ShortcutInfo extends ItemInfo { } interface ShortcutListener { - public void onTitleChanged(CharSequence title); + public void onTitleChanged(ShortcutInfo item); + public void onIconChanged(ShortcutInfo item); } } diff --git a/src/com/cyanogenmod/trebuchet/preference/Preferences.java b/src/com/cyanogenmod/trebuchet/preference/Preferences.java index f2fcec8be..2f66a65c6 100644 --- a/src/com/cyanogenmod/trebuchet/preference/Preferences.java +++ b/src/com/cyanogenmod/trebuchet/preference/Preferences.java @@ -193,7 +193,7 @@ public class Preferences extends PreferenceActivity public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { if (preference.getKey().equals("ui_general_iconpack")) { - IconPackHelper.pickIconPack(getActivity()); + IconPackHelper.pickIconPack(getActivity(), false); } return super.onPreferenceTreeClick(preferenceScreen, preference); } |