summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/org/cyanogenmod/themes/provider/PreviewGenerationService.java21
-rw-r--r--src/org/cyanogenmod/themes/provider/ThemePackageHelper.java67
-rw-r--r--src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java56
-rw-r--r--src/org/cyanogenmod/themes/provider/ThemesProvider.java9
-rw-r--r--src/org/cyanogenmod/themes/provider/util/BitmapUtils.java25
-rw-r--r--src/org/cyanogenmod/themes/provider/util/SystemUiPreviewGenerator.java50
6 files changed, 219 insertions, 9 deletions
diff --git a/src/org/cyanogenmod/themes/provider/PreviewGenerationService.java b/src/org/cyanogenmod/themes/provider/PreviewGenerationService.java
index 99b40f5..e4dc14e 100644
--- a/src/org/cyanogenmod/themes/provider/PreviewGenerationService.java
+++ b/src/org/cyanogenmod/themes/provider/PreviewGenerationService.java
@@ -74,6 +74,7 @@ public class PreviewGenerationService extends IntentService {
final Bundle extras = intent.getExtras();
String pkgName = extras.getString(EXTRA_PKG_NAME);
boolean hasSystemUi = false;
+ boolean hasHeaders = false;
boolean hasIcons = false;
boolean hasWallpaper = false;
boolean hasStyles = false;
@@ -86,7 +87,9 @@ public class PreviewGenerationService extends IntentService {
// mods_status_bar was added in version 7 of the database so we need to make sure
// it exists when trying to get the int value from the row.
final int sysUiIndex = c.getColumnIndex(ThemesColumns.MODIFIES_STATUS_BAR);
+ final int headersIndex = c.getColumnIndex(ThemesColumns.MODIFIES_STATUSBAR_HEADERS);
hasSystemUi = sysUiIndex >= 0 && c.getInt(sysUiIndex) == 1;
+ hasHeaders = headersIndex >= 0 && c.getInt(headersIndex) == 1;
hasIcons = c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_ICONS)) == 1;
hasWallpaper = c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_LAUNCHER)) == 1 ||
c.getInt(c.getColumnIndex(ThemesColumns.MODIFIES_LOCKSCREEN)) == 1;
@@ -116,7 +119,7 @@ public class PreviewGenerationService extends IntentService {
SystemUiItems items = null;
try {
- items = !hasSystemUi ? null :
+ items = (!hasSystemUi && !hasHeaders) ? null :
new SystemUiPreviewGenerator(this).generateSystemUiItems(pkgName);
} catch (Exception e) {
Log.e(TAG, "Unable to create statusbar previews for " + pkgName, e);
@@ -267,6 +270,22 @@ public class PreviewGenerationService extends IntentService {
values = createPreviewEntryString(id, PreviewColumns.NAVBAR_RECENT_BUTTON,
path);
themeValues.add(values);
+
+ path = PreviewUtils.compressAndSavePng(items.headerMorning, filesDir, pkgName,
+ PreviewColumns.HEADER_PREVIEW_1);
+ values = createPreviewEntryString(id, PreviewColumns.HEADER_PREVIEW_1, path);
+ themeValues.add(values);
+
+ path = PreviewUtils.compressAndSavePng(items.headerNoon, filesDir, pkgName,
+ PreviewColumns.HEADER_PREVIEW_2);
+ values = createPreviewEntryString(id, PreviewColumns.HEADER_PREVIEW_2, path);
+ themeValues.add(values);
+
+ path = PreviewUtils.compressAndSavePng(items.headerEvening, filesDir, pkgName,
+ PreviewColumns.HEADER_PREVIEW_3);
+ values = createPreviewEntryString(id, PreviewColumns.HEADER_PREVIEW_3,
+ path);
+ themeValues.add(values);
}
if (icons != null) {
path = PreviewUtils.compressAndSavePng(icons.icon1, filesDir, pkgName,
diff --git a/src/org/cyanogenmod/themes/provider/ThemePackageHelper.java b/src/org/cyanogenmod/themes/provider/ThemePackageHelper.java
index 5479229..1e75212 100644
--- a/src/org/cyanogenmod/themes/provider/ThemePackageHelper.java
+++ b/src/org/cyanogenmod/themes/provider/ThemePackageHelper.java
@@ -41,10 +41,14 @@ import org.cyanogenmod.internal.util.ThemeUtils;
import org.cyanogenmod.themes.provider.util.ProviderUtils;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import static android.content.res.ThemeConfig.SYSTEMUI_STATUSBAR_HEADER_PKG;
import static android.content.res.ThemeConfig.SYSTEMUI_NAVBAR_PKG;
import static android.content.res.ThemeConfig.SYSTEMUI_STATUS_BAR_PKG;
import static android.content.res.ThemeConfig.SYSTEM_DEFAULT;
@@ -73,6 +77,19 @@ public class ThemePackageHelper {
"overlays/com.android.systemui");
sComponentToFolderName.put(ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN,
"live-lockscreen");
+ sComponentToFolderName.put(ThemesColumns.MODIFIES_STATUSBAR_HEADERS,
+ "overlays/com.android.systemui");
+ }
+
+ // allow theme to explicitly declare what components to show by listing desired
+ // components in a string array in package resources. Currently only "headers"
+ // is supported but soon "navbar" will also be supported
+ public static final String THEME_PACKAGE_WHITELIST = "theme_component_whitelist";
+
+ // map theme whitelist component names to theme column
+ public static HashMap<String, String> sComponentWhitelist = new HashMap<String, String>();
+ static {
+ sComponentWhitelist.put("headers", ThemesColumns.MODIFIES_STATUSBAR_HEADERS);
}
public static boolean insertPackage(Context context, String pkgName, boolean isProcessing)
@@ -320,9 +337,56 @@ public class ThemePackageHelper {
boolean hasComponent = hasThemeComponent(themeContext, folderName);
implementMap.put(component, hasComponent);
}
+
+ // populate map first then pass through whitelist filter
+ filterWhitelistCapabilities(themeContext, implementMap);
return implementMap;
}
+ private static void filterWhitelistCapabilities(Context themeContext,
+ Map<String, Boolean> capabilities) {
+ List<String> items = null;
+ try {
+ int id = themeContext.getResources().getIdentifier(THEME_PACKAGE_WHITELIST,
+ "array",
+ themeContext.getPackageName());
+ items = Arrays.asList(themeContext.getResources().getStringArray(id));
+ } catch (Exception e) {
+ Log.e(TAG, "Theme whitelist not supported for " + themeContext.getPackageName());
+ }
+ if (items != null && items.size() > 0) {
+ // validate entries against authorized whitelist elements
+ Log.e(TAG, "Theme whitelist found for " + themeContext.getPackageName() + " Elements: "
+ + items.toString());
+ List<String> toRemove = new ArrayList<String>();
+ for (String component : items) {
+ if (!sComponentWhitelist.containsKey(component)) {
+ toRemove.add(component);
+ Log.e(TAG,
+ "Unsupported whitelist element found in "
+ + themeContext.getPackageName() + " Elements: "
+ + component.toString());
+ }
+ }
+ items.removeAll(toRemove);
+ if (items.size() > 0) {
+ Log.e(TAG, "Whitelist elements validated in " + themeContext.getPackageName()
+ + " Elements: " + items.toString() + " Disabling all other components");
+ // set everything to false
+ for (Map.Entry<String, Boolean> entry : capabilities.entrySet()) {
+ String component = entry.getKey();
+ Boolean isImplemented = false;
+ capabilities.put(component, isImplemented);
+ }
+ for (String component : items) {
+ String entry = sComponentWhitelist.get(component);
+ Boolean isImplemented = true;
+ capabilities.put(entry, isImplemented);
+ }
+ }
+ }
+ }
+
private static void insertCapabilities(Map<String, Boolean> capabilities,
ContentValues values) {
for (Map.Entry<String, Boolean> entry : capabilities.entrySet()) {
@@ -381,6 +445,9 @@ public class ThemePackageHelper {
if (pkgName.equals(themeConfig.getOverlayPkgNameForApp(SYSTEMUI_NAVBAR_PKG))) {
builder.setNavBar(pkgName);
}
+ if (pkgName.equals(themeConfig.getOverlayPkgNameForApp(SYSTEMUI_STATUSBAR_HEADER_PKG))) {
+ builder.setHeaders(pkgName);
+ }
// Check if there are any per-app overlays using this theme
final Map<String, ThemeConfig.AppTheme> themes = themeConfig.getAppThemes();
diff --git a/src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java b/src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java
index d70ad50..003e9f3 100644
--- a/src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java
+++ b/src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java
@@ -38,7 +38,7 @@ import org.cyanogenmod.internal.util.ThemeUtils;
public class ThemesOpenHelper extends SQLiteOpenHelper {
private static final String TAG = ThemesOpenHelper.class.getName();
- private static final int DATABASE_VERSION = 20;
+ private static final int DATABASE_VERSION = 21;
private static final String DATABASE_NAME = "themes.db";
private static final String SYSTEM_THEME_PKG_NAME = ThemeConfig.SYSTEM_DEFAULT;
private static final String OLD_SYSTEM_THEME_PKG_NAME = "holo";
@@ -138,6 +138,10 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
upgradeToVersion20(db);
oldVersion = 20;
}
+ if (oldVersion == 20) {
+ upgradeToVersion21(db);
+ oldVersion = 21;
+ }
if (oldVersion != DATABASE_VERSION) {
Log.e(TAG, "Recreating db because unknown database version: " + oldVersion);
dropTables(db);
@@ -497,6 +501,47 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
SYSTEM_THEME_PKG_NAME));
}
+ private void upgradeToVersion21(SQLiteDatabase db) {
+ String sql = String.format("ALTER TABLE %s ADD COLUMN %s INTEGER",
+ ThemesTable.TABLE_NAME, ThemesColumns.MODIFIES_STATUSBAR_HEADERS);
+ db.execSQL(sql);
+
+ // we need to update any existing themes
+ final String[] projection = {
+ ThemesColumns.PKG_NAME
+ };
+ final String selection = ThemesColumns.MODIFIES_STATUS_BAR + "=?";
+ final String[] selectionArgs = {
+ "1"
+ };
+ final Cursor c = db.query(ThemesTable.TABLE_NAME, projection, selection, selectionArgs,
+ null, null, null);
+ if (c != null) {
+ while (c.moveToNext()) {
+ final String pkgName = c.getString(0);
+ boolean hasSystemUi = false;
+ try {
+ Context themeContext = mContext.createPackageContext(pkgName, 0);
+ hasSystemUi = ThemePackageHelper.hasThemeComponent(themeContext,
+ ThemePackageHelper.sComponentToFolderName.get(
+ ThemesColumns.MODIFIES_STATUS_BAR));
+ } catch (PackageManager.NameNotFoundException e) {
+ // default to false
+ }
+ if (hasSystemUi) {
+ db.execSQL(String.format("UPDATE %s SET %s='1'", ThemesTable.TABLE_NAME,
+ ThemesColumns.MODIFIES_STATUSBAR_HEADERS, ThemesColumns.PKG_NAME,
+ pkgName));
+ Intent intent = new Intent(mContext, PreviewGenerationService.class);
+ intent.setAction(PreviewGenerationService.ACTION_INSERT);
+ intent.putExtra(PreviewGenerationService.EXTRA_PKG_NAME, pkgName);
+ mContext.startService(intent);
+ }
+ }
+ c.close();
+ }
+ }
+
private void dropTables(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + ThemesTable.TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS " + MixnMatchTable.TABLE_NAME);
@@ -535,6 +580,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
ThemesColumns.MODIFIES_STATUS_BAR + " INTEGER DEFAULT 0, " +
ThemesColumns.MODIFIES_NAVIGATION_BAR + " INTEGER DEFAULT 0, " +
ThemesColumns.MODIFIES_LIVE_LOCK_SCREEN + " INTEGER DEFAULT 0, " +
+ ThemesColumns.MODIFIES_STATUSBAR_HEADERS + " INTEGER DEFAULT 0, " +
ThemesColumns.PRESENT_AS_THEME + " INTEGER DEFAULT 0, " +
ThemesColumns.IS_LEGACY_THEME + " INTEGER DEFAULT 0, " +
ThemesColumns.IS_DEFAULT_THEME + " INTEGER DEFAULT 0, " +
@@ -563,6 +609,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
values.put(ThemesColumns.MODIFIES_RINGTONES, 1);
values.put(ThemesColumns.MODIFIES_STATUS_BAR, 1);
values.put(ThemesColumns.MODIFIES_NAVIGATION_BAR, 1);
+ values.put(ThemesColumns.MODIFIES_STATUSBAR_HEADERS, 1);
values.put(ThemesColumns.PRESENT_AS_THEME, 1);
values.put(ThemesColumns.IS_LEGACY_THEME, 0);
values.put(ThemesColumns.IS_DEFAULT_THEME, isDefault);
@@ -634,6 +681,11 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
PreviewColumns.NAVBAR_RECENT_BUTTON,
PreviewColumns.NAVBAR_BACKGROUND
};
+ public static final String[] STATUSBAR_HEADERS_PREVIEW_KEYS = {
+ PreviewColumns.HEADER_PREVIEW_1,
+ PreviewColumns.HEADER_PREVIEW_2,
+ PreviewColumns.HEADER_PREVIEW_3
+ };
public static final String[] ICON_PREVIEW_KEYS = {
PreviewColumns.ICON_PREVIEW_1,
PreviewColumns.ICON_PREVIEW_2,
@@ -653,5 +705,3 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
return ThemeConfig.SYSTEM_DEFAULT == ThemeUtils.getDefaultThemePackageName(context);
}
}
-
-
diff --git a/src/org/cyanogenmod/themes/provider/ThemesProvider.java b/src/org/cyanogenmod/themes/provider/ThemesProvider.java
index 61828fb..1a916a6 100644
--- a/src/org/cyanogenmod/themes/provider/ThemesProvider.java
+++ b/src/org/cyanogenmod/themes/provider/ThemesProvider.java
@@ -420,6 +420,15 @@ public class ThemesProvider extends ContentProvider {
previewKey));
delimeter = ",";
}
+ } else if (ThemesColumns.MODIFIES_STATUSBAR_HEADERS.equals(component)) {
+ for (String previewKey : PreviewsTable.STATUSBAR_HEADERS_PREVIEW_KEYS) {
+ sb.append(delimeter).append(String.format(Locale.US,
+ "(SELECT %s AS %s FROM previews WHERE %s=%d AND %s='%s')",
+ PreviewColumns.COL_VALUE, previewKey,
+ PreviewColumns.THEME_ID, id, PreviewColumns.COL_KEY,
+ previewKey));
+ delimeter = ",";
+ }
} else if (ThemesColumns.MODIFIES_OVERLAYS.equals(component)) {
String previewKey = PreviewColumns.STYLE_PREVIEW;
sb.append(delimeter).append(String.format(Locale.US,
diff --git a/src/org/cyanogenmod/themes/provider/util/BitmapUtils.java b/src/org/cyanogenmod/themes/provider/util/BitmapUtils.java
index de1bf98..afedaf0 100644
--- a/src/org/cyanogenmod/themes/provider/util/BitmapUtils.java
+++ b/src/org/cyanogenmod/themes/provider/util/BitmapUtils.java
@@ -175,6 +175,31 @@ public class BitmapUtils {
}
/**
+ * @param image Bitmap to scale
+ * @param maxSize max size of larget dimen
+ * @return resized bitmap
+ *
+ * Credit StackOverflow
+ * http://stackoverflow.com/questions/15759195/reduce
+ * -size-of-bitmap-to-some-specified-pixel-in-android
+ */
+ public static Bitmap getResizedBitmap(Bitmap image, int maxSize) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+
+ float bitmapRatio = (float) width / (float) height;
+ if (bitmapRatio > 1) {
+ width = maxSize;
+ height = (int) (width / bitmapRatio);
+ } else {
+ height = maxSize;
+ width = (int) (height * bitmapRatio);
+ }
+
+ return Bitmap.createScaledBitmap(image, width, height, true);
+ }
+
+ /**
* For excessively large images with an awkward ratio we
* will want to crop them
* @return
diff --git a/src/org/cyanogenmod/themes/provider/util/SystemUiPreviewGenerator.java b/src/org/cyanogenmod/themes/provider/util/SystemUiPreviewGenerator.java
index 9b5df5e..aed8eb8 100644
--- a/src/org/cyanogenmod/themes/provider/util/SystemUiPreviewGenerator.java
+++ b/src/org/cyanogenmod/themes/provider/util/SystemUiPreviewGenerator.java
@@ -22,12 +22,17 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.Bitmap.Config;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Xml;
import android.widget.FrameLayout;
import org.cyanogenmod.themes.provider.view.BatteryMeterView;
+import org.cyanogenmod.themes.provider.util.*;
import org.cyanogenmod.themes.provider.R;
@@ -47,9 +52,13 @@ public class SystemUiPreviewGenerator {
private static final String IC_SYSBAR_HOME = "ic_sysbar_home";
private static final String IC_SYSBAR_RECENT = "ic_sysbar_recent";
private static final String STATUS_BAR_ICON_SIZE = "status_bar_icon_size";
-
+ private static final String STATUS_BAR_HEADER_MORNING = "notifhead_morning";
+ private static final String STATUS_BAR_HEADER_NOON = "notifhead_noon";
+ private static final String STATUS_BAR_HEADER_EVENING = "notifhead_sunset";
// Style used for tinting of wifi and signal icons
private static final String DUAL_TONE_LIGHT_THEME = "DualToneLightTheme";
+ private static final int HEADER_WIDTH = 1440;
+ private static final int HEADER_HEIGHT = 300;
private Context mContext;
@@ -107,12 +116,36 @@ public class SystemUiPreviewGenerator {
items.navbarRecent = BitmapFactory.decodeResource(res, res.getIdentifier(IC_SYSBAR_RECENT,
"drawable", SYSTEMUI_PACKAGE));
+ final int headerWidth = convertDpToPixel(HEADER_WIDTH, mContext);
+ final int headerHeight = convertDpToPixel(HEADER_HEIGHT, mContext);
+
+ // Generate headers
+ d = themeContext.getDrawable(res.getIdentifier(STATUS_BAR_HEADER_MORNING, "drawable",
+ SYSTEMUI_PACKAGE));
+ items.headerMorning = BitmapUtils.getResizedBitmap(renderDrawableToBitmap(d, headerWidth, headerHeight), HEADER_WIDTH);
+ d = themeContext.getDrawable(res.getIdentifier(STATUS_BAR_HEADER_NOON, "drawable",
+ SYSTEMUI_PACKAGE));
+ items.headerNoon = BitmapUtils.getResizedBitmap(renderDrawableToBitmap(d, headerWidth, headerHeight), HEADER_WIDTH);
+ d = themeContext.getDrawable(res.getIdentifier(STATUS_BAR_HEADER_EVENING, "drawable",
+ SYSTEMUI_PACKAGE));
+ items.headerEvening = BitmapUtils.getResizedBitmap(renderDrawableToBitmap(d, headerWidth, headerHeight), HEADER_WIDTH);
return items;
}
+ private static int convertDpToPixel(float dp, Context context) {
+ Resources resources = context.getResources();
+ DisplayMetrics metrics = resources.getDisplayMetrics();
+ float px = dp * (metrics.densityDpi / 160f);
+ return Math.round(px);
+ }
+
private Bitmap renderDrawableToBitmap(Drawable d, int iconSize) {
+ return renderDrawableToBitmap(d, iconSize, iconSize);
+ }
+
+ private Bitmap renderDrawableToBitmap(Drawable d, int iconWidth, int iconHeight) {
if (d instanceof VectorDrawable) {
- return renderVectorDrawableToBitmap((VectorDrawable) d, iconSize);
+ return renderVectorDrawableToBitmap((VectorDrawable) d, iconWidth, iconHeight);
} else if (d instanceof BitmapDrawable) {
return ((BitmapDrawable) d).getBitmap();
}
@@ -120,10 +153,10 @@ public class SystemUiPreviewGenerator {
return null;
}
- private Bitmap renderVectorDrawableToBitmap(VectorDrawable d, int iconSize) {
- Bitmap bmp = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+ private Bitmap renderVectorDrawableToBitmap(VectorDrawable d, int iconWidth, int iconHeight) {
+ Bitmap bmp = Bitmap.createBitmap(iconWidth, iconHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
- d.setBounds(0, 0, iconSize, iconSize);
+ d.setBounds(0, 0, iconWidth, iconHeight);
d.draw(canvas);
return bmp;
@@ -209,5 +242,12 @@ public class SystemUiPreviewGenerator {
public Bitmap navbarBack;
public Bitmap navbarHome;
public Bitmap navbarRecent;
+
+ /**
+ * Statusbar Header items
+ */
+ public Bitmap headerMorning;
+ public Bitmap headerNoon;
+ public Bitmap headerEvening;
}
}