diff options
Diffstat (limited to 'src/com/android/launcher3/IconPackHelper.java')
-rw-r--r-- | src/com/android/launcher3/IconPackHelper.java | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/src/com/android/launcher3/IconPackHelper.java b/src/com/android/launcher3/IconPackHelper.java new file mode 100644 index 000000000..520e8df8b --- /dev/null +++ b/src/com/android/launcher3/IconPackHelper.java @@ -0,0 +1,440 @@ +package com.android.launcher3; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + +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; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.launcher3.settings.SettingsProvider; + +public class IconPackHelper { + + public final static String[] sSupportedActions = new String[] { + "org.adw.launcher.THEMES", + "com.gau.go.launcherex.theme" + }; + + public static final String[] sSupportedCategories = new String[] { + "com.fede.launcher.THEME_ICONPACK", + "com.anddoes.launcher.THEME", + "com.teslacoilsw.launcher.THEME" + }; + + // Holds package/class -> drawable + private Map<String, String> mIconPackResources; + private final Context mContext; + private String mLoadedIconPackName; + private Resources mLoadedIconPackResource; + + IconPackHelper(Context context) { + mContext = context; + mIconPackResources = new HashMap<String, String>(); + } + + public static Map<String, IconPackInfo> getSupportedPackages(Context context) { + Intent i = new Intent(); + Map<String, IconPackInfo> packages = new HashMap<String, IconPackInfo>(); + PackageManager packageManager = context.getPackageManager(); + for (String action : sSupportedActions) { + i.setAction(action); + for (ResolveInfo r : packageManager.queryIntentActivities(i, 0)) { + IconPackInfo info = new IconPackInfo(r, packageManager); + packages.put(r.activityInfo.packageName, info); + } + } + i = new Intent(Intent.ACTION_MAIN); + for (String category : sSupportedCategories) { + i.addCategory(category); + for (ResolveInfo r : packageManager.queryIntentActivities(i, 0)) { + IconPackInfo info = new IconPackInfo(r, packageManager); + packages.put(r.activityInfo.packageName, info); + } + i.removeCategory(category); + } + return packages; + } + + private static void loadResourcesFromXmlParser(XmlPullParser parser, + Map<String, String> iconPackResources) throws XmlPullParserException, IOException { + int eventType = parser.getEventType(); + do { + + if (eventType != XmlPullParser.START_TAG) { + continue; + } + + if (!parser.getName().equalsIgnoreCase("item")) { + continue; + } + + String component = parser.getAttributeValue(null, "component"); + String drawable = parser.getAttributeValue(null, "drawable"); + + // Validate component/drawable exist + if (TextUtils.isEmpty(component) || TextUtils.isEmpty(drawable)) { + continue; + } + + // Validate format/length of component + if (!component.startsWith("ComponentInfo{") || !component.endsWith("}") + || component.length() < 16) { + continue; + } + + // Sanitize stored value + component = component.substring(14, component.length() - 1).toLowerCase(); + + ComponentName name = null; + if (!component.contains("/")) { + // Package icon reference + iconPackResources.put(component, drawable); + } else { + name = ComponentName.unflattenFromString(component); + if (name != null) { + iconPackResources.put(name.getPackageName(), drawable); + iconPackResources.put(name.getClassName(), drawable); + } + } + } while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT); + } + + private static void loadApplicationResources(Context context, + Map<String, 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.toLowerCase(); + name = name.replaceAll("_", "."); + + iconPackResources.put(name, icon); + + int activityIndex = name.lastIndexOf("."); + if (activityIndex <= 0 || activityIndex == name.length() - 1) { + continue; + } + + String iconPackage = name.substring(0, activityIndex); + if (TextUtils.isEmpty(iconPackage)) { + continue; + } + iconPackResources.put(iconPackage, icon); + + String iconActivity = name.substring(activityIndex + 1); + if (TextUtils.isEmpty(iconActivity)) { + continue; + } + iconPackResources.put(iconPackage + "." + iconActivity, icon); + } + } + + public boolean loadIconPack(String packageName) { + mIconPackResources = getIconPackResources(mContext, packageName); + Resources res = null; + try { + res = mContext.getPackageManager().getResourcesForApplication(packageName); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return false; + } + mLoadedIconPackResource = res; + mLoadedIconPackName = packageName; + return true; + } + + public static Map<String, String> getIconPackResources(Context context, String packageName) { + if (TextUtils.isEmpty(packageName)) { + 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<String, String> iconPackResources = new HashMap<String, String>(); + + try { + inputStream = res.getAssets().open("appfilter.xml"); + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + parser = factory.newPullParser(); + parser.setInput(inputStream, "UTF-8"); + } catch (Exception e) { + // Catch any exception since we want to fall back to parsing the xml/ + // resource in all cases + int resId = res.getIdentifier("appfilter", "xml", packageName); + if (resId != 0) { + parser = res.getXml(resId); + } + } + + if (parser != null) { + try { + loadResourcesFromXmlParser(parser, iconPackResources); + return iconPackResources; + } catch (XmlPullParserException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + // Cleanup resources + if (parser instanceof XmlResourceParser) { + ((XmlResourceParser) parser).close(); + } + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + } + } + } + } + + // Application uses a different theme format (most likely launcher pro) + int arrayId = res.getIdentifier("theme_iconpack", "array", packageName); + if (arrayId == 0) { + arrayId = res.getIdentifier("icon_pack", "array", packageName); + } + + if (arrayId != 0) { + String[] iconPack = res.getStringArray(arrayId); + for (String entry : iconPack) { + + if (TextUtils.isEmpty(entry)) { + continue; + } + + String icon = entry.toLowerCase(); + entry = entry.replaceAll("_", "."); + + iconPackResources.put(entry, icon); + + int activityIndex = entry.lastIndexOf("."); + if (activityIndex <= 0 || activityIndex == entry.length() - 1) { + continue; + } + + String iconPackage = entry.substring(0, activityIndex); + if (TextUtils.isEmpty(iconPackage)) { + continue; + } + iconPackResources.put(iconPackage, icon); + + String iconActivity = entry.substring(activityIndex + 1); + if (TextUtils.isEmpty(iconActivity)) { + continue; + } + iconPackResources.put(iconPackage + "." + iconActivity, icon); + } + } else { + loadApplicationResources(context, iconPackResources, packageName); + } + return iconPackResources; + } + + public void unloadIconPack() { + mLoadedIconPackResource = null; + mLoadedIconPackName = null; + if (mIconPackResources != null) { + mIconPackResources.clear(); + } + } + + public static void pickIconPack(final Context context, final boolean pickIcon) { + Map<String, IconPackInfo> supportedPackages = getSupportedPackages(context); + if (supportedPackages.isEmpty()) { + Toast.makeText(context, R.string.no_iconpacks_summary, Toast.LENGTH_SHORT).show(); + return; + } + + final IconAdapter adapter = new IconAdapter(context, supportedPackages); + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.dialog_pick_iconpack_title); + if (!pickIcon) { + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int position) { + if (adapter.isOriginalIconPack(position)) { + return; + } + String selectedPackage = adapter.getItem(position); + SettingsProvider.putString(context, + SettingsProvider.SETTINGS_UI_GENERAL_ICONS_ICON_PACK, selectedPackage); + LauncherAppState.getInstance().getIconCache().flush(); + LauncherAppState.getInstance().getModel().forceReload(); + } + }); + } else { + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String selectedPackage = adapter.getItem(which); + Launcher launcherActivity = (Launcher) context; + if (TextUtils.isEmpty(selectedPackage)) { + launcherActivity.onActivityResult(Launcher.REQUEST_PICK_ICON, Activity.RESULT_OK, null); + } else { + Intent i = new Intent(); + i.setClass(context, IconPickerActivity.class); + i.putExtra(IconPickerActivity.PACKAGE_NAME_EXTRA, selectedPackage); + launcherActivity.startActivityForResult(i, Launcher.REQUEST_PICK_ICON); + } + } + }); + } + builder.show().getWindow().getDecorView().setAlpha(0.8f); + } + + boolean isIconPackLoaded() { + return mLoadedIconPackResource != null && + mLoadedIconPackName != null && + mIconPackResources != null; + } + + private int getResourceIdForDrawable(String resource) { + int resId = mLoadedIconPackResource.getIdentifier(resource, "drawable", mLoadedIconPackName); + return resId; + } + + public Resources getIconPackResources() { + return mLoadedIconPackResource; + } + + public int getResourceIdForActivityIcon(ActivityInfo info) { + String drawable = mIconPackResources.get(info.name.toLowerCase()); + if (drawable == null) { + // Icon pack doesn't have an icon for the activity, fallback to package icon + drawable = mIconPackResources.get(info.packageName.toLowerCase()); + if (drawable == null) { + return 0; + } + } + return getResourceIdForDrawable(drawable); + } + + static class IconPackInfo { + String packageName; + CharSequence label; + Drawable icon; + + IconPackInfo(ResolveInfo r, PackageManager packageManager) { + packageName = r.activityInfo.packageName; + icon = r.loadIcon(packageManager); + label = r.loadLabel(packageManager); + } + + IconPackInfo(){ + } + + public IconPackInfo(String label, Drawable icon, String packageName) { + this.label = label; + this.icon = icon; + this.packageName = packageName; + } + } + + private static class IconAdapter extends BaseAdapter { + ArrayList<IconPackInfo> mSupportedPackages; + LayoutInflater mLayoutInflater; + String mCurrentIconPack; + int mCurrentIconPackPosition; + + IconAdapter(Context ctx, Map<String, IconPackInfo> supportedPackages) { + mLayoutInflater = LayoutInflater.from(ctx); + mSupportedPackages = new ArrayList<IconPackInfo>(supportedPackages.values()); + Collections.sort(mSupportedPackages, new Comparator<IconPackInfo>() { + @Override + public int compare(IconPackInfo lhs, IconPackInfo rhs) { + return lhs.label.toString().compareToIgnoreCase(rhs.toString()); + } + }); + + Resources res = ctx.getResources(); + String defaultLabel = res.getString(R.string.default_iconpack_title); + Drawable icon = res.getDrawable(R.mipmap.ic_launcher_home); + mSupportedPackages.add(0, new IconPackInfo(defaultLabel, icon, "")); + + mCurrentIconPack = SettingsProvider.getStringCustomDefault(ctx, + SettingsProvider.SETTINGS_UI_GENERAL_ICONS_ICON_PACK, ""); + } + + @Override + public int getCount() { + return mSupportedPackages.size(); + } + + @Override + public String getItem(int position) { + return (String) mSupportedPackages.get(position).packageName; + } + + @Override + public long getItemId(int position) { + return 0; + } + + public boolean isOriginalIconPack(int position) { + return mCurrentIconPackPosition == position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = mLayoutInflater.inflate(R.layout.iconpack_chooser, null); + } + IconPackInfo info = mSupportedPackages.get(position); + TextView txtView = (TextView) convertView.findViewById(R.id.title); + txtView.setText(info.label); + ImageView imgView = (ImageView) convertView.findViewById(R.id.icon); + imgView.setImageDrawable(info.icon); + ImageView chk = (ImageView) convertView.findViewById(R.id.check); + boolean isCurrentIconPack = info.packageName.equals(mCurrentIconPack); + chk.setVisibility(isCurrentIconPack ? View.VISIBLE : View.GONE); + if (isCurrentIconPack) { + mCurrentIconPackPosition = position; + } + return convertView; + } + } + +}
\ No newline at end of file |