summaryrefslogtreecommitdiffstats
path: root/src/com/cyanogenmod
diff options
context:
space:
mode:
authorDanesh Mondegarian <daneshm90@gmail.com>2013-08-19 21:44:45 -0700
committerDanesh Mondegarian <daneshm90@gmail.com>2013-08-25 11:05:07 -0700
commit596b71d43c5f13f2d0199ffdfeaa550e15838783 (patch)
tree22e84ab3d2760ad86cae3eebfaba8f869815b72c /src/com/cyanogenmod
parentcad0342d7477efbb98227d10f73d7a1bfa7f2417 (diff)
downloadandroid_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')
-rw-r--r--src/com/cyanogenmod/trebuchet/IconCache.java19
-rw-r--r--src/com/cyanogenmod/trebuchet/IconPackHelper.java294
-rw-r--r--src/com/cyanogenmod/trebuchet/Launcher.java3
-rw-r--r--src/com/cyanogenmod/trebuchet/LauncherApplication.java6
-rw-r--r--src/com/cyanogenmod/trebuchet/preference/Preferences.java30
-rw-r--r--src/com/cyanogenmod/trebuchet/preference/PreferencesProvider.java14
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);
+ }
}
}