diff options
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); + } +} |