summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/IconPackHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/IconPackHelper.java')
-rw-r--r--src/com/android/launcher3/IconPackHelper.java440
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