diff options
author | Danesh Mondegarian <daneshm90@gmail.com> | 2013-08-19 21:44:45 -0700 |
---|---|---|
committer | Danesh Mondegarian <daneshm90@gmail.com> | 2013-08-25 11:05:07 -0700 |
commit | 596b71d43c5f13f2d0199ffdfeaa550e15838783 (patch) | |
tree | 22e84ab3d2760ad86cae3eebfaba8f869815b72c /src/com/cyanogenmod | |
parent | cad0342d7477efbb98227d10f73d7a1bfa7f2417 (diff) | |
download | android_packages_apps_Trebuchet-596b71d43c5f13f2d0199ffdfeaa550e15838783.tar.gz android_packages_apps_Trebuchet-596b71d43c5f13f2d0199ffdfeaa550e15838783.tar.bz2 android_packages_apps_Trebuchet-596b71d43c5f13f2d0199ffdfeaa550e15838783.zip |
Trebuchet : Icon pack theme
This patchset allows the user to set an icon pack
for the entire launcher.
Change-Id: I3dc8311f7e0a7a4f174fd568aa1d74b5ceb8471a
Diffstat (limited to 'src/com/cyanogenmod')
6 files changed, 361 insertions, 5 deletions
diff --git a/src/com/cyanogenmod/trebuchet/IconCache.java b/src/com/cyanogenmod/trebuchet/IconCache.java index 2715a784d..7f4b13594 100644 --- a/src/com/cyanogenmod/trebuchet/IconCache.java +++ b/src/com/cyanogenmod/trebuchet/IconCache.java @@ -27,9 +27,12 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.Drawable; +import android.text.TextUtils; import java.util.HashMap; +import com.cyanogenmod.trebuchet.preference.PreferencesProvider; + /** * Cache of application icons. Icons can be made from any thread. */ @@ -38,6 +41,7 @@ public class IconCache { private static final String TAG = "Trebuchet.IconCache"; private static final int INITIAL_ICON_CACHE_CAPACITY = 50; + private IconPackHelper mIconPackHelper; private static class CacheEntry { public Bitmap icon; @@ -61,6 +65,12 @@ public class IconCache { // need to set mIconDpi before getting default icon mDefaultIcon = makeDefaultIcon(); + + String iconPack = PreferencesProvider.Interface.General.getIconPack(); + if (!TextUtils.isEmpty(iconPack)) { + mIconPackHelper = new IconPackHelper(context); + mIconPackHelper.loadIconPack(iconPack); + } } public Drawable getFullResDefaultActivityIcon() { @@ -108,7 +118,14 @@ public class IconCache { resources = null; } if (resources != null) { - int iconId = info.getIconResource(); + 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 new file mode 100644 index 000000000..228ea2c88 --- /dev/null +++ b/src/com/cyanogenmod/trebuchet/IconPackHelper.java @@ -0,0 +1,294 @@ +package com.cyanogenmod.trebuchet; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +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.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.Resources.NotFoundException; +import android.content.res.XmlResourceParser; +import android.text.TextUtils; +import android.widget.Toast; + +import com.cyanogenmod.trebuchet.preference.PreferencesProvider; + +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" + }; + + private final Context mContext; + private Map<ComponentName, String> mIconPackResources; + private String mLoadedIconPackName; + private Resources mLoadedIconPackResource; + + IconPackHelper(Context context) { + mContext = context; + mIconPackResources = new HashMap<ComponentName, String>(); + } + + public static HashMap<CharSequence, String> getSupportedPackages(Context context) { + Intent i = new Intent(); + HashMap<CharSequence, String> packages = new HashMap<CharSequence, String>(); + PackageManager packageManager = context.getPackageManager(); + for (String action : sSupportedActions) { + i.setAction(action); + for (ResolveInfo r : packageManager.queryIntentActivities(i, 0)) { + packages.put(r.loadLabel(packageManager), r.activityInfo.packageName); + } + } + i = new Intent(Intent.ACTION_MAIN); + for (String category : sSupportedCategories) { + i.addCategory(category); + for (ResolveInfo r : packageManager.queryIntentActivities(i, 0)) { + packages.put(r.loadLabel(packageManager), r.activityInfo.packageName); + } + i.removeCategory(category); + } + return packages; + } + + private void loadResourcesFromXmlParser(XmlPullParser parser) throws XmlPullParserException, IOException { + int eventType = parser.getEventType(); + mIconPackResources.clear(); + 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 || drawable.length() == 0) { + continue; + } + + // Sanitize stored value + component = component.substring(14, component.length() - 1).toLowerCase(); + + ComponentName name = null; + if (!component.contains("/")) { + // Package icon reference + name = new ComponentName(component.toLowerCase(), ""); + } else { + name = ComponentName.unflattenFromString(component); + } + + if (name != null) { + mIconPackResources.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)) { + return; + } + + Resources res = null; + try { + res = mContext.getPackageManager().getResourcesForApplication(packageName); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return; + } + + XmlPullParser parser = null; + InputStream inputStream = null; + + try { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + inputStream = res.getAssets().open("appfilter.xml"); + 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); + mLoadedIconPackResource = res; + mLoadedIconPackName = packageName; + return; + } catch (XmlPullParserException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + // Cleanup resources + if (parser instanceof XmlResourceParser) { + ((XmlResourceParser) parser).close(); + } else 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) { + return; + } + } + + String[] iconPack = res.getStringArray(arrayId); + ComponentName compName = null; + mIconPackResources.clear(); + for (String entry : iconPack) { + + if (TextUtils.isEmpty(entry)) { + continue; + } + + String icon = entry; + entry = entry.replaceAll("_", "."); + + compName = new ComponentName(entry.toLowerCase(), ""); + mIconPackResources.put(compName, icon); + + int activityIndex = entry.lastIndexOf("."); + if (activityIndex <= 0 || activityIndex == entry.length() - 1) { + continue; + } + + String iconPackage = entry.substring(0, activityIndex); + if (TextUtils.isEmpty(iconPackage)) { + 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(); + + iconActivity = iconPackage + "." + iconActivity; + compName = new ComponentName(iconPackage, iconActivity); + mIconPackResources.put(compName, icon); + } + mLoadedIconPackResource = res; + mLoadedIconPackName = packageName; + } + + public static void pickIconPack(final Context context) { + final HashMap<CharSequence, String> supportedPackages = getSupportedPackages(context); + + final CharSequence[] dialogEntries = new CharSequence[supportedPackages.size() + 1]; + supportedPackages.keySet().toArray(dialogEntries); + + final String defaultIcons = context.getResources().getString(R.string.default_iconpack_title); + dialogEntries[dialogEntries.length - 1] = defaultIcons; + Arrays.sort(dialogEntries); + + String iconPack = PreferencesProvider.Interface.General.getIconPack(); + + int selectedIndex = -1; + int defaultIndex = 0; + for (int i = 0; i < dialogEntries.length; i++) { + CharSequence appLabel = dialogEntries[i]; + if (appLabel.equals(defaultIcons)) { + defaultIndex = i; + } else if (supportedPackages.get(appLabel).equals(iconPack)) { + selectedIndex = i; + break; + } + } + + // Icon pack either uninstalled or + // user had selected default icons + if (selectedIndex == -1) { + selectedIndex = defaultIndex; + } + + 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)); + } + dialog.dismiss(); + } + }); + builder.show(); + } + + boolean isIconPackLoaded() { + return mLoadedIconPackResource != null && + mLoadedIconPackName != 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) { + ComponentName compName = new ComponentName(info.packageName.toLowerCase(), info.name.toLowerCase()); + String drawable = mIconPackResources.get(compName); + if (drawable == null) { + // Icon pack doesn't have an icon for the activity, fallback to package icon + compName = new ComponentName(info.packageName.toLowerCase(), ""); + drawable = mIconPackResources.get(compName); + if (drawable == null) { + return 0; + } + } + return getResourceIdForDrawable(drawable); + } + +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/trebuchet/Launcher.java b/src/com/cyanogenmod/trebuchet/Launcher.java index 26084f5ff..08e67cc57 100644 --- a/src/com/cyanogenmod/trebuchet/Launcher.java +++ b/src/com/cyanogenmod/trebuchet/Launcher.java @@ -389,9 +389,6 @@ public final class Launcher extends Activity mInflater = getLayoutInflater(); final Resources res = getResources(); - // Load all preferences - PreferencesProvider.load(this); - mAppWidgetManager = AppWidgetManager.getInstance(this); mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); mAppWidgetHost.startListening(); diff --git a/src/com/cyanogenmod/trebuchet/LauncherApplication.java b/src/com/cyanogenmod/trebuchet/LauncherApplication.java index 56fc842ba..c82393863 100644 --- a/src/com/cyanogenmod/trebuchet/LauncherApplication.java +++ b/src/com/cyanogenmod/trebuchet/LauncherApplication.java @@ -27,6 +27,7 @@ import android.database.ContentObserver; import android.os.Handler; import com.cyanogenmod.trebuchet.R; +import com.cyanogenmod.trebuchet.preference.PreferencesProvider; import java.lang.ref.WeakReference; @@ -48,6 +49,9 @@ public class LauncherApplication extends Application { sIsScreenLarge = getResources().getBoolean(R.bool.is_large_screen); sScreenDensity = getResources().getDisplayMetrics().density; + // Load all preferences + PreferencesProvider.load(this); + mWidgetPreviewCacheDb = new WidgetPreviewLoader.CacheDb(this); mIconCache = new IconCache(this); mModel = new LauncherModel(this, mIconCache); @@ -108,7 +112,7 @@ public class LauncherApplication extends Application { return mModel; } - IconCache getIconCache() { + public IconCache getIconCache() { return mIconCache; } diff --git a/src/com/cyanogenmod/trebuchet/preference/Preferences.java b/src/com/cyanogenmod/trebuchet/preference/Preferences.java index cf90b170a..f2fcec8be 100644 --- a/src/com/cyanogenmod/trebuchet/preference/Preferences.java +++ b/src/com/cyanogenmod/trebuchet/preference/Preferences.java @@ -23,6 +23,7 @@ import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; import android.text.TextUtils; import android.view.MenuItem; import android.view.LayoutInflater; @@ -33,6 +34,7 @@ import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.TextView; +import com.cyanogenmod.trebuchet.IconPackHelper; import com.cyanogenmod.trebuchet.LauncherApplication; import com.cyanogenmod.trebuchet.R; @@ -161,11 +163,39 @@ public class Preferences extends PreferenceActivity } public static class GeneralFragment extends PreferenceFragment { + private static final String ICON_PACK_KEY = "ui_general_iconpack"; + private Preference mIconPackPreference; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences_general); + mIconPackPreference = findPreference(ICON_PACK_KEY); + } + + @Override + public void onResume() { + int numIconPacks = IconPackHelper.getSupportedPackages( + getActivity()).size(); + if (numIconPacks > 0) { + mIconPackPreference.setSummary( + R.string.preferences_interface_general_iconpack_summary); + mIconPackPreference.setEnabled(true); + } else { + mIconPackPreference.setSummary(R.string.no_iconpacks_summary); + mIconPackPreference.setEnabled(false); + } + super.onResume(); + } + + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, + Preference preference) { + if (preference.getKey().equals("ui_general_iconpack")) { + IconPackHelper.pickIconPack(getActivity()); + } + return super.onPreferenceTreeClick(preferenceScreen, preference); } } diff --git a/src/com/cyanogenmod/trebuchet/preference/PreferencesProvider.java b/src/com/cyanogenmod/trebuchet/preference/PreferencesProvider.java index 9f61f8224..cd88bb5fd 100644 --- a/src/com/cyanogenmod/trebuchet/preference/PreferencesProvider.java +++ b/src/com/cyanogenmod/trebuchet/preference/PreferencesProvider.java @@ -61,6 +61,14 @@ public final class PreferencesProvider { (String) sKeyValues.get(key) : def; } + private static void setString(Context ctx, String key, String value) { + SharedPreferences preferences = ctx.getSharedPreferences(PREFERENCES_KEY, 0); + Editor editor = preferences.edit(); + editor.putString(key, value); + editor.apply(); // For better performance + sKeyValues.put(key, value); + } + public static class Interface { public static class Homescreen { public static int getNumberHomescreens() { @@ -231,6 +239,12 @@ public final class PreferencesProvider { public static boolean getFullscreenMode() { return getBoolean("ui_general_fullscreen", false); } + public static String getIconPack() { + return getString("ui_general_iconpack", ""); + } + public static void setIconPack(Context ctx, String packageName) { + setString(ctx, "ui_general_iconpack", packageName); + } } } |