diff options
author | Clark Scheff <clark@cyngn.com> | 2015-02-18 16:15:29 -0800 |
---|---|---|
committer | Clark Scheff <clark@cyngn.com> | 2015-10-27 10:40:35 -0700 |
commit | d23b0fcb5f2be06951676d85aa5cae50c6abd9a0 (patch) | |
tree | 5a2ddd80bb4ce6e66bdde62878f6964e3571f6d6 | |
parent | d12db22f546d6d55f9c6d1ec729875282c6f4097 (diff) | |
download | frameworks_base-d23b0fcb5f2be06951676d85aa5cae50c6abd9a0.zip frameworks_base-d23b0fcb5f2be06951676d85aa5cae50c6abd9a0.tar.gz frameworks_base-d23b0fcb5f2be06951676d85aa5cae50c6abd9a0.tar.bz2 |
Themes: Enhanced theming capabilities [1/3]
This patch includes a new class, ThemeChangeRequest, which will be
used to facilitate theme changes. This class includes a builder
that will be used to create a ThemeChangeRequest.
Change-Id: I60144f8a6505aefcc570feb15ccc50e77bcb1114
-rw-r--r-- | cmds/tm/src/com/android/commands/tm/Tm.java | 17 | ||||
-rw-r--r-- | core/java/android/content/pm/ThemeUtils.java | 15 | ||||
-rw-r--r-- | core/java/android/content/res/IThemeService.aidl | 3 | ||||
-rw-r--r-- | core/java/android/content/res/ThemeChangeRequest.aidl | 19 | ||||
-rw-r--r-- | core/java/android/content/res/ThemeChangeRequest.java | 225 | ||||
-rw-r--r-- | core/java/android/content/res/ThemeConfig.java | 16 | ||||
-rw-r--r-- | core/java/android/content/res/ThemeManager.java | 22 | ||||
-rw-r--r-- | services/core/java/com/android/server/ThemeService.java | 178 |
8 files changed, 403 insertions, 92 deletions
diff --git a/cmds/tm/src/com/android/commands/tm/Tm.java b/cmds/tm/src/com/android/commands/tm/Tm.java index 14101f7..af1ac75 100644 --- a/cmds/tm/src/com/android/commands/tm/Tm.java +++ b/cmds/tm/src/com/android/commands/tm/Tm.java @@ -23,6 +23,7 @@ import android.content.pm.PackageInfo; import android.content.pm.ParceledListSlice; import android.content.pm.ThemeUtils; import android.content.res.IThemeService; +import android.content.res.ThemeChangeRequest; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -54,13 +55,14 @@ public class Tm extends BaseCommand { StringBuilder sb = new StringBuilder(); sb.append("usage: tm [subcommand] [options]\n"); sb.append(" tm list\n"); - sb.append(" tm apply <PACKAGE_NAME> [-c <COMPONENT> [-c <COMPONENT>] ...]\n"); + sb.append(" tm apply <PACKAGE_NAME> [-r] [-c <COMPONENT> [-c <COMPONENT>] ...]\n"); sb.append(" tm rebuild\n"); sb.append(" tm process <PACKAGE_NAME>\n"); sb.append("\n"); sb.append("tm list: return a list of theme packages.\n"); sb.append("\n"); sb.append("tm apply: applies the components for the theme specified by PACKAGE_NAME.\n"); + sb.append(" -r: remove per app themes\n"); sb.append(" [-c <COMPONENT> [-c <COMPONENT>] ...]\n"); sb.append(" if no components are specified all components will be applied.\n"); sb.append(" Valid components are:\n"); @@ -143,22 +145,27 @@ public class Tm extends BaseCommand { } } - Map<String, String> componentMap = new HashMap<String, String>(); + boolean removePerAppThemes = false; + + ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); String opt; while ((opt=nextOption()) != null) { if (opt.equals("-c")) { - componentMap.put(nextArgRequired(), pkgName); + builder.setComponent(nextArgRequired(), pkgName); + } else if (opt.equals("-r")) { + removePerAppThemes = true; } } // No components specified so let's just try and apply EVERYTHING! + Map<String, String> componentMap = builder.build().getThemeComponentsMap(); if (componentMap.size() == 0) { List<String> components = ThemeUtils.getAllComponents(); for (String component : components) { - componentMap.put(component, pkgName); + builder.setComponent(component, pkgName); } } - mTs.requestThemeChange(componentMap); + mTs.requestThemeChange(builder.build(), removePerAppThemes); } private void runRebuildResourceCache() throws Exception { diff --git a/core/java/android/content/pm/ThemeUtils.java b/core/java/android/content/pm/ThemeUtils.java index 38391d4..a5a523c 100644 --- a/core/java/android/content/pm/ThemeUtils.java +++ b/core/java/android/content/pm/ThemeUtils.java @@ -107,6 +107,9 @@ public class ThemeUtils { public static final int SYSTEM_TARGET_API = 0; + // Package name for any app which does not have a specific theme applied + private static final String DEFAULT_PKG = "default"; + private static final String SETTINGS_DB = "/data/data/com.android.providers.settings/databases/settings.db"; private static final String SETTINGS_SECURE_TABLE = "secure"; @@ -715,4 +718,16 @@ public class ThemeUtils { return config; } + + /** + * Convenience method to determine if a theme component is a per app theme and not a standard + * component. + * @param component + * @return + */ + public static boolean isPerAppThemeComponent(String component) { + return !(DEFAULT_PKG.equals(component) + || ThemeConfig.SYSTEMUI_STATUS_BAR_PKG.equals(component) + || ThemeConfig.SYSTEMUI_NAVBAR_PKG.equals(component)); + } } diff --git a/core/java/android/content/res/IThemeService.aidl b/core/java/android/content/res/IThemeService.aidl index 101ace9..90cb9fb 100644 --- a/core/java/android/content/res/IThemeService.aidl +++ b/core/java/android/content/res/IThemeService.aidl @@ -17,6 +17,7 @@ package android.content.res; import android.content.res.IThemeChangeListener; import android.content.res.IThemeProcessingListener; +import android.content.res.ThemeChangeRequest; import android.graphics.Bitmap; import java.util.Map; @@ -26,7 +27,7 @@ interface IThemeService { void requestThemeChangeUpdates(in IThemeChangeListener listener); void removeUpdates(in IThemeChangeListener listener); - void requestThemeChange(in Map componentMap); + void requestThemeChange(in ThemeChangeRequest request, boolean removePerAppThemes); void applyDefaultTheme(); boolean isThemeApplying(); int getProgress(); diff --git a/core/java/android/content/res/ThemeChangeRequest.aidl b/core/java/android/content/res/ThemeChangeRequest.aidl new file mode 100644 index 0000000..e6cf115 --- /dev/null +++ b/core/java/android/content/res/ThemeChangeRequest.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.content.res; + +/** @hide */ +parcelable ThemeChangeRequest; diff --git a/core/java/android/content/res/ThemeChangeRequest.java b/core/java/android/content/res/ThemeChangeRequest.java new file mode 100644 index 0000000..2c1f6ff --- /dev/null +++ b/core/java/android/content/res/ThemeChangeRequest.java @@ -0,0 +1,225 @@ +/* + * 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 android.content.res; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + + +import static android.provider.ThemesContract.ThemesColumns.*; + +/** @hide */ +public final class ThemeChangeRequest implements Parcelable { + private final Map<String, String> mThemeComponents = new HashMap<String, String>(); + private final Map<String, String> mPerAppOverlays = new HashMap<String, String>(); + + public String getOverlayThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_OVERLAYS); + } + + public String getStatusBarThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_STATUS_BAR); + } + + public String getNavBarThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_NAVIGATION_BAR); + } + + public String getFontThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_FONTS); + } + + public String getIconsThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_ICONS); + } + + public String getBootanimationThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_BOOT_ANIM); + } + + public String getWallpaperThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_LAUNCHER); + } + + public String getLockWallpaperThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_LOCKSCREEN); + } + + public String getAlarmThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_ALARMS); + } + + public String getNotificationThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_NOTIFICATIONS); + } + + public String getRingtoneThemePackageName() { + return getThemePackageNameForComponent(MODIFIES_RINGTONES); + } + + public final Map<String, String> getThemeComponentsMap() { + return Collections.unmodifiableMap(mThemeComponents); + } + + /** + * Get the mapping for per app themes + * @return A mapping of apps and the theme to apply for each one. or null if none set. + */ + public final Map<String, String> getPerAppOverlays() { + return Collections.unmodifiableMap(mPerAppOverlays); + } + + public int getNumChangesRequested() { + return mThemeComponents.size() + mPerAppOverlays.size(); + } + + private String getThemePackageNameForComponent(String componentName) { + return mThemeComponents.get(componentName); + } + + private ThemeChangeRequest(Map<String, String> components, Map<String, String> perAppThemes) { + if (components != null) { + mThemeComponents.putAll(components); + } + if (perAppThemes != null) { + mPerAppOverlays.putAll(perAppThemes); + } + } + + private ThemeChangeRequest(Parcel source) { + int numComponents = source.readInt(); + for (int i = 0; i < numComponents; i++) { + mThemeComponents.put(source.readString(), source.readString()); + } + + numComponents = source.readInt(); + for (int i = 0 ; i < numComponents; i++) { + mPerAppOverlays.put(source.readString(), source.readString()); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mThemeComponents.size()); + for (String component : mThemeComponents.keySet()) { + dest.writeString(component); + dest.writeString(mThemeComponents.get(component)); + } + dest.writeInt((mPerAppOverlays.size())); + for (String appPkgName : mPerAppOverlays.keySet()) { + dest.writeString(appPkgName); + dest.writeString(mPerAppOverlays.get(appPkgName)); + } + } + + public static final Parcelable.Creator<ThemeChangeRequest> CREATOR = + new Parcelable.Creator<ThemeChangeRequest>() { + @Override + public ThemeChangeRequest createFromParcel(Parcel source) { + return new ThemeChangeRequest(source); + } + + @Override + public ThemeChangeRequest[] newArray(int size) { + return new ThemeChangeRequest[size]; + } + }; + + public static class Builder { + Map<String, String> mThemeComponents = new HashMap<String, String>(); + Map<String, String> mPerAppOverlays = new HashMap<String, String>(); + + public Builder() {} + + public Builder setOverlay(String pkgName) { + return setComponent(MODIFIES_OVERLAYS, pkgName); + } + + public Builder setStatusBar(String pkgName) { + return setComponent(MODIFIES_STATUS_BAR, pkgName); + } + + public Builder setNavBar(String pkgName) { + return setComponent(MODIFIES_NAVIGATION_BAR, pkgName); + } + + public Builder setFont(String pkgName) { + return setComponent(MODIFIES_FONTS, pkgName); + } + + public Builder setIcons(String pkgName) { + return setComponent(MODIFIES_ICONS, pkgName); + } + + public Builder setBootanimation(String pkgName) { + return setComponent(MODIFIES_BOOT_ANIM, pkgName); + } + + public Builder setWallpaper(String pkgName) { + return setComponent(MODIFIES_LAUNCHER, pkgName); + } + + public Builder setLockWallpaper(String pkgName) { + return setComponent(MODIFIES_LOCKSCREEN, pkgName); + } + + public Builder setAlarm(String pkgName) { + return setComponent(MODIFIES_ALARMS, pkgName); + } + + public Builder setNotification(String pkgName) { + return setComponent(MODIFIES_NOTIFICATIONS, pkgName); + } + + public Builder setRingtone(String pkgName) { + return setComponent(MODIFIES_RINGTONES, pkgName); + } + + public Builder setComponent(String component, String pkgName) { + if (pkgName != null) { + mThemeComponents.put(component, pkgName); + } else { + mThemeComponents.remove(component); + } + return this; + } + + public Builder setAppOverlay(String appPkgName, String themePkgName) { + if (appPkgName != null) { + if (themePkgName != null) { + mPerAppOverlays.put(appPkgName, themePkgName); + } else { + mPerAppOverlays.remove(appPkgName); + } + } + + return this; + } + + public ThemeChangeRequest build() { + return new ThemeChangeRequest(mThemeComponents, mPerAppOverlays); + } + } +} diff --git a/core/java/android/content/res/ThemeConfig.java b/core/java/android/content/res/ThemeConfig.java index 61c37c3..1882211 100644 --- a/core/java/android/content/res/ThemeConfig.java +++ b/core/java/android/content/res/ThemeConfig.java @@ -31,6 +31,7 @@ import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -105,6 +106,10 @@ public class ThemeConfig implements Cloneable, Parcelable, Comparable<ThemeConfi return theme.mFontPkgName; } + public Map<String, AppTheme> getAppThemes() { + return Collections.unmodifiableMap(mThemes); + } + private AppTheme getThemeFor(String pkgName) { AppTheme theme = mThemes.get(pkgName); if (theme == null) theme = getDefaultTheme(); @@ -429,8 +434,15 @@ public class ThemeConfig implements Cloneable, Parcelable, Comparable<ThemeConfi String overlay = mOverlays.get(appPkgName); String font = mFonts.get(appPkgName); - AppTheme appTheme = new AppTheme(overlay, icon, font); - appThemes.put(appPkgName, appTheme); + // Remove app theme if all items are null + if (overlay == null && icon == null && font == null) { + if (appThemes.containsKey(appPkgName)) { + appThemes.remove(appPkgName); + } + } else { + AppTheme appTheme = new AppTheme(overlay, icon, font); + appThemes.put(appPkgName, appTheme); + } } ThemeConfig themeConfig = new ThemeConfig(appThemes); themeConfig.mThemeChangeTimestamp = mThemeChangeTimestamp; diff --git a/core/java/android/content/res/ThemeManager.java b/core/java/android/content/res/ThemeManager.java index a9d2fcc..fd05f1e 100644 --- a/core/java/android/content/res/ThemeManager.java +++ b/core/java/android/content/res/ThemeManager.java @@ -222,16 +222,34 @@ public class ThemeManager { } public void requestThemeChange(String pkgName, List<String> components) { + requestThemeChange(pkgName, components, true); + } + + public void requestThemeChange(String pkgName, List<String> components, + boolean removePerAppThemes) { Map<String, String> componentMap = new HashMap<String, String>(components.size()); for (String component : components) { componentMap.put(component, pkgName); } - requestThemeChange(componentMap); + requestThemeChange(componentMap, removePerAppThemes); } public void requestThemeChange(Map<String, String> componentMap) { + requestThemeChange(componentMap, true); + } + + public void requestThemeChange(Map<String, String> componentMap, boolean removePerAppThemes) { + ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); + for (String component : componentMap.keySet()) { + builder.setComponent(component, componentMap.get(component)); + } + + requestThemeChange(builder.build(), removePerAppThemes); + } + + public void requestThemeChange(ThemeChangeRequest request, boolean removePerAppThemes) { try { - mService.requestThemeChange(componentMap); + mService.requestThemeChange(request, removePerAppThemes); } catch (RemoteException e) { logThemeServiceException(e); } diff --git a/services/core/java/com/android/server/ThemeService.java b/services/core/java/com/android/server/ThemeService.java index 6547a41..d2fa28e 100644 --- a/services/core/java/com/android/server/ThemeService.java +++ b/services/core/java/com/android/server/ThemeService.java @@ -37,12 +37,12 @@ import android.content.pm.ThemeUtils; import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.IThemeProcessingListener; +import android.content.res.ThemeChangeRequest; import android.content.res.ThemeConfig; import android.content.res.IThemeChangeListener; import android.content.res.IThemeService; import android.database.Cursor; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.media.RingtoneManager; import android.os.Binder; import android.os.Environment; @@ -136,8 +136,8 @@ public class ThemeService extends IThemeService.Stub { public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_CHANGE_THEME: - final Map<String, String> componentMap = (Map<String, String>) msg.obj; - doApplyTheme(componentMap); + final ThemeChangeRequest request = (ThemeChangeRequest) msg.obj; + doApplyTheme(request, msg.arg1 == 1); break; case MESSAGE_APPLY_DEFAULT_THEME: doApplyDefaultTheme(); @@ -280,7 +280,7 @@ public class ThemeService extends IThemeService.Stub { // of the pkg with the system. If it is not compatible then we will add it to a theme // change request. Map<String, String> defaults = ThemeUtils.getDefaultComponents(mContext); - HashMap<String, String> changeThemeRequestMap = new HashMap<String, String>(); + ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); for(Map.Entry<String, String> entry : currentThemeMap.entrySet()) { String component = entry.getKey(); String pkgName = entry.getValue(); @@ -303,14 +303,15 @@ public class ThemeService extends IThemeService.Stub { if (!isThemeCompatibleWithUpgradedApi(pkgName)) { Log.d(TAG, pkgName + "is incompatible with latest theme api for component " + component + ", Applying " + defaultPkg); - changeThemeRequestMap.put(component, pkgName); + builder.setComponent(component, pkgName); } } // Now actually unapply the incompatible themes - if (!changeThemeRequestMap.isEmpty()) { + ThemeChangeRequest request = builder.build(); + if (!request.getThemeComponentsMap().isEmpty()) { try { - requestThemeChange(changeThemeRequestMap); + requestThemeChange(request, true); } catch(RemoteException e) { // This cannot happen } @@ -361,13 +362,13 @@ public class ThemeService extends IThemeService.Stub { } } - private void doApplyTheme(Map<String, String> componentMap) { + private void doApplyTheme(ThemeChangeRequest request, boolean removePerAppTheme) { synchronized(this) { mProgress = 0; } - if (componentMap == null || componentMap.size() == 0) { - postFinish(true, componentMap); + if (request == null || request.getNumChangesRequested() == 0) { + postFinish(true, request); return; } mIsThemeApplying = true; @@ -375,75 +376,59 @@ public class ThemeService extends IThemeService.Stub { incrementProgress(5); // TODO: provide progress updates that reflect the time needed for each component - final int progressIncrement = 75 / componentMap.size(); + final int progressIncrement = 75 / request.getNumChangesRequested(); - if (componentMap.containsKey(ThemesColumns.MODIFIES_ICONS)) { - if (!updateIcons(componentMap.get(ThemesColumns.MODIFIES_ICONS))) { - componentMap.remove(ThemesColumns.MODIFIES_ICONS); - } + if (request.getIconsThemePackageName() != null) { + updateIcons(request.getIconsThemePackageName()); incrementProgress(progressIncrement); } - if (componentMap.containsKey(ThemesColumns.MODIFIES_LAUNCHER)) { - if (updateWallpaper(componentMap.get(ThemesColumns.MODIFIES_LAUNCHER))) { + if (request.getWallpaperThemePackageName() != null) { + if (updateWallpaper(request.getWallpaperThemePackageName())) { mWallpaperChangedByUs = true; - } else { - componentMap.remove(ThemesColumns.MODIFIES_LAUNCHER); } incrementProgress(progressIncrement); } - if (componentMap.containsKey(ThemesColumns.MODIFIES_LOCKSCREEN)) { - if (!updateLockscreen(componentMap.get(ThemesColumns.MODIFIES_LOCKSCREEN))) { - componentMap.remove(ThemesColumns.MODIFIES_LOCKSCREEN); - } + if (request.getLockWallpaperThemePackageName() != null) { + updateLockscreen(request.getLockWallpaperThemePackageName()); incrementProgress(progressIncrement); } - if (componentMap.containsKey(ThemesColumns.MODIFIES_NOTIFICATIONS)) { - if (!updateNotifications(componentMap.get(ThemesColumns.MODIFIES_NOTIFICATIONS))) { - componentMap.remove(ThemesColumns.MODIFIES_NOTIFICATIONS); - } + Environment.setUserRequired(false); + if (request.getNotificationThemePackageName() != null) { + updateNotifications(request.getNotificationThemePackageName()); incrementProgress(progressIncrement); } - Environment.setUserRequired(false); - if (componentMap.containsKey(ThemesColumns.MODIFIES_ALARMS)) { - if (!updateAlarms(componentMap.get(ThemesColumns.MODIFIES_ALARMS))) { - componentMap.remove(ThemesColumns.MODIFIES_ALARMS); - } + if (request.getAlarmThemePackageName() != null) { + updateNotifications(request.getAlarmThemePackageName()); incrementProgress(progressIncrement); } - if (componentMap.containsKey(ThemesColumns.MODIFIES_RINGTONES)) { - if (!updateRingtones(componentMap.get(ThemesColumns.MODIFIES_RINGTONES))) { - componentMap.remove(ThemesColumns.MODIFIES_RINGTONES); - } + if (request.getRingtoneThemePackageName() != null) { + updateNotifications(request.getRingtoneThemePackageName()); incrementProgress(progressIncrement); } + Environment.setUserRequired(true); - if (componentMap.containsKey(ThemesColumns.MODIFIES_BOOT_ANIM)) { - if (!updateBootAnim(componentMap.get(ThemesColumns.MODIFIES_BOOT_ANIM))) { - componentMap.remove(ThemesColumns.MODIFIES_BOOT_ANIM); - } + if (request.getBootanimationThemePackageName() != null) { + updateBootAnim(request.getBootanimationThemePackageName()); incrementProgress(progressIncrement); } - Environment.setUserRequired(true); - if (componentMap.containsKey(ThemesColumns.MODIFIES_FONTS)) { - if (!updateFonts(componentMap.get(ThemesColumns.MODIFIES_FONTS))) { - componentMap.remove(ThemesColumns.MODIFIES_FONTS); - } + if (request.getFontThemePackageName() != null) { + updateFonts(request.getFontThemePackageName()); incrementProgress(progressIncrement); } - updateProvider(componentMap); + updateProvider(request); - updateConfiguration(componentMap); + updateConfiguration(request, removePerAppTheme); - killLaunchers(componentMap); + killLaunchers(request); - postFinish(true, componentMap); + postFinish(true, request); mIsThemeApplying = false; } @@ -461,12 +446,12 @@ public class ThemeService extends IThemeService.Stub { components = new ArrayList<String>( Arrays.asList(defaultThemeComponents.split("\\|"))); } - Map<String, String> componentMap = new HashMap<String, String>(components.size()); + ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); for (String component : components) { - componentMap.put(component, defaultThemePkg); + builder.setComponent(component, defaultThemePkg); } try { - requestThemeChange(componentMap); + requestThemeChange(builder.build(), true); } catch (RemoteException e) { Log.w(TAG, "Unable to set default theme", e); } @@ -478,9 +463,10 @@ public class ThemeService extends IThemeService.Stub { processInstalledThemes(); } - private void updateProvider(Map<String, String> componentMap) { + private void updateProvider(ThemeChangeRequest request) { ContentValues values = new ContentValues(); + Map<String, String> componentMap = request.getThemeComponentsMap(); for (String component : componentMap.keySet()) { values.put(ThemesContract.MixnMatchColumns.COL_VALUE, componentMap.get(component)); String where = ThemesContract.MixnMatchColumns.COL_KEY + "=?"; @@ -721,13 +707,15 @@ public class ThemeService extends IThemeService.Stub { return true; } - private boolean updateConfiguration(Map<String, String> components) { + private boolean updateConfiguration(ThemeChangeRequest request, + boolean removePerAppThemes) { final IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { final long token = Binder.clearCallingIdentity(); try { Configuration config = am.getConfiguration(); - ThemeConfig.Builder themeBuilder = createBuilderFrom(config, components, null); + ThemeConfig.Builder themeBuilder = createBuilderFrom(config, request, null, + removePerAppThemes); ThemeConfig newConfig = themeBuilder.build(); config.themeConfig = newConfig; @@ -742,32 +730,40 @@ public class ThemeService extends IThemeService.Stub { } private static ThemeConfig.Builder createBuilderFrom(Configuration config, - Map<String, String> componentMap, String pkgName) { + ThemeChangeRequest request, String pkgName, boolean removePerAppThemes) { ThemeConfig.Builder builder = new ThemeConfig.Builder(config.themeConfig); - if (componentMap.containsKey(ThemesColumns.MODIFIES_ICONS)) { - builder.defaultIcon(pkgName == null ? - componentMap.get(ThemesColumns.MODIFIES_ICONS) : pkgName); + if (removePerAppThemes) removePerAppThemesFromConfig(builder, config.themeConfig); + + if (request.getIconsThemePackageName() != null) { + builder.defaultIcon(pkgName == null ? request.getIconsThemePackageName() : pkgName); } - if (componentMap.containsKey(ThemesColumns.MODIFIES_OVERLAYS)) { + if (request.getOverlayThemePackageName() != null) { builder.defaultOverlay(pkgName == null ? - componentMap.get(ThemesColumns.MODIFIES_OVERLAYS) : pkgName); + request.getOverlayThemePackageName() : pkgName); } - if (componentMap.containsKey(ThemesColumns.MODIFIES_FONTS)) { - builder.defaultFont(pkgName == null ? - componentMap.get(ThemesColumns.MODIFIES_FONTS) : pkgName); + if (request.getFontThemePackageName() != null) { + builder.defaultFont(pkgName == null ? request.getFontThemePackageName() : pkgName); } - if (componentMap.containsKey(ThemesColumns.MODIFIES_STATUS_BAR)) { + if (request.getStatusBarThemePackageName() != null) { builder.overlay(ThemeConfig.SYSTEMUI_STATUS_BAR_PKG, pkgName == null ? - componentMap.get(ThemesColumns.MODIFIES_STATUS_BAR) : pkgName); + request.getStatusBarThemePackageName() : pkgName); } - if (componentMap.containsKey(ThemesColumns.MODIFIES_NAVIGATION_BAR)) { + if (request.getNavBarThemePackageName() != null) { builder.overlay(ThemeConfig.SYSTEMUI_NAVBAR_PKG, pkgName == null ? - componentMap.get(ThemesColumns.MODIFIES_NAVIGATION_BAR) : pkgName); + request.getNavBarThemePackageName() : pkgName); + } + + // check for any per app overlays being applied + Map<String, String> appOverlays = request.getPerAppOverlays(); + for (String appPkgName : appOverlays.keySet()) { + if (appPkgName != null) { + builder.overlay(appPkgName, appOverlays.get(appPkgName)); + } } builder.setThemeChangeTimestamp(System.currentTimeMillis()); @@ -775,11 +771,23 @@ public class ThemeService extends IThemeService.Stub { return builder; } + private static void removePerAppThemesFromConfig(ThemeConfig.Builder builder, + ThemeConfig themeConfig) { + if (themeConfig != null) { + Map<String, ThemeConfig.AppTheme> themes = themeConfig.getAppThemes(); + for (String appPkgName : themes.keySet()) { + if (ThemeUtils.isPerAppThemeComponent(appPkgName)) { + builder.overlay(appPkgName, null); + } + } + } + } + // Kill the current Home process, they tend to be evil and cache // drawable references in all apps - private void killLaunchers(Map<String, String> componentMap) { - if (!(componentMap.containsKey(ThemesColumns.MODIFIES_ICONS) - || componentMap.containsKey(ThemesColumns.MODIFIES_OVERLAYS))) { + private void killLaunchers(ThemeChangeRequest request) { + if (request.getOverlayThemePackageName() == null + && request.getIconsThemePackageName() == null) { return; } @@ -838,7 +846,7 @@ public class ThemeService extends IThemeService.Stub { mClients.finishBroadcast(); } - private void postFinish(boolean isSuccess, Map<String, String> componentMap) { + private void postFinish(boolean isSuccess, ThemeChangeRequest request) { synchronized(this) { mProgress = 0; } @@ -856,7 +864,7 @@ public class ThemeService extends IThemeService.Stub { // if successful, broadcast that the theme changed if (isSuccess) { - broadcastThemeChange(componentMap); + broadcastThemeChange(request); } } @@ -873,9 +881,12 @@ public class ThemeService extends IThemeService.Stub { mProcessingListeners.finishBroadcast(); } - private void broadcastThemeChange(Map<String, String> components) { + private void broadcastThemeChange(ThemeChangeRequest request) { + Map<String, String> componentMap = request.getThemeComponentsMap(); + if (componentMap == null || componentMap.size() == 0) return; + final Intent intent = new Intent(ThemeUtils.ACTION_THEME_CHANGED); - ArrayList componentsArrayList = new ArrayList(components.keySet()); + ArrayList componentsArrayList = new ArrayList(componentMap.keySet()); intent.putStringArrayListExtra("components", componentsArrayList); mContext.sendBroadcastAsUser(intent, UserHandle.ALL); } @@ -903,7 +914,8 @@ public class ThemeService extends IThemeService.Stub { } @Override - public void requestThemeChange(Map componentMap) throws RemoteException { + public void requestThemeChange(ThemeChangeRequest request, boolean removePerAppThemes) + throws RemoteException { mContext.enforceCallingOrSelfPermission( Manifest.permission.ACCESS_THEME_MANAGER, null); Message msg; @@ -917,6 +929,7 @@ public class ThemeService extends IThemeService.Stub { * the theme will be applied once the processing is done. */ synchronized (mThemesToProcessQueue) { + Map<String, String> componentMap = request.getThemeComponentsMap(); for (Object key : componentMap.keySet()) { if (ThemesColumns.MODIFIES_OVERLAYS.equals(key) || ThemesColumns.MODIFIES_NAVIGATION_BAR.equals(key) || @@ -928,16 +941,17 @@ public class ThemeService extends IThemeService.Stub { mThemesToProcessQueue.add(0, pkgName); // We want to make sure these resources are taken care of first so // send the dequeue message and place it in the front of the queue - msg = mHandler.obtainMessage( + msg = mResourceProcessingHandler.obtainMessage( ResourceProcessingHandler.MESSAGE_DEQUEUE_AND_PROCESS_THEME); - mHandler.sendMessageAtFrontOfQueue(msg); + mResourceProcessingHandler.sendMessageAtFrontOfQueue(msg); } } } } msg = Message.obtain(); msg.what = ThemeWorkerHandler.MESSAGE_CHANGE_THEME; - msg.obj = componentMap; + msg.obj = request; + msg.arg1 = removePerAppThemes ? 1 : 0; mHandler.sendMessage(msg); } @@ -1091,9 +1105,9 @@ public class ThemeService extends IThemeService.Stub { public void onReceive(Context context, Intent intent) { if (!mWallpaperChangedByUs) { // In case the mixnmatch table has a mods_launcher entry, we'll clear it - Map<String, String> components = new HashMap<String, String>(1); - components.put(ThemesColumns.MODIFIES_LAUNCHER, ""); - updateProvider(components); + ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); + builder.setWallpaper(""); + updateProvider(builder.build()); } else { mWallpaperChangedByUs = false; } |