summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/drawable-hdpi/ic_iconpacks.pngbin0 -> 1045 bytes
-rw-r--r--res/drawable-hdpi/ic_widget.pngbin1560 -> 410 bytes
-rw-r--r--res/drawable-mdpi/ic_iconpacks.pngbin0 -> 769 bytes
-rw-r--r--res/drawable-mdpi/ic_widget.pngbin1174 -> 370 bytes
-rw-r--r--res/drawable-xhdpi/ic_iconpacks.pngbin0 -> 1430 bytes
-rw-r--r--res/drawable-xhdpi/ic_widget.pngbin1978 -> 498 bytes
-rw-r--r--res/drawable-xxhdpi/ic_iconpacks.pngbin0 -> 2146 bytes
-rw-r--r--res/drawable-xxhdpi/ic_widget.pngbin2413 -> 555 bytes
-rw-r--r--res/layout/iconpack_chooser.xml28
-rw-r--r--res/layout/overview_panel.xml23
-rw-r--r--res/values/cm_strings.xml4
-rw-r--r--src/com/android/launcher3/IconCache.java27
-rw-r--r--src/com/android/launcher3/IconPackHelper.java440
-rw-r--r--src/com/android/launcher3/IconPickerActivity.java152
-rw-r--r--src/com/android/launcher3/Launcher.java18
-rw-r--r--src/com/android/launcher3/LauncherModel.java2
-rw-r--r--src/com/android/launcher3/settings/SettingsProvider.java5
17 files changed, 694 insertions, 5 deletions
diff --git a/res/drawable-hdpi/ic_iconpacks.png b/res/drawable-hdpi/ic_iconpacks.png
new file mode 100644
index 000000000..7985c1847
--- /dev/null
+++ b/res/drawable-hdpi/ic_iconpacks.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_widget.png b/res/drawable-hdpi/ic_widget.png
index 8c57af0de..e7cc5346a 100644
--- a/res/drawable-hdpi/ic_widget.png
+++ b/res/drawable-hdpi/ic_widget.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_iconpacks.png b/res/drawable-mdpi/ic_iconpacks.png
new file mode 100644
index 000000000..36e35c215
--- /dev/null
+++ b/res/drawable-mdpi/ic_iconpacks.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_widget.png b/res/drawable-mdpi/ic_widget.png
index 5f974c28c..955ebf5b7 100644
--- a/res/drawable-mdpi/ic_widget.png
+++ b/res/drawable-mdpi/ic_widget.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_iconpacks.png b/res/drawable-xhdpi/ic_iconpacks.png
new file mode 100644
index 000000000..207d68a35
--- /dev/null
+++ b/res/drawable-xhdpi/ic_iconpacks.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_widget.png b/res/drawable-xhdpi/ic_widget.png
index 47dcdd14f..fae347ba7 100644
--- a/res/drawable-xhdpi/ic_widget.png
+++ b/res/drawable-xhdpi/ic_widget.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_iconpacks.png b/res/drawable-xxhdpi/ic_iconpacks.png
new file mode 100644
index 000000000..d1aea29da
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_iconpacks.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_widget.png b/res/drawable-xxhdpi/ic_widget.png
index fddfecaa3..3bdb42d5e 100644
--- a/res/drawable-xxhdpi/ic_widget.png
+++ b/res/drawable-xxhdpi/ic_widget.png
Binary files differ
diff --git a/res/layout/iconpack_chooser.xml b/res/layout/iconpack_chooser.xml
new file mode 100644
index 000000000..6caf9f765
--- /dev/null
+++ b/res/layout/iconpack_chooser.xml
@@ -0,0 +1,28 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_gravity="center_vertical"
+ android:layout_width="@dimen/app_icon_size"
+ android:layout_height="@dimen/app_icon_size"
+ android:layout_margin="8dp"/>
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:paddingStart="8dip"
+ android:paddingEnd="8dip"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+ <ImageView
+ android:src="@*android:drawable/ic_cab_done_holo_dark"
+ android:id="@+id/check"
+ android:layout_gravity="center_vertical"
+ android:layout_width="@dimen/app_icon_size"
+ android:layout_height="@dimen/app_icon_size"
+ android:layout_margin="8dp"/>
+
+</LinearLayout>
diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml
index fad5ebe18..dd33cfb97 100644
--- a/res/layout/overview_panel.xml
+++ b/res/layout/overview_panel.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -28,7 +28,8 @@
<TextView
android:id="@+id/default_screen_button"
- android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/overview_panel_button_spacing"
android:paddingRight="@dimen/overview_panel_button_spacing"
@@ -42,7 +43,8 @@
<TextView
android:id="@+id/transition_effect_button"
- android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/overview_panel_button_spacing"
android:paddingRight="@dimen/overview_panel_button_spacing"
@@ -54,6 +56,21 @@
android:textAllCaps="true"
android:textSize="12sp" />
+ <TextView
+ android:id="@+id/icon_pack_button"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/overview_panel_button_spacing"
+ android:paddingRight="@dimen/overview_panel_button_spacing"
+ android:text="@string/icon_packs_title"
+ android:drawablePadding="4dp"
+ android:drawableTop="@drawable/ic_iconpacks"
+ android:gravity="center_horizontal"
+ android:fontFamily="sans-serif-condensed"
+ android:textAllCaps="true"
+ android:textSize="12sp" />
+
</LinearLayout>
<LinearLayout
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index f8583867a..952f5c288 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -54,4 +54,8 @@
<string name="preferences_interface_general_icons_large_summary">Use extra large application icons in homescreen and drawer</string>
<string name="preferences_interface_general_icons_text_style_title">Text font style</string>
<string name="preferences_interface_general_icons_text_style_summary">Variant and style of font to use for icon text</string>
+ <string name="dialog_pick_iconpack_title">Pick icon pack</string>
+ <string name="default_iconpack_title">Default icons</string>
+ <string name="icon_packs_title">Icon packs</string>
+ <string name="no_iconpacks_summary">No icon packs installed</string>
</resources>
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 543b8ee2d..b4bb5b9c3 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -27,11 +27,14 @@ 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 java.util.Iterator;
import java.util.Map.Entry;
+import com.android.launcher3.settings.SettingsProvider;
+
/**
* Cache of application icons. Icons can be made from any thread.
*/
@@ -40,6 +43,7 @@ public class IconCache {
private static final String TAG = "Launcher.IconCache";
private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
+ private IconPackHelper mIconPackHelper;
private static class CacheEntry {
public Bitmap icon;
@@ -63,6 +67,9 @@ public class IconCache {
// need to set mIconDpi before getting default icon
mDefaultIcon = makeDefaultIcon();
+
+ mIconPackHelper = new IconPackHelper(context);
+ loadIconPack();
}
public Drawable getFullResDefaultActivityIcon() {
@@ -110,7 +117,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);
}
@@ -130,6 +144,16 @@ public class IconCache {
return b;
}
+ private void loadIconPack() {
+ mIconPackHelper.unloadIconPack();
+ String iconPack = SettingsProvider.getStringCustomDefault(mContext,
+ SettingsProvider.SETTINGS_UI_GENERAL_ICONS_ICON_PACK, "");
+ if (!TextUtils.isEmpty(iconPack) && !mIconPackHelper.loadIconPack(iconPack)) {
+ SettingsProvider.putString(mContext,
+ SettingsProvider.SETTINGS_UI_GENERAL_ICONS_ICON_PACK, "");
+ }
+ }
+
/**
* Remove any records for the supplied ComponentName.
*/
@@ -146,6 +170,7 @@ public class IconCache {
synchronized (mCache) {
mCache.clear();
}
+ loadIconPack();
}
/**
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
diff --git a/src/com/android/launcher3/IconPickerActivity.java b/src/com/android/launcher3/IconPickerActivity.java
new file mode 100644
index 000000000..5f08eda68
--- /dev/null
+++ b/src/com/android/launcher3/IconPickerActivity.java
@@ -0,0 +1,152 @@
+package com.android.launcher3;
+
+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";
+ public static final String PACKAGE_NAME_EXTRA = "package";
+
+ @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_NAME_EXTRA);
+
+ 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<String, 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/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0084b7182..e88109aef 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -152,6 +152,7 @@ public class Launcher extends Activity
private static final int REQUEST_PICK_WALLPAPER = 10;
private static final int REQUEST_BIND_APPWIDGET = 11;
+ static final int REQUEST_PICK_ICON = 13;
/**
* IntentStarter uses request codes starting with this. This must be greater than all activity
@@ -1383,6 +1384,15 @@ public class Launcher extends Activity
});
transitionEffectButton.setOnTouchListener(getHapticFeedbackTouchListener());
+ View iconPackButton = findViewById(R.id.icon_pack_button);
+ iconPackButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ IconPackHelper.pickIconPack(Launcher.this, false);
+ }
+ });
+ iconPackButton.setOnTouchListener(getHapticFeedbackTouchListener());
+
View sortButton = findViewById(R.id.sort_button);
sortButton.setOnClickListener(new OnClickListener() {
@Override
@@ -2914,6 +2924,7 @@ public class Launcher extends Activity
View wallpaperButton = mOverviewPanel.findViewById(R.id.wallpaper_button);
View sortButton = mOverviewPanel.findViewById(R.id.sort_button);
View filterButton = mOverviewPanel.findViewById(R.id.filter_button);
+ View iconPackButton = findViewById(R.id.icon_pack_button);
PagedView pagedView = !isAllAppsVisible() ? mWorkspace : mAppsCustomizeContent;
@@ -2926,6 +2937,13 @@ public class Launcher extends Activity
// filterButton.setVisibility(isAllAppsVisible() ? View.VISIBLE : View.GONE);
filterButton.setVisibility(View.GONE);
+ boolean isVisible = !isAllAppsVisible();
+ if (isVisible) {
+ int numIconPacks = IconPackHelper.getSupportedPackages(this).size();
+ isVisible = numIconPacks > 0;
+ }
+ iconPackButton.setVisibility(isVisible ? View.VISIBLE : View.GONE);
+
// Make sure overview panel is drawn above apps customize
mOverviewPanel.bringToFront();
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 00b6fbb8e..70b6d55b1 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -1164,7 +1164,7 @@ public class LauncherModel extends BroadcastReceiver {
}
}
- private void forceReload() {
+ void forceReload() {
resetLoadedState(true, true);
// Do this here because if the launcher activity is running it will be restarted.
diff --git a/src/com/android/launcher3/settings/SettingsProvider.java b/src/com/android/launcher3/settings/SettingsProvider.java
index 501a7ea73..8bf726646 100644
--- a/src/com/android/launcher3/settings/SettingsProvider.java
+++ b/src/com/android/launcher3/settings/SettingsProvider.java
@@ -35,6 +35,7 @@ public final class SettingsProvider {
public static final String SETTINGS_UI_GENERAL_ICONS_LARGE = "ui_general_icons_large";
public static final String SETTINGS_UI_GENERAL_ICONS_TEXT_FONT_FAMILY = "ui_general_icons_text_font";
public static final String SETTINGS_UI_GENERAL_ICONS_TEXT_FONT_STYLE = "ui_general_icons_text_font_style";
+ public static final String SETTINGS_UI_GENERAL_ICONS_ICON_PACK = "ui_general_iconpack";
public static SharedPreferences get(Context context) {
return context.getSharedPreferences(SETTINGS_KEY, Context.MODE_MULTI_PROCESS);
@@ -71,4 +72,8 @@ public final class SettingsProvider {
public static String getString(Context context, String key, int resource) {
return getStringCustomDefault(context, key, context.getResources().getString(resource));
}
+
+ public static void putString(Context context, String key, String value) {
+ get(context).edit().putString(key, value).commit();
+ }
}