summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authord34d <clark@cyngn.com>2015-03-02 23:31:05 (GMT)
committerd34d <clark@cyngn.com>2015-03-03 21:36:04 (GMT)
commitd56651ee27f618762440fa0efe5b16c137814854 (patch)
tree14762526351fb0c79f2136d1b0f0ae20ad3148e0 /src
parent59c61579c13cb257e603c28b1c51f6eff64fe2dc (diff)
downloadandroid_packages_providers_ThemesProvider-d56651ee27f618762440fa0efe5b16c137814854.zip
android_packages_providers_ThemesProvider-d56651ee27f618762440fa0efe5b16c137814854.tar.gz
android_packages_providers_ThemesProvider-d56651ee27f618762440fa0efe5b16c137814854.tar.bz2
Themes: Update ThemesContract with install state [2/3]
This provider will be responsible for keeping track of the installed state of themes. This includes two intermedite states, INSTALLING and UPDATING. When a theme is installed from PackageManager the provider will receive this broadcast and add the theme to its DB and set the state to INSTALLING if the ThemeService is processing the theme, or INSTALLED if not and broadcast the ACTION_THEME_INSTALLED action. When a theme is updated the provider will receive another broadcast indicating that the current version of the theme is being replaced. If the ThemeService needs to do some processing, we'll update the state to UPDATING. Once the theme service is done processing a theme, the provider will receive a broadcast from the ThemeService. At this point, the themes provider will update the state to INSTALLED, if it is not already set to that state. The provider will broadcast the ACTION_THEME_INSTALLED action if the previous state was INSTALLING and the ACTION_THEME_UPDATED action if the previous state was UPDATING. Change-Id: Ie37f85463e472d96b8393801007537db1e3eefc6
Diffstat (limited to 'src')
-rw-r--r--src/org/cyanogenmod/themes/provider/AppReceiver.java65
-rw-r--r--src/org/cyanogenmod/themes/provider/PreferenceUtils.java66
-rw-r--r--src/org/cyanogenmod/themes/provider/ThemePackageHelper.java39
-rw-r--r--src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java47
-rw-r--r--src/org/cyanogenmod/themes/provider/ThemesProvider.java37
-rw-r--r--src/org/cyanogenmod/themes/provider/util/ProviderUtils.java116
6 files changed, 219 insertions, 151 deletions
diff --git a/src/org/cyanogenmod/themes/provider/AppReceiver.java b/src/org/cyanogenmod/themes/provider/AppReceiver.java
index d979c96..2a6f85a 100644
--- a/src/org/cyanogenmod/themes/provider/AppReceiver.java
+++ b/src/org/cyanogenmod/themes/provider/AppReceiver.java
@@ -20,13 +20,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.ThemeManager;
-import android.database.Cursor;
import android.net.Uri;
-import android.provider.ThemesContract;
import android.util.Log;
-
-import java.util.Set;
+import org.cyanogenmod.themes.provider.util.ProviderUtils;
public class AppReceiver extends BroadcastReceiver {
public final static String TAG = AppReceiver.class.getName();
@@ -37,71 +33,38 @@ public class AppReceiver extends BroadcastReceiver {
final String pkgName = uri != null ? uri.getSchemeSpecificPart() : null;
final boolean isReplacing = intent.getExtras().getBoolean(Intent.EXTRA_REPLACING, false);
final String action = intent.getAction();
+ final boolean themeProcessing;
try {
if (Intent.ACTION_PACKAGE_ADDED.equals(action) && !isReplacing) {
- final boolean themeProcessing = isThemeBeingProcessed(context, pkgName);
- ThemePackageHelper.insertPackage(context, pkgName, !themeProcessing);
-
- if (themeProcessing) {
- // store this package name so we know it's being processed and it can be
- // added to the DB when ACTION_THEME_RESOURCES_CACHED is received
- PreferenceUtils.addThemeBeingProcessed(context, pkgName);
- }
+ themeProcessing = ProviderUtils.isThemeBeingProcessed(context, pkgName);
+ ThemePackageHelper.insertPackage(context, pkgName, themeProcessing);
} else if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
ThemePackageHelper.removePackage(context, pkgName);
} else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
- final boolean themeProcessing = isThemeBeingProcessed(context, pkgName);
- if (themeExistsInProvider(context, pkgName)) {
- if (!themeProcessing) ThemePackageHelper.updatePackage(context, pkgName);
+ themeProcessing = ProviderUtils.isThemeBeingProcessed(context, pkgName);
+ if (ProviderUtils.themeExistsInProvider(context, pkgName)) {
+ ThemePackageHelper.updatePackage(context, pkgName, themeProcessing);
} else {
// Edge case where app was not a theme in previous install
- ThemePackageHelper.insertPackage(context, pkgName, !themeProcessing);
- }
-
- if (themeProcessing) {
- // store this package name so we know it's being processed and it can be
- // added or updated when ACTION_THEME_RESOURCES_CACHED is received
- PreferenceUtils.addThemeBeingProcessed(context, pkgName);
+ ThemePackageHelper.insertPackage(context, pkgName, themeProcessing);
}
} else if (Intent.ACTION_THEME_RESOURCES_CACHED.equals(action)) {
final String themePkgName = intent.getStringExtra(Intent.EXTRA_THEME_PACKAGE_NAME);
final int result = intent.getIntExtra(Intent.EXTRA_THEME_RESULT,
PackageManager.INSTALL_FAILED_THEME_UNKNOWN_ERROR);
- Set<String> processingThemes =
- PreferenceUtils.getInstalledThemesBeingProcessed(context);
- if (processingThemes != null &&
- processingThemes.contains(themePkgName) && result >= 0) {
- PreferenceUtils.removeThemeBeingProcessed(context, themePkgName);
- if (themeExistsInProvider(context, themePkgName)) {
- ThemePackageHelper.updatePackage(context, themePkgName);
+ if (result == 0) {
+ if (ProviderUtils.themeExistsInProvider(context, themePkgName)) {
+ ThemePackageHelper.updatePackage(context, themePkgName, false);
} else {
// Edge case where app was not a theme in previous install
- ThemePackageHelper.insertPackage(context, themePkgName, true);
+ ThemePackageHelper.insertPackage(context, themePkgName, false);
}
+ } else {
+ Log.e(TAG, "Unable to update theme " + themePkgName + ", result=" + result);
}
}
} catch(NameNotFoundException e) {
Log.e(TAG, "Unable to add package to theme's provider ", e);
}
}
-
- private static boolean themeExistsInProvider(Context context, String pkgName) {
- boolean exists = false;
- String[] projection = new String[] { ThemesContract.ThemesColumns.PKG_NAME };
- String selection = ThemesContract.ThemesColumns.PKG_NAME + "=?";
- String[] selectionArgs = new String[] { pkgName };
- Cursor c = context.getContentResolver().query(ThemesContract.ThemesColumns.CONTENT_URI,
- projection, selection, selectionArgs, null);
-
- if (c != null) {
- exists = c.getCount() >= 1;
- c.close();
- }
- return exists;
- }
-
- private boolean isThemeBeingProcessed(Context context, String pkgName) {
- ThemeManager tm = (ThemeManager) context.getSystemService(Context.THEME_SERVICE);
- return tm.isThemeBeingProcessed(pkgName);
- }
}
diff --git a/src/org/cyanogenmod/themes/provider/PreferenceUtils.java b/src/org/cyanogenmod/themes/provider/PreferenceUtils.java
deleted file mode 100644
index 09d62bb..0000000
--- a/src/org/cyanogenmod/themes/provider/PreferenceUtils.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2014 The CyanogenMod Project
- *
- * 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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.cyanogenmod.themes.provider;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class PreferenceUtils {
- public static final String PREF_INSTALLED_THEMES_PROCESSING = "installed_themes_processing";
-
- public static SharedPreferences getSharedPreferences(Context context) {
- if (context == null) return null;
- return context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
- }
-
- public static Set<String> getInstalledThemesBeingProcessed(Context context) {
- SharedPreferences prefs = getSharedPreferences(context);
- if (prefs == null) return null;
-
- return prefs.getStringSet(PREF_INSTALLED_THEMES_PROCESSING, null);
- }
-
- public static void addThemeBeingProcessed(Context context, String pkgName) {
- SharedPreferences prefs = getSharedPreferences(context);
- if (prefs != null) {
- Set<String> updatedThemes = new HashSet<String>();
- Set<String> current = prefs.getStringSet(PREF_INSTALLED_THEMES_PROCESSING, null);
- if (current != null) {
- updatedThemes.addAll(current);
- }
- if (updatedThemes.add(pkgName)) {
- prefs.edit().putStringSet(PREF_INSTALLED_THEMES_PROCESSING, updatedThemes).apply();
- }
- }
- }
-
- public static void removeThemeBeingProcessed(Context context, String pkgName) {
- SharedPreferences prefs = getSharedPreferences(context);
- if (prefs != null) {
- Set<String> updatedThemes = new HashSet<String>();
- Set<String> current = prefs.getStringSet(PREF_INSTALLED_THEMES_PROCESSING, null);
- if (current != null) {
- updatedThemes.addAll(current);
- }
- if (updatedThemes.remove(pkgName)) {
- prefs.edit().putStringSet(PREF_INSTALLED_THEMES_PROCESSING, updatedThemes).apply();
- }
- }
- }
-}
diff --git a/src/org/cyanogenmod/themes/provider/ThemePackageHelper.java b/src/org/cyanogenmod/themes/provider/ThemePackageHelper.java
index 053473e..254e658 100644
--- a/src/org/cyanogenmod/themes/provider/ThemePackageHelper.java
+++ b/src/org/cyanogenmod/themes/provider/ThemePackageHelper.java
@@ -15,6 +15,7 @@
*/
package org.cyanogenmod.themes.provider;
+import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageInfo;
@@ -31,7 +32,9 @@ import android.database.Cursor;
import android.provider.ThemesContract;
import android.provider.ThemesContract.MixnMatchColumns;
import android.provider.ThemesContract.ThemesColumns;
+import android.provider.ThemesContract.ThemesColumns.InstallState;
import android.util.Log;
+import org.cyanogenmod.themes.provider.util.ProviderUtils;
import java.io.IOException;
import java.util.Collections;
@@ -66,7 +69,7 @@ public class ThemePackageHelper {
"overlays/com.android.systemui");
}
- public static boolean insertPackage(Context context, String pkgName, boolean processPreviews)
+ public static boolean insertPackage(Context context, String pkgName, boolean isProcessing)
throws NameNotFoundException {
PackageInfo pi = context.getPackageManager().getPackageInfo(pkgName, 0);
if (pi == null)
@@ -74,18 +77,18 @@ public class ThemePackageHelper {
Map<String, Boolean> capabilities = getCapabilities(context, pkgName);
if (pi.themeInfo != null) {
- insertPackageInternal(context, pi, capabilities, processPreviews);
+ insertPackageInternal(context, pi, capabilities, isProcessing);
} else if (pi.isLegacyIconPackApk){
// We must be here because it is a legacy icon pack
capabilities = new HashMap<String, Boolean>();
capabilities.put(ThemesColumns.MODIFIES_ICONS, true);
- insertLegacyIconPackInternal(context, pi, capabilities,processPreviews);
+ insertLegacyIconPackInternal(context, pi, capabilities, isProcessing);
}
return true;
}
private static void insertPackageInternal(Context context, PackageInfo pi,
- Map<String, Boolean> capabilities, boolean processPreviews) {
+ Map<String, Boolean> capabilities, boolean isProcessing) {
ThemeInfo info = pi.themeInfo;
boolean isPresentableTheme = isPresentableTheme(capabilities);
@@ -100,8 +103,9 @@ public class ThemePackageHelper {
ThemeUtils.getDefaultThemePackageName(context).equals(pi.packageName) ? 1 : 0);
values.put(ThemesColumns.LAST_UPDATE_TIME, pi.lastUpdateTime);
values.put(ThemesColumns.INSTALL_TIME, pi.firstInstallTime);
- values.put(ThemesProvider.KEY_PROCESS_PREVIEWS, processPreviews);
values.put(ThemesColumns.TARGET_API, pi.applicationInfo.targetSdkVersion);
+ values.put(ThemesColumns.INSTALL_STATE, isProcessing ? InstallState.INSTALLING :
+ InstallState.INSTALLED);
// Insert theme capabilities
insertCapabilities(capabilities, values);
@@ -110,7 +114,7 @@ public class ThemePackageHelper {
}
private static void insertLegacyIconPackInternal(Context context, PackageInfo pi,
- Map<String, Boolean> capabilities, boolean processPreviews) {
+ Map<String, Boolean> capabilities, boolean isProcessing) {
PackageManager pm = context.getPackageManager();
CharSequence labelName = pm.getApplicationLabel(pi.applicationInfo);
if (labelName == null) labelName = context.getString(R.string.unknown_app_name);
@@ -123,8 +127,9 @@ public class ThemePackageHelper {
values.put(ThemesColumns.LAST_UPDATE_TIME, pi.lastUpdateTime);
values.put(ThemesColumns.INSTALL_TIME, pi.firstInstallTime);
values.put(ThemesColumns.IS_LEGACY_ICONPACK, 1);
- values.put(ThemesProvider.KEY_PROCESS_PREVIEWS, processPreviews);
values.put(ThemesColumns.TARGET_API, pi.applicationInfo.targetSdkVersion);
+ values.put(ThemesColumns.INSTALL_STATE, isProcessing ? InstallState.INSTALLING :
+ InstallState.INSTALLED);
// Insert theme capabilities
insertCapabilities(capabilities, values);
@@ -132,16 +137,17 @@ public class ThemePackageHelper {
context.getContentResolver().insert(ThemesColumns.CONTENT_URI, values);
}
- public static void updatePackage(Context context, String pkgName) throws NameNotFoundException {
+ public static void updatePackage(Context context, String pkgName, boolean isProcessing)
+ throws NameNotFoundException {
if (SYSTEM_DEFAULT.equals(pkgName)) {
updateSystemPackageInternal(context);
} else {
PackageInfo pi = context.getPackageManager().getPackageInfo(pkgName, 0);
Map<String, Boolean> capabilities = getCapabilities(context, pkgName);
if (pi.themeInfo != null) {
- updatePackageInternal(context, pi, capabilities);
+ updatePackageInternal(context, pi, capabilities, isProcessing);
} else if (pi.isLegacyIconPackApk) {
- updateLegacyIconPackInternal(context, pi, capabilities);
+ updateLegacyIconPackInternal(context, pi, capabilities, isProcessing);
}
// We should reapply any components that are currently applied for this theme.
@@ -150,7 +156,7 @@ public class ThemePackageHelper {
}
private static void updatePackageInternal(Context context, PackageInfo pi,
- Map<String, Boolean> capabilities) {
+ Map<String, Boolean> capabilities, boolean isProcessing) {
ThemeInfo info = pi.themeInfo;
boolean isPresentableTheme = ThemePackageHelper.isPresentableTheme(capabilities);
ContentValues values = new ContentValues();
@@ -164,6 +170,8 @@ public class ThemePackageHelper {
ThemeUtils.getDefaultThemePackageName(context).equals(pi.packageName) ? 1 : 0);
values.put(ThemesColumns.LAST_UPDATE_TIME, pi.lastUpdateTime);
values.put(ThemesColumns.INSTALL_TIME, pi.firstInstallTime);
+ values.put(ThemesColumns.INSTALL_STATE,
+ isProcessing ? InstallState.UPDATING : InstallState.INSTALLED);
// Insert theme capabilities
insertCapabilities(capabilities, values);
@@ -183,7 +191,7 @@ public class ThemePackageHelper {
}
private static void updateLegacyIconPackInternal(Context context, PackageInfo pi,
- Map<String, Boolean> capabilities) {
+ Map<String, Boolean> capabilities, boolean isProcessing) {
PackageManager pm = context.getPackageManager();
CharSequence labelName = pm.getApplicationLabel(pi.applicationInfo);
if (labelName == null) labelName = context.getString(R.string.unknown_app_name);
@@ -195,6 +203,8 @@ public class ThemePackageHelper {
values.put(ThemesColumns.DATE_CREATED, System.currentTimeMillis());
values.put(ThemesColumns.LAST_UPDATE_TIME, pi.lastUpdateTime);
values.put(ThemesColumns.INSTALL_TIME, pi.firstInstallTime);
+ values.put(ThemesColumns.INSTALL_STATE,
+ isProcessing ? InstallState.UPDATING : InstallState.INSTALLED);
String where = ThemesColumns.PKG_NAME + "=?";
String[] args = { pi.packageName };
@@ -240,7 +250,10 @@ public class ThemePackageHelper {
// Delete the theme from the db
String selection = ThemesColumns.PKG_NAME + "= ?";
String[] selectionArgs = { pkgToRemove };
- context.getContentResolver().delete(ThemesColumns.CONTENT_URI, selection, selectionArgs);
+ final ContentResolver resolver = context.getContentResolver();
+ if (resolver.delete(ThemesColumns.CONTENT_URI, selection, selectionArgs) > 0) {
+ ProviderUtils.sendThemeRemovedBroadcast(context, pkgToRemove);
+ }
}
/**
diff --git a/src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java b/src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java
index 7e747bc..b065f79 100644
--- a/src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java
+++ b/src/org/cyanogenmod/themes/provider/ThemesOpenHelper.java
@@ -36,9 +36,9 @@ import android.util.Log;
public class ThemesOpenHelper extends SQLiteOpenHelper {
private static final String TAG = ThemesOpenHelper.class.getName();
- private static final int DATABASE_VERSION = 12;
+ private static final int DATABASE_VERSION = 13;
private static final String DATABASE_NAME = "themes.db";
- private static final String DEFAULT_PKG_NAME = ThemeConfig.SYSTEM_DEFAULT;
+ private static final String SYSTEM_THEME_PKG_NAME = ThemeConfig.SYSTEM_DEFAULT;
private Context mContext;
@@ -106,6 +106,10 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
upgradeToVersion12(db);
oldVersion = 12;
}
+ if (oldVersion == 12) {
+ upgradeToVersion13(db);
+ oldVersion = 13;
+ }
if (oldVersion != DATABASE_VERSION) {
Log.e(TAG, "Recreating db because unknown database version: " + oldVersion);
dropTables(db);
@@ -130,7 +134,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
// Add default value to mixnmatch for KEY_ALARM
ContentValues values = new ContentValues();
values.put(MixnMatchColumns.COL_KEY, ThemesContract.MixnMatchColumns.KEY_ALARM);
- values.put(MixnMatchColumns.COL_VALUE, DEFAULT_PKG_NAME);
+ values.put(MixnMatchColumns.COL_VALUE, SYSTEM_THEME_PKG_NAME);
db.insert(MixnMatchTable.TABLE_NAME, null, values);
}
@@ -149,20 +153,20 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
// change default package name to holo
String changeDefaultToSystem = String.format("UPDATE %s SET %s='%s' WHERE" +
" %s='%s'", ThemesTable.TABLE_NAME, ThemesColumns.PKG_NAME,
- DEFAULT_PKG_NAME, ThemesColumns.PKG_NAME, "default");
+ SYSTEM_THEME_PKG_NAME, ThemesColumns.PKG_NAME, "default");
db.execSQL(changeDefaultToSystem);
if (isSystemDefault(mContext)) {
// flag holo as default if
String makeHoloDefault = String.format("UPDATE %s SET %s=%d WHERE" +
" %s='%s'", ThemesTable.TABLE_NAME, ThemesColumns.IS_DEFAULT_THEME, 1,
- ThemesColumns.PKG_NAME, DEFAULT_PKG_NAME);
+ ThemesColumns.PKG_NAME, SYSTEM_THEME_PKG_NAME);
db.execSQL(makeHoloDefault);
}
// change any existing mixnmatch values set to "default" to "holo"
db.execSQL(String.format("UPDATE %s SET %s='%s' WHERE %s='%s'",
- MixnMatchTable.TABLE_NAME, MixnMatchColumns.COL_VALUE, DEFAULT_PKG_NAME,
+ MixnMatchTable.TABLE_NAME, MixnMatchColumns.COL_VALUE, SYSTEM_THEME_PKG_NAME,
MixnMatchColumns.COL_VALUE, "default"));
}
@@ -217,7 +221,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
final String pkgName = c.getString(0);
final boolean isLegacyTheme = c.getInt(1) == 1;
boolean hasSystemUi = false;
- if (DEFAULT_PKG_NAME.equals(pkgName) || isLegacyTheme) {
+ if (SYSTEM_THEME_PKG_NAME.equals(pkgName) || isLegacyTheme) {
hasSystemUi = true;
} else {
try {
@@ -262,7 +266,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
final String pkgName = c.getString(0);
final boolean isLegacyTheme = c.getInt(1) == 1;
boolean hasSystemUi = false;
- if (DEFAULT_PKG_NAME.equals(pkgName) || isLegacyTheme) {
+ if (SYSTEM_THEME_PKG_NAME.equals(pkgName) || isLegacyTheme) {
hasSystemUi = true;
} else {
try {
@@ -323,7 +327,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
while(c.moveToNext()) {
final String pkgName = c.getString(0);
int targetSdk = -1;
- if (DEFAULT_PKG_NAME.equals(pkgName)) {
+ if (SYSTEM_THEME_PKG_NAME.equals(pkgName)) {
// 0 is a special value used for the system theme, not to be confused with the
// default theme which may not be the same as the system theme.
targetSdk = 0;
@@ -354,7 +358,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
"WHERE %s='%s'",
ThemesTable.TABLE_NAME,
NEW_THEME_TITLE,
- DEFAULT_PKG_NAME,
+ SYSTEM_THEME_PKG_NAME,
ThemesColumns.PKG_NAME, PREV_SYSTEM_PKG_NAME);
db.execSQL(holoToSystem);
@@ -380,6 +384,18 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
}
}
+ private void upgradeToVersion13(SQLiteDatabase db) {
+ // add install_state column to themes db
+ String sql = String.format("ALTER TABLE %s ADD COLUMN %s INTEGER DEFAULT %d",
+ ThemesTable.TABLE_NAME, ThemesColumns.INSTALL_STATE,
+ ThemesColumns.InstallState.UNKNOWN);
+ db.execSQL(sql);
+
+ // we need to update any existing themes with their install state
+ db.execSQL(String.format("UPDATE %s SET %s='%d'", ThemesTable.TABLE_NAME,
+ ThemesColumns.INSTALL_STATE, ThemesColumns.InstallState.INSTALLED));
+ }
+
private void dropTables(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + ThemesTable.TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS " + MixnMatchTable.TABLE_NAME);
@@ -423,14 +439,16 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
ThemesColumns.IS_LEGACY_ICONPACK + " INTEGER DEFAULT 0, " +
ThemesColumns.LAST_UPDATE_TIME + " INTEGER DEFAULT 0, " +
ThemesColumns.INSTALL_TIME + " INTEGER DEFAULT 0, " +
- ThemesColumns.TARGET_API + " INTEGER DEFAULT 0" +
+ ThemesColumns.TARGET_API + " INTEGER DEFAULT 0," +
+ ThemesColumns.INSTALL_STATE + " INTEGER DEFAULT " +
+ ThemesColumns.InstallState.UNKNOWN +
")";
public static void insertSystemDefaults(SQLiteDatabase db, Context context) {
int isDefault = isSystemDefault(context) ? 1 : 0;
ContentValues values = new ContentValues();
values.put(ThemesColumns.TITLE, "System");
- values.put(ThemesColumns.PKG_NAME, DEFAULT_PKG_NAME);
+ values.put(ThemesColumns.PKG_NAME, SYSTEM_THEME_PKG_NAME);
values.put(ThemesColumns.PRIMARY_COLOR, 0xff33b5e5);
values.put(ThemesColumns.SECONDARY_COLOR, 0xff000000);
values.put(ThemesColumns.AUTHOR, "Android");
@@ -450,6 +468,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
values.put(ThemesColumns.IS_LEGACY_ICONPACK, 0);
values.put(ThemesColumns.MODIFIES_OVERLAYS, 1);
values.put(ThemesColumns.TARGET_API, Build.VERSION.SDK_INT);
+ values.put(ThemesColumns.INSTALL_STATE, ThemesColumns.InstallState.INSTALLED);
db.insert(TABLE_NAME, null, values);
}
}
@@ -466,7 +485,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
ContentValues values = new ContentValues();
for(String key : MixnMatchColumns.ROWS) {
values.put(MixnMatchColumns.COL_KEY, key);
- values.put(MixnMatchColumns.COL_VALUE, DEFAULT_PKG_NAME);
+ values.put(MixnMatchColumns.COL_VALUE, SYSTEM_THEME_PKG_NAME);
db.insert(TABLE_NAME, null, values);
}
}
@@ -533,7 +552,7 @@ public class ThemesOpenHelper extends SQLiteOpenHelper {
public static void insertDefaults(Context context) {
Intent intent = new Intent(context, PreviewGenerationService.class);
intent.setAction(PreviewGenerationService.ACTION_INSERT);
- intent.putExtra(PreviewGenerationService.EXTRA_PKG_NAME, DEFAULT_PKG_NAME);
+ intent.putExtra(PreviewGenerationService.EXTRA_PKG_NAME, SYSTEM_THEME_PKG_NAME);
intent.putExtra(PreviewGenerationService.EXTRA_HAS_SYSTEMUI, true);
intent.putExtra(PreviewGenerationService.EXTRA_HAS_ICONS, true);
intent.putExtra(PreviewGenerationService.EXTRA_HAS_STYLES, true);
diff --git a/src/org/cyanogenmod/themes/provider/ThemesProvider.java b/src/org/cyanogenmod/themes/provider/ThemesProvider.java
index 503d703..ae0a5af 100644
--- a/src/org/cyanogenmod/themes/provider/ThemesProvider.java
+++ b/src/org/cyanogenmod/themes/provider/ThemesProvider.java
@@ -17,6 +17,7 @@ package org.cyanogenmod.themes.provider;
import android.content.ContentProvider;
+import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
@@ -43,6 +44,7 @@ import android.util.Log;
import org.cyanogenmod.themes.provider.ThemesOpenHelper.MixnMatchTable;
import org.cyanogenmod.themes.provider.ThemesOpenHelper.PreviewsTable;
import org.cyanogenmod.themes.provider.ThemesOpenHelper.ThemesTable;
+import org.cyanogenmod.themes.provider.util.ProviderUtils;
import java.util.ArrayList;
import java.util.Collection;
@@ -150,9 +152,9 @@ public class ThemesProvider extends ContentProvider {
switch (uriType) {
case THEMES:
boolean processPreviews = true;
- if (values.containsKey(KEY_PROCESS_PREVIEWS)) {
- processPreviews = values.getAsBoolean(KEY_PROCESS_PREVIEWS);
- values.remove(KEY_PROCESS_PREVIEWS);
+ if (values.containsKey(ThemesColumns.INSTALL_STATE)) {
+ int state = values.getAsInteger(ThemesColumns.INSTALL_STATE);
+ processPreviews = state == ThemesColumns.InstallState.INSTALLING;
}
id = sqlDB.insert(ThemesOpenHelper.ThemesTable.TABLE_NAME, null, values);
if (processPreviews) {
@@ -185,8 +187,11 @@ public class ThemesProvider extends ContentProvider {
break;
default:
}
- getContext().getContentResolver().notifyChange(uri, null);
- return Uri.parse(MixnMatchColumns.CONTENT_URI + "/" + id);
+ if (id >= 0) {
+ ContentUris.withAppendedId(uri, id);
+ getContext().getContentResolver().notifyChange(uri, null);
+ }
+ return uri;
}
@Override
@@ -272,6 +277,8 @@ public class ThemesProvider extends ContentProvider {
case THEMES_ID:
String pkgName = values.getAsString(ThemesColumns.PKG_NAME);
final boolean updatePreviews = getShouldUpdatePreviews(sqlDB, pkgName);
+ final int oldInstallState =
+ ProviderUtils.getInstallStateForTheme(getContext(), pkgName);
rowsUpdated = sqlDB.update(ThemesTable.TABLE_NAME, values, selection, selectionArgs);
if (updateNotTriggeredByContentProvider(values) && updatePreviews) {
Intent intent = new Intent(getContext(), PreviewGenerationService.class);
@@ -295,6 +302,18 @@ public class ThemesProvider extends ContentProvider {
hasBootAni != null && hasBootAni);
getContext().startService(intent);
}
+ // Broadcast that the theme is installed if the previous state was INSTALLING and
+ // the new state is INSTALLED.
+ if (values.containsKey(ThemesColumns.INSTALL_STATE)) {
+ int newState = values.getAsInteger(ThemesColumns.INSTALL_STATE);
+ if (newState == ThemesColumns.InstallState.INSTALLED) {
+ if (oldInstallState == ThemesColumns.InstallState.INSTALLING) {
+ ProviderUtils.sendThemeInstalledBroadcast(getContext(), pkgName);
+ } else if (oldInstallState == ThemesColumns.InstallState.UPDATING) {
+ ProviderUtils.sendThemeUpdatedBroadcast(getContext(), pkgName);
+ }
+ }
+ }
getContext().getContentResolver().notifyChange(uri, null);
break;
case MIXNMATCH:
@@ -555,7 +574,9 @@ public class ThemesProvider extends ContentProvider {
private void insertThemes(Collection<PackageInfo> themesToInsert) {
for (PackageInfo themeInfo : themesToInsert) {
try {
- ThemePackageHelper.insertPackage(getContext(), themeInfo.packageName, true);
+ final Context context = getContext();
+ ThemePackageHelper.insertPackage(context, themeInfo.packageName,
+ ProviderUtils.isThemeBeingProcessed(context, themeInfo.packageName));
} catch (NameNotFoundException e) {
Log.e(TAG, "Unable to insert theme " + themeInfo.packageName, e);
}
@@ -565,7 +586,9 @@ public class ThemesProvider extends ContentProvider {
private void updateThemes(List<String> themesToUpdate) {
for (String pkgName : themesToUpdate) {
try {
- ThemePackageHelper.updatePackage(getContext(), pkgName);
+ final Context context = getContext();
+ ThemePackageHelper.updatePackage(context, pkgName,
+ ProviderUtils.isThemeBeingProcessed(context, pkgName));
} catch (NameNotFoundException e) {
Log.e(TAG, "Unable to update theme " + pkgName, e);
}
diff --git a/src/org/cyanogenmod/themes/provider/util/ProviderUtils.java b/src/org/cyanogenmod/themes/provider/util/ProviderUtils.java
new file mode 100644
index 0000000..a07d0ba
--- /dev/null
+++ b/src/org/cyanogenmod/themes/provider/util/ProviderUtils.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod Project
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.cyanogenmod.themes.provider.util;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.ThemeManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ThemesContract;
+import android.provider.ThemesContract.ThemesColumns;
+
+public class ProviderUtils {
+ /**
+ * Convenience method for determining if a theme exists in the provider
+ * @param context
+ * @param pkgName
+ * @return True if the theme exists, false otherwise
+ */
+ public static boolean themeExistsInProvider(Context context, String pkgName) {
+ boolean exists = false;
+ String[] projection = new String[] { ThemesColumns.PKG_NAME };
+ String selection = ThemesColumns.PKG_NAME + "=?";
+ String[] selectionArgs = new String[] { pkgName };
+ Cursor c = context.getContentResolver().query(ThemesColumns.CONTENT_URI,
+ projection, selection, selectionArgs, null);
+
+ if (c != null) {
+ exists = c.getCount() >= 1;
+ c.close();
+ }
+ return exists;
+ }
+
+ /**
+ * Queries the {@link android.content.res.ThemeManager} to check if the theme is currently
+ * being processed by {@link com.android.server.ThemeService}
+ * @param context
+ * @param pkgName
+ * @return True if the theme is being processed or queued up for processing
+ */
+ public static boolean isThemeBeingProcessed(Context context, String pkgName) {
+ ThemeManager tm = (ThemeManager) context.getSystemService(Context.THEME_SERVICE);
+ return tm.isThemeBeingProcessed(pkgName);
+ }
+
+ /**
+ * Convenience method for getting the install state of a theme in the provider
+ * @param context
+ * @param pkgName
+ * @return
+ */
+ public static int getInstallStateForTheme(Context context, String pkgName) {
+ String[] projection = new String[] { ThemesColumns.INSTALL_STATE };
+ String selection = ThemesColumns.PKG_NAME + "=?";
+ String[] selectionArgs = new String[] { pkgName };
+ Cursor c = context.getContentResolver().query(ThemesColumns.CONTENT_URI,
+ projection, selection, selectionArgs, null);
+
+ int state = ThemesColumns.InstallState.UNKNOWN;
+ if (c != null) {
+ if (c.moveToFirst()) {
+ state = c.getInt(c.getColumnIndex(ThemesColumns.INSTALL_STATE));
+ }
+ c.close();
+ }
+ return state;
+ }
+
+ /**
+ * Sends the {@link android.provider.ThemesContract.Intent#ACTION_THEME_INSTALLED} action
+ * @param context
+ * @param pkgName
+ */
+ public static void sendThemeInstalledBroadcast(Context context, String pkgName) {
+ Intent intent = new Intent(ThemesContract.Intent.ACTION_THEME_INSTALLED,
+ Uri.fromParts(ThemesContract.Intent.URI_SCHEME_PACKAGE, pkgName, null));
+ context.sendBroadcast(intent, Manifest.permission.READ_THEMES);
+ }
+
+ /**
+ * Sends the {@link android.provider.ThemesContract.Intent#ACTION_THEME_UPDATED} action
+ * @param context
+ * @param pkgName
+ */
+ public static void sendThemeUpdatedBroadcast(Context context, String pkgName) {
+ Intent intent = new Intent(ThemesContract.Intent.ACTION_THEME_UPDATED,
+ Uri.fromParts(ThemesContract.Intent.URI_SCHEME_PACKAGE, pkgName, null));
+ context.sendBroadcast(intent, Manifest.permission.READ_THEMES);
+ }
+
+ /**
+ * Sends the {@link android.provider.ThemesContract.Intent#ACTION_THEME_REMOVED} action
+ * @param context
+ * @param pkgName
+ */
+ public static void sendThemeRemovedBroadcast(Context context, String pkgName) {
+ Intent intent = new Intent(ThemesContract.Intent.ACTION_THEME_REMOVED,
+ Uri.fromParts(ThemesContract.Intent.URI_SCHEME_PACKAGE, pkgName, null));
+ context.sendBroadcast(intent, Manifest.permission.READ_THEMES);
+ }
+}