diff options
author | Ricardo Cerqueira <github@cerqueira.org> | 2012-05-05 18:49:09 +0100 |
---|---|---|
committer | Ricardo Cerqueira <github@cerqueira.org> | 2012-05-05 18:49:17 +0100 |
commit | e821f5b727ef247a789557badb6640880cf992dd (patch) | |
tree | fc74bf9cc07a3eac04166477bed32ee5f9583d40 /core/java/android/content | |
parent | f0b7008ac173a4402b982b0f50ca3db8b0659bb7 (diff) | |
parent | fd6ee4e7d2f1600021c0d2f47914c01600bd1b97 (diff) | |
download | frameworks_base-e821f5b727ef247a789557badb6640880cf992dd.zip frameworks_base-e821f5b727ef247a789557badb6640880cf992dd.tar.gz frameworks_base-e821f5b727ef247a789557badb6640880cf992dd.tar.bz2 |
Merge branch 'themes-4.0' into 'ics'
Change-Id: Idc363f8140be2d252bee2aeba46c944032fb0ae9
Diffstat (limited to 'core/java/android/content')
17 files changed, 1170 insertions, 8 deletions
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 34966bb..af6f3b3 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -2140,6 +2141,19 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED"; + /** + * Broadcast Action: Indicate that unrecoverable error happened during app launch. + * Could indicate that curently applied theme is malicious. + * @hide + */ + public static final String ACTION_APP_LAUNCH_FAILURE = "com.tmobile.intent.action.APP_LAUNCH_FAILURE"; + + /** + * Broadcast Action: Request to reset the unrecoverable errors count to 0. + * @hide + */ + public static final String ACTION_APP_LAUNCH_FAILURE_RESET = "com.tmobile.intent.action.APP_LAUNCH_FAILURE_RESET"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). @@ -2272,6 +2286,7 @@ public class Intent implements Parcelable, Cloneable { */ public static final String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST = "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"; + /** * An activity to run when device is inserted into a car dock. * Used with {@link #ACTION_MAIN} to launch an activity. For more @@ -2308,6 +2323,14 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE"; + /** + * Used to indicate that a theme package has been installed or un-installed. + * + * @hide + */ + public static final String CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE = + "com.tmobile.intent.category.THEME_PACKAGE_INSTALL_STATE_CHANGE"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Application launch intent categories (see addCategory()). diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 0e6694d..d320768 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -321,6 +322,10 @@ public class ActivityInfo extends ComponentInfo */ public static final int CONFIG_ORIENTATION = 0x0080; /** + * @hide + */ + public static final int CONFIG_THEME_RESOURCE = 0x008000; + /** * Bit in {@link #configChanges} that indicates that the activity * can itself handle changes to the screen layout. Set from the * {@link android.R.attr#configChanges} attribute. diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 65a8750..af7dcd2 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -419,6 +420,30 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * @hide */ public int enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + /** + * Is given application theme agnostic, i.e. behaves properly when default theme is changed. + * {@hide} + */ + public boolean isThemeable = false; + + private static final String PLUTO_SCHEMA = "http://www.w3.org/2001/pluto.html"; + + /** + * @hide + */ + public static final String PLUTO_ISTHEMEABLE_ATTRIBUTE_NAME = "isThemeable"; + + /** + * @hide + */ + public static final String PLUTO_HANDLE_THEME_CONFIG_CHANGES_ATTRIBUTE_NAME = "handleThemeConfigChanges"; + + /** + * @hide + */ + public static boolean isPlutoNamespace(String namespace) { + return namespace != null && namespace.equalsIgnoreCase(PLUTO_SCHEMA); + } /** * For convenient access to package's install location. @@ -520,6 +545,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { manageSpaceActivityName = orig.manageSpaceActivityName; descriptionRes = orig.descriptionRes; uiOptions = orig.uiOptions; + isThemeable = orig.isThemeable; } @@ -559,6 +585,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeString(backupAgentName); dest.writeInt(descriptionRes); dest.writeInt(uiOptions); + dest.writeInt(isThemeable? 1 : 0); } public static final Parcelable.Creator<ApplicationInfo> CREATOR @@ -597,6 +624,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { backupAgentName = source.readString(); descriptionRes = source.readInt(); uiOptions = source.readInt(); + isThemeable = source.readInt() != 0; } /** diff --git a/core/java/android/content/pm/BaseThemeInfo.java b/core/java/android/content/pm/BaseThemeInfo.java new file mode 100644 index 0000000..0171137b --- /dev/null +++ b/core/java/android/content/pm/BaseThemeInfo.java @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2010, T-Mobile USA, Inc. + * + * 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.pm; + +import android.os.Parcelable; +import android.os.Parcel; +import android.util.Log; +import android.util.AttributeSet; +import android.content.res.Resources; + +/** + * @hide + */ +public class BaseThemeInfo implements Parcelable { + + /** + * Wallpaper drawable. + * + * @see wallpaperImage attribute + */ + public int wallpaperResourceId; + + /** + * The resource id of theme thumbnail. + * Specifies a theme thumbnail image resource as @drawable/foo. + * + * @see thumbnail attribute + * + */ + public int thumbnailResourceId; + + /** + * The theme id, which does not change when the theme is modified. + * Specifies an Android UI Style using style name. + * + * @see themeId attribute + * + */ + public String themeId; + + /** + * The style resource id of Android UI Style, supplied by the resource commpiler. + * Specifies an Android UI Style id. + * + * @see styleId attribute + * + */ + public int styleResourceId = 0; + + /** + * The name of the theme (as displayed by UI). + * + * @see name attribute + * + */ + public String name; + + /** + * The name of the call ringtone audio file. + * Specifies a relative path in assets subfolder. + * If the parent's name is "locked" - DRM protected. + * + * @see ringtoneFileName attribute + * + */ + public String ringtoneFileName; + + /** + * The name of the call ringtone as shown to user. + * + * @see ringtoneName attribute + * + */ + public String ringtoneName; + + /** + * The name of the notification ringtone audio file. + * Specifies a relative path in assets subfolder. + * If the parent's name is "locked" - DRM protected. + * + * @see notificationRingtoneFileName attribute + * + */ + public String notificationRingtoneFileName; + + /** + * The name of the notification ringtone as shown to user. + * + * @see notificationRingtoneName attribute + * + */ + public String notificationRingtoneName; + + /** + * The author name of the theme package. + * + * @see author attribute + * + */ + public String author; + + /** + * The copyright text. + * + * @see copyright attribute + * + */ + public String copyright; + + /** + * {@hide} + */ + // There is no corresposponding flag in manifest file + // This flag is set to true iff any media resource is DRM protected + public boolean isDrmProtected = false; + + /** + * The name of the "main" theme style (as displayed by UI). + * + * @see themeStyleName attribute + * + */ + public String themeStyleName; + + /** + * Preview image drawable. + * + * @see preview attribute + */ + public int previewResourceId; + + /** + * The name of a sound pack. + * + * @see soundpack attribute + * + */ + public String soundPackName; + + + private static final String LOCKED_NAME = "locked/"; + + /* + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return a bitmask indicating the set of special object types marshalled + * by the Parcelable. + * + * @see android.os.Parcelable#describeContents() + */ + public int describeContents() { + return 0; + } + + /* + * Flatten this object in to a Parcel. + * + * @param dest The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. + * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}. + * + * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int) + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(wallpaperResourceId); + dest.writeInt(thumbnailResourceId); + dest.writeString(themeId); + dest.writeInt(styleResourceId); + dest.writeString(name); + dest.writeString(ringtoneFileName); + dest.writeString(notificationRingtoneFileName); + dest.writeString(ringtoneName); + dest.writeString(notificationRingtoneName); + dest.writeString(author); + dest.writeString(copyright); + dest.writeInt(isDrmProtected? 1 : 0); + dest.writeString(soundPackName); + dest.writeString(themeStyleName); + dest.writeInt(previewResourceId); + } + + /** @hide */ + public static final Parcelable.Creator<BaseThemeInfo> CREATOR + = new Parcelable.Creator<BaseThemeInfo>() { + public BaseThemeInfo createFromParcel(Parcel source) { + return new BaseThemeInfo(source); + } + + public BaseThemeInfo[] newArray(int size) { + return new BaseThemeInfo[size]; + } + }; + + /** @hide */ + public final String getResolvedString(Resources res, AttributeSet attrs, int index) { + int resId = attrs.getAttributeResourceValue(index, 0); + if (resId !=0 ) { + return res.getString(resId); + } + return attrs.getAttributeValue(index); + } + + protected BaseThemeInfo() { + } + + protected BaseThemeInfo(Parcel source) { + wallpaperResourceId = source.readInt(); + thumbnailResourceId = source.readInt(); + themeId = source.readString(); + styleResourceId = source.readInt(); + name = source.readString(); + ringtoneFileName = source.readString(); + notificationRingtoneFileName = source.readString(); + ringtoneName = source.readString(); + notificationRingtoneName = source.readString(); + author = source.readString(); + copyright = source.readString(); + isDrmProtected = (source.readInt() != 0); + soundPackName = source.readString(); + themeStyleName = source.readString(); + previewResourceId = source.readInt(); + } + + protected void changeDrmFlagIfNeeded(String resourcePath) { + if (resourcePath != null && resourcePath.contains(LOCKED_NAME)) { + isDrmProtected = true; + } + } +} diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index decb974..0842820 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -39,6 +39,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.ThemeInfo; import android.net.Uri; import android.content.IntentSender; @@ -121,6 +122,8 @@ interface IPackageManager { */ ParceledListSlice getInstalledPackages(int flags, in String lastRead); + List<PackageInfo> getInstalledThemePackages(); + /** * This implements getInstalledApplications via a "last returned row" * mechanism that is not exposed in the API. This is to get around the IPC diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index eb05d76..42dd621 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -194,9 +195,69 @@ public class PackageInfo implements Parcelable { */ public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY; + // Is Theme Apk + /** + * {@hide} + */ + public boolean isThemeApk = false; + + // ThemeInfo + /** + * {@hide} + */ + public ThemeInfo [] themeInfos; + public PackageInfo() { } + /* + * Is Theme Apk is DRM protected (contains DRM-protected resources) + * + */ + private boolean drmProtectedThemeApk = false; + + /** + * @hide + * + * @return Is Theme Apk is DRM protected (contains DRM-protected resources) + */ + public boolean isDrmProtectedThemeApk() { + return drmProtectedThemeApk; + } + + /** + * @hide + * + * @param value if Theme Apk is DRM protected (contains DRM-protected resources) + */ + public void setDrmProtectedThemeApk(boolean value) { + drmProtectedThemeApk = value; + } + + /* + * If isThemeApk and isDrmProtectedThemeApk are true - path to hidden locked zip file + * + */ + private String lockedZipFilePath; + + /** + * @hide + * + * @return path for hidden locked zip file + */ + public String getLockedZipFilePath() { + return lockedZipFilePath; + } + + /** + * @hide + * + * @param value path for hidden locked zip file + */ + public void setLockedZipFilePath(String value) { + lockedZipFilePath = value; + } + public String toString() { return "PackageInfo{" + Integer.toHexString(System.identityHashCode(this)) @@ -233,6 +294,12 @@ public class PackageInfo implements Parcelable { dest.writeTypedArray(configPreferences, parcelableFlags); dest.writeTypedArray(reqFeatures, parcelableFlags); dest.writeInt(installLocation); + + /* Theme-specific. */ + dest.writeInt((isThemeApk)? 1 : 0); + dest.writeInt((drmProtectedThemeApk)? 1 : 0); + dest.writeTypedArray(themeInfos, parcelableFlags); + dest.writeString(lockedZipFilePath); } public static final Parcelable.Creator<PackageInfo> CREATOR @@ -270,5 +337,11 @@ public class PackageInfo implements Parcelable { configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR); reqFeatures = source.createTypedArray(FeatureInfo.CREATOR); installLocation = source.readInt(); + + /* Theme-specific. */ + isThemeApk = (source.readInt() != 0); + drmProtectedThemeApk = (source.readInt() != 0); + themeInfos = source.createTypedArray(ThemeInfo.CREATOR); + lockedZipFilePath = source.readString(); } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 8541748..c249a53 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1407,6 +1408,17 @@ public abstract class PackageManager { public abstract List<PackageInfo> getInstalledPackages(int flags); /** + * Return a List of all theme packages that are installed + * on the device. + * + * @return A List of PackageInfo objects, one for each theme package + * that is installed on the device. + * + * @hide + */ + public abstract List<PackageInfo> getInstalledThemePackages(); + + /** * Check whether a particular package has been granted a particular * permission. * diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index e593d5b..fddd0bc 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -200,6 +201,17 @@ public class PackageParser { return name.endsWith(".apk"); } + public static String getLockedZipFilePath(String path) { + if (path == null) { + return null; + } + if (isPackageFilename(path)) { + return path.substring(0, path.length() - 4) + ".locked.zip"; + } else { + return path + ".locked.zip"; + } + } + /** * Generate and return the {@link PackageInfo} for a parsed package. * @@ -215,6 +227,21 @@ public class PackageParser { pi.versionName = p.mVersionName; pi.sharedUserId = p.mSharedUserId; pi.sharedUserLabel = p.mSharedUserLabel; + pi.isThemeApk = p.mIsThemeApk; + pi.setDrmProtectedThemeApk(false); + if (pi.isThemeApk) { + int N = p.mThemeInfos.size(); + if (N > 0) { + pi.themeInfos = new ThemeInfo[N]; + for (int i = 0; i < N; i++) { + pi.themeInfos[i] = p.mThemeInfos.get(i); + pi.setDrmProtectedThemeApk(pi.isDrmProtectedThemeApk() || pi.themeInfos[i].isDrmProtected); + } + if (pi.isDrmProtectedThemeApk()) { + pi.setLockedZipFilePath(PackageParser.getLockedZipFilePath(p.mPath)); + } + } + } pi.applicationInfo = generateApplicationInfo(p, flags); pi.installLocation = p.installLocation; pi.firstInstallTime = firstInstallTime; @@ -1180,7 +1207,10 @@ public class PackageParser { // Just skip this tag XmlUtils.skipCurrentTag(parser); continue; - + } else if (tagName.equals("theme")) { + // this is a theme apk. + pkg.mIsThemeApk = true; + pkg.mThemeInfos.add(new ThemeInfo(parser, res, attrs)); } else if (RIGID_PARSER) { outError[0] = "Bad element under <manifest>: " + parser.getName(); @@ -1253,6 +1283,9 @@ public class PackageParser { >= android.os.Build.VERSION_CODES.DONUT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; } + if (pkg.mIsThemeApk) { + pkg.applicationInfo.isThemeable = false; + } return pkg; } @@ -1536,12 +1569,43 @@ public class PackageParser { return a; } + private void parseApplicationThemeAttributes(XmlPullParser parser, AttributeSet attrs, + ApplicationInfo appInfo) { + for (int i = 0; i < attrs.getAttributeCount(); i++) { + if (!ApplicationInfo.isPlutoNamespace(parser.getAttributeNamespace(i))) { + continue; + } + String attrName = attrs.getAttributeName(i); + if (attrName.equalsIgnoreCase(ApplicationInfo.PLUTO_ISTHEMEABLE_ATTRIBUTE_NAME)) { + appInfo.isThemeable = attrs.getAttributeBooleanValue(i, false); + return; + } + } + } + + private void parseActivityThemeAttributes(XmlPullParser parser, AttributeSet attrs, + ActivityInfo ai) { + for (int i = 0; i < attrs.getAttributeCount(); i++) { + if (!ApplicationInfo.isPlutoNamespace(parser.getAttributeNamespace(i))) { + continue; + } + String attrName = attrs.getAttributeName(i); + if (attrName.equalsIgnoreCase(ApplicationInfo.PLUTO_HANDLE_THEME_CONFIG_CHANGES_ATTRIBUTE_NAME)) { + ai.configChanges |= ActivityInfo.CONFIG_THEME_RESOURCE; + } + } + } + private boolean parseApplication(Package owner, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) throws XmlPullParserException, IOException { final ApplicationInfo ai = owner.applicationInfo; final String pkgName = owner.applicationInfo.packageName; + // assume that this package is themeable unless explicitly set to false. + ai.isThemeable = true; + parseApplicationThemeAttributes(parser, attrs, ai); + TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestApplication); @@ -2045,6 +2109,8 @@ public class PackageParser { return null; } + parseActivityThemeAttributes(parser, attrs, a.info); + int outerDepth = parser.getDepth(); int type; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT @@ -2982,6 +3048,12 @@ public class PackageParser { // For use by package manager to keep track of where it has done dexopt. public boolean mDidDexOpt; + // Is Theme Apk + public boolean mIsThemeApk = false; + + // Theme info + public final ArrayList<ThemeInfo> mThemeInfos = new ArrayList<ThemeInfo>(0); + // User set enabled state. public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; diff --git a/core/java/android/content/pm/ThemeInfo.aidl b/core/java/android/content/pm/ThemeInfo.aidl new file mode 100755 index 0000000..acbc85e --- /dev/null +++ b/core/java/android/content/pm/ThemeInfo.aidl @@ -0,0 +1,3 @@ +package android.content.pm; + +parcelable ThemeInfo; diff --git a/core/java/android/content/pm/ThemeInfo.java b/core/java/android/content/pm/ThemeInfo.java new file mode 100644 index 0000000..e51dbb6 --- /dev/null +++ b/core/java/android/content/pm/ThemeInfo.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2010, T-Mobile USA, Inc. + * + * 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.pm; + +import java.util.HashMap; +import java.util.Map; + +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParser; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.content.res.Resources; + +/** + * Overall information about "theme" package. This corresponds + * to the information collected from AndroidManifest.xml (theme tag). + * + * Below is an example of theme tag + * <theme + * pluto:name="Pluto Default" + * pluto:preview="@drawable/preview" + * pluto:author="John Doe" + * pluto:ringtoneFileName="media/audio/ringtone.mp3" + * pluto:notificationRingtoneFileName="media/audio/locked/notification.mp3" + * pluto:copyright="T-Mobile, 2009" + * /> + * + * @hide + */ +public final class ThemeInfo extends BaseThemeInfo { + private enum AttributeIndex { + THEME_PACKAGE_INDEX, + PREVIEW_INDEX, + AUTHOR_INDEX, + THEME_INDEX, + THEME_STYLE_NAME_INDEX, + THUMBNAIL_INDEX, + RINGTONE_FILE_NAME_INDEX, + NOTIFICATION_RINGTONE_FILE_NAME_INDEX, + WALLPAPER_IMAGE_INDEX, + COPYRIGHT_INDEX, + RINGTONE_NAME_INDEX, + NOTIFICATION_RINGTONE_NAME_INDEX, + STYLE_INDEX; + + public static AttributeIndex get(int ordinal) { + return values()[ordinal]; + } + }; + + private static final String [] compulsoryAttributes = new String [] { + "name", + "preview", + "author", + "themeId", + "styleName", + }; + + private static final String [] optionalAttributes = new String [] { + "thumbnail", + "ringtoneFileName", + "notificationRingtoneFileName", + "wallpaperImage", + "copyright", + "ringtoneName", + "notificationRingtoneName", + "styleId", + }; + + private static final Map<String, AttributeIndex> sAttributesLookupTable; + + static { + sAttributesLookupTable = new HashMap<String, AttributeIndex>(); + for (int i = 0; i < compulsoryAttributes.length; i++) { + sAttributesLookupTable.put(compulsoryAttributes[i], AttributeIndex.get(i)); + } + + for (int i = 0; i < optionalAttributes.length; i++) { + sAttributesLookupTable.put(optionalAttributes[i], + AttributeIndex.get(compulsoryAttributes.length + i)); + } + } + + public ThemeInfo(XmlPullParser parser, Resources res, AttributeSet attrs) throws XmlPullParserException { + super(); + + Map<String, AttributeIndex> tempMap = + new HashMap<String, AttributeIndex>(sAttributesLookupTable); + int numberOfCompulsoryAttributes = 0; + for (int i = 0; i < attrs.getAttributeCount(); i++) { + if (!ApplicationInfo.isPlutoNamespace(parser.getAttributeNamespace(i))) { + continue; + } + String key = attrs.getAttributeName(i); + if (tempMap.containsKey(key)) { + AttributeIndex index = tempMap.get(key); + tempMap.remove(key); + + if (index.ordinal() < compulsoryAttributes.length) { + numberOfCompulsoryAttributes++; + } + switch (index) { + case THEME_PACKAGE_INDEX: + // theme name + name = getResolvedString(res, attrs, i); + break; + + case THUMBNAIL_INDEX: + // theme thumbprint + thumbnailResourceId = attrs.getAttributeResourceValue(i, 0); + break; + + case AUTHOR_INDEX: + // theme author + author = getResolvedString(res, attrs, i); + break; + + case THEME_INDEX: + // androidUiStyle attribute + themeId = attrs.getAttributeValue(i); + break; + + case THEME_STYLE_NAME_INDEX: + themeStyleName = getResolvedString(res, attrs, i); + break; + + case RINGTONE_FILE_NAME_INDEX: + // ringtone + ringtoneFileName = attrs.getAttributeValue(i); + changeDrmFlagIfNeeded(ringtoneFileName); + break; + + case NOTIFICATION_RINGTONE_FILE_NAME_INDEX: + // notification ringtone + notificationRingtoneFileName = attrs.getAttributeValue(i); + changeDrmFlagIfNeeded(notificationRingtoneFileName); + break; + + case WALLPAPER_IMAGE_INDEX: + // wallpaperImage attribute + wallpaperResourceId = attrs.getAttributeResourceValue(i, 0); + break; + + case COPYRIGHT_INDEX: + // themeCopyright attribute + copyright = getResolvedString(res, attrs, i); + break; + + case RINGTONE_NAME_INDEX: + // ringtone UI name + ringtoneName = attrs.getAttributeValue(i); + break; + + case NOTIFICATION_RINGTONE_NAME_INDEX: + // notification ringtone UI name + notificationRingtoneName = attrs.getAttributeValue(i); + break; + + case STYLE_INDEX: + styleResourceId = attrs.getAttributeResourceValue(i, 0); + break; + + case PREVIEW_INDEX: + // theme thumbprint + previewResourceId = attrs.getAttributeResourceValue(i, 0); + break; + } + } + } + if (numberOfCompulsoryAttributes < compulsoryAttributes.length) { + throw new XmlPullParserException("Not all compulsory attributes are specified in <theme>"); + } + } + + public static final Parcelable.Creator<ThemeInfo> CREATOR + = new Parcelable.Creator<ThemeInfo>() { + public ThemeInfo createFromParcel(Parcel source) { + return new ThemeInfo(source); + } + + public ThemeInfo[] newArray(int size) { + return new ThemeInfo[size]; + } + }; + + private ThemeInfo(Parcel source) { + super(source); + } +} diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index ffefaa2..80d0946 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +19,7 @@ package android.content.res; import android.os.ParcelFileDescriptor; import android.util.Log; +import android.util.SparseArray; import android.util.TypedValue; import java.io.FileNotFoundException; @@ -77,6 +79,20 @@ public final class AssetManager { private boolean mOpen = true; private HashMap<Integer, RuntimeException> mRefStacks; + private String mAssetDir; + private String mAppName; + + private boolean mThemeSupport; + private String mThemePackageName; + private int mThemeCookie; + + /** + * Organize all added redirection maps using Java strong references to keep + * the native layer cleanup simple (that is, finalize() in Java will be + * responsible for delete in C++). + */ + private SparseArray<PackageRedirectionMap> mRedirections; + /** * Create a new AssetManager containing only the basic system assets. * Applications will not generally use this method, instead retrieving the @@ -252,6 +268,12 @@ public final class AssetManager { } } + /*package*/ final void recreateStringBlocks() { + synchronized (this) { + makeStringBlocks(true); + } + } + /*package*/ final void makeStringBlocks(boolean copyFromSystem) { final int sysNum = copyFromSystem ? sSystem.mStringBlocks.length : 0; final int num = getStringBlockCount(); @@ -460,6 +482,18 @@ public final class AssetManager { /** * {@hide} + * Split a theme package with DRM-protected resources into two files. + * + * @param packageFileName Original theme package file name. + * @param lockedFileName Name of the new "locked" file with DRM resources. + * @param drmProtectedresources Array of names of DRM-protected assets. + */ + public final int splitDrmProtectedThemePackage(String packageFileName, String lockedFileName, String [] drmProtectedresources) { + return splitThemePackage(packageFileName, lockedFileName, drmProtectedresources); + } + + /** + * {@hide} * Retrieve a non-asset as a compiled XML file. Not for use by * applications. * @@ -625,6 +659,110 @@ public final class AssetManager { } /** + * Delete a set of theme assets from the asset manager. Not for use by + * applications. Returns true if succeeded or false on failure. + * + * @hide + */ + public native final boolean detachThemePath(String packageName, int cookie); + + /** + * Attach a set of theme assets to the asset manager. If necessary, this + * method will forcefully update the internal ResTable data structure. + * + * @return Cookie of the added asset or 0 on failure. + * @hide + */ + public native final int attachThemePath(String path); + + /** + * Sets a flag indicating that this AssetManager should have themes + * attached, according to the initial request to create it by the + * ApplicationContext. + * + * {@hide} + */ + public final void setThemeSupport(boolean themeSupport) { + mThemeSupport = themeSupport; + } + + /** + * Should this AssetManager have themes attached, according to the initial + * request to create it by the ApplicationContext? + * + * {@hide} + */ + public final boolean hasThemeSupport() { + return mThemeSupport; + } + + /** + * Apply a heuristic to match-up all attributes from the source style with + * attributes in the destination style. For each match, an entry in the + * package redirection map will be inserted. + * + * {@hide} + */ + public native final boolean generateStyleRedirections(int resMapNative, int sourceStyle, + int destStyle); + + /** + * Get package name of current theme (may return null). + * {@hide} + */ + public String getThemePackageName() { + return mThemePackageName; + } + + /** + * Sets package name and highest level style id for current theme (null, 0 is allowed). + * {@hide} + */ + public void setThemePackageName(String packageName) { + mThemePackageName = packageName; + } + + /** + * Get asset cookie for current theme (may return 0). + * {@hide} + */ + public int getThemeCookie() { + return mThemeCookie; + } + + /** + * Sets asset cookie for current theme (0 if not a themed asset manager). + * {@hide} + */ + public void setThemeCookie(int cookie) { + mThemeCookie = cookie; + } + + /** + * Add a redirection map to the asset manager. All future resource lookups + * will consult this map. + * {@hide} + */ + public void addRedirections(PackageRedirectionMap map) { + if (mRedirections == null) { + mRedirections = new SparseArray<PackageRedirectionMap>(2); + } + mRedirections.append(map.getPackageId(), map); + addRedirectionsNative(map.getNativePointer()); + } + + /** + * Clear redirection map for the asset manager. + * {@hide} + */ + public void clearRedirections() { + if (mRedirections != null) { + mRedirections.clear(); + } + clearRedirectionsNative(); + } + + /** * Determine whether the state in this asset manager is up-to-date with * the files on the filesystem. If false is returned, you need to * instantiate a new AssetManager class to see the new data. @@ -741,6 +879,26 @@ public final class AssetManager { private native final int[] getArrayStringInfo(int arrayRes); /*package*/ native final int[] getArrayIntResource(int arrayRes); + private native final int splitThemePackage(String srcFileName, String dstFileName, String [] drmProtectedAssetNames); + + /** + * {@hide} + */ + public native final int getBasePackageCount(); + + /** + * {@hide} + */ + public native final String getBasePackageName(int index); + + /** + * {@hide} + */ + public native final int getBasePackageId(int index); + + private native final void addRedirectionsNative(int redirectionMapNativePointer); + private native final void clearRedirectionsNative(); + private native final void init(); private native final void destroy(); diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index 1c9285e..d6856c9 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -92,9 +92,15 @@ public class CompatibilityInfo implements Parcelable { */ public final float applicationInvertedScale; + /** + * Whether the application supports third-party theming. + */ + public final boolean isThemeable; + public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, boolean forceCompat) { int compatFlags = 0; + isThemeable = appInfo.isThemeable; if (appInfo.requiresSmallestWidthDp != 0 || appInfo.compatibleWidthLimitDp != 0 || appInfo.largestWidthLimitDp != 0) { @@ -242,17 +248,19 @@ public class CompatibilityInfo implements Parcelable { } private CompatibilityInfo(int compFlags, - int dens, float scale, float invertedScale) { + int dens, float scale, float invertedScale, boolean isThemeable) { mCompatibilityFlags = compFlags; applicationDensity = dens; applicationScale = scale; applicationInvertedScale = invertedScale; + this.isThemeable = isThemeable; } private CompatibilityInfo() { this(NEVER_NEEDS_COMPAT, DisplayMetrics.DENSITY_DEVICE, 1.0f, - 1.0f); + 1.0f, + true); } /** @@ -519,6 +527,7 @@ public class CompatibilityInfo implements Parcelable { if (applicationDensity != oc.applicationDensity) return false; if (applicationScale != oc.applicationScale) return false; if (applicationInvertedScale != oc.applicationInvertedScale) return false; + if (isThemeable != oc.isThemeable) return false; return true; } catch (ClassCastException e) { return false; @@ -556,6 +565,7 @@ public class CompatibilityInfo implements Parcelable { result = 31 * result + applicationDensity; result = 31 * result + Float.floatToIntBits(applicationScale); result = 31 * result + Float.floatToIntBits(applicationInvertedScale); + result = 31 * result + (isThemeable ? 1 : 0); return result; } @@ -570,6 +580,7 @@ public class CompatibilityInfo implements Parcelable { dest.writeInt(applicationDensity); dest.writeFloat(applicationScale); dest.writeFloat(applicationInvertedScale); + dest.writeInt(isThemeable ? 1 : 0); } public static final Parcelable.Creator<CompatibilityInfo> CREATOR @@ -588,5 +599,6 @@ public class CompatibilityInfo implements Parcelable { applicationDensity = source.readInt(); applicationScale = source.readFloat(); applicationInvertedScale = source.readFloat(); + isThemeable = source.readInt() == 1 ? true : false; } } diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 5c3a17a..9822936 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project + * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +21,9 @@ import android.content.pm.ActivityInfo; import android.os.Parcel; import android.os.Parcelable; import android.util.LocaleUtil; +import android.util.Log; +import android.os.SystemProperties; +import android.text.TextUtils; import java.util.Locale; @@ -56,6 +60,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration public Locale locale; /** + * @hide + */ + public CustomTheme customTheme; + + /** * Locale should persist on setting. This is hidden because it is really * questionable whether this is the right way to expose the functionality. * @hide @@ -214,7 +223,22 @@ public final class Configuration implements Parcelable, Comparable<Configuration public static final int ORIENTATION_PORTRAIT = 1; public static final int ORIENTATION_LANDSCAPE = 2; public static final int ORIENTATION_SQUARE = 3; - + + /** + * @hide + */ + public static final int THEME_UNDEFINED = 0; + + /** + * @hide + */ + public static final String THEME_ID_PERSISTENCE_PROPERTY = "persist.sys.themeId"; + + /** + * @hide + */ + public static final String THEME_PACKAGE_NAME_PERSISTENCE_PROPERTY = "persist.sys.themePackageName"; + /** * Overall orientation of the screen. May be one of * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}, @@ -327,6 +351,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration compatScreenHeightDp = o.compatScreenHeightDp; compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp; seq = o.seq; + if (o.customTheme != null) { + customTheme = (CustomTheme) o.customTheme.clone(); + } } public String toString() { @@ -444,6 +471,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration sb.append(" s."); sb.append(seq); } + sb.append(" themeResource="); + sb.append(customTheme); sb.append('}'); return sb.toString(); } @@ -470,6 +499,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; textLayoutDirection = LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE; seq = 0; + customTheme = null; } /** {@hide} */ @@ -589,7 +619,13 @@ public final class Configuration implements Parcelable, Comparable<Configuration if (delta.seq != 0) { seq = delta.seq; } - + + if (delta.customTheme != null + && (customTheme == null || !customTheme.equals(delta.customTheme))) { + changed |= ActivityInfo.CONFIG_THEME_RESOURCE; + customTheme = (CustomTheme)delta.customTheme.clone(); + } + return changed; } @@ -685,6 +721,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration && smallestScreenWidthDp != delta.smallestScreenWidthDp) { changed |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; } + if (delta.customTheme != null && + (customTheme == null || !customTheme.equals(delta.customTheme))) { + changed |= ActivityInfo.CONFIG_THEME_RESOURCE; + } return changed; } @@ -701,7 +741,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration * @return Return true if the resource needs to be loaded, else false. */ public static boolean needNewResources(int configChanges, int interestingChanges) { - return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0; + return (configChanges & (interestingChanges | + ActivityInfo.CONFIG_FONT_SCALE | + ActivityInfo.CONFIG_THEME_RESOURCE)) != 0; } /** @@ -774,6 +816,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration dest.writeInt(compatSmallestScreenWidthDp); dest.writeInt(textLayoutDirection); dest.writeInt(seq); + + if (customTheme == null) { + dest.writeInt(0); + } else { + dest.writeInt(1); + dest.writeString(customTheme.getThemeId()); + dest.writeString(customTheme.getThemePackageName()); + } } public void readFromParcel(Parcel source) { @@ -802,6 +852,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration compatSmallestScreenWidthDp = source.readInt(); textLayoutDirection = source.readInt(); seq = source.readInt(); + + if (source.readInt() != 0) { + String themeId = source.readString(); + String themePackage = source.readString(); + customTheme = new CustomTheme(themeId, themePackage); + } } public static final Parcelable.Creator<Configuration> CREATOR @@ -868,6 +924,17 @@ public final class Configuration implements Parcelable, Comparable<Configuration if (n != 0) return n; n = this.smallestScreenWidthDp - that.smallestScreenWidthDp; //if (n != 0) return n; + if (this.customTheme == null) { + if (that.customTheme != null) return 1; + } else if (that.customTheme == null) { + return -1; + } else { + n = this.customTheme.getThemeId().compareTo(that.customTheme.getThemeId()); + if (n != 0) return n; + n = this.customTheme.getThemePackageName().compareTo(that.customTheme.getThemePackageName()); + if (n != 0) return n; + } + return n; } @@ -903,6 +970,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration result = 31 * result + screenWidthDp; result = 31 * result + screenHeightDp; result = 31 * result + smallestScreenWidthDp; + result = 31 * result + (this.customTheme != null ? + this.customTheme.hashCode() : 0); return result; } } diff --git a/core/java/android/content/res/CustomTheme.java b/core/java/android/content/res/CustomTheme.java new file mode 100644 index 0000000..364fb11 --- /dev/null +++ b/core/java/android/content/res/CustomTheme.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2010, T-Mobile USA, Inc. + * + * 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.SystemProperties; +import android.text.TextUtils; + +/** + * @hide + */ +public final class CustomTheme implements Cloneable { + private final String mThemeId; + private final String mThemePackageName; + + private static final CustomTheme sBootTheme = new CustomTheme(); + private static final CustomTheme sSystemTheme = new CustomTheme("", ""); + + private CustomTheme() { + mThemeId = SystemProperties.get("persist.sys.themeId"); + mThemePackageName = SystemProperties.get("persist.sys.themePackageName"); + } + + public CustomTheme(String themeId, String packageName) { + mThemeId = themeId; + mThemePackageName = packageName; + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (object instanceof CustomTheme) { + CustomTheme o = (CustomTheme) object; + if (!mThemeId.equals(o.mThemeId)) { + return false; + } + String currentPackageName = (mThemePackageName == null)? "" : mThemePackageName; + String newPackageName = (o.mThemePackageName == null)? "" : o.mThemePackageName; + String currentThemeId = (mThemeId == null)? "" : mThemeId; + String newThemeId = (o.mThemeId == null)? "" : o.mThemeId; + + /* uhh, why are we trimming here instead of when the object is + * constructed? actually, why are we trimming at all? */ + return (currentPackageName.trim().equalsIgnoreCase(newPackageName.trim())) && + (currentThemeId.trim().equalsIgnoreCase(newThemeId.trim())); + } + return false; + } + + @Override + public final String toString() { + StringBuilder result = new StringBuilder(); + if (!TextUtils.isEmpty(mThemePackageName) && !TextUtils.isEmpty(mThemeId)) { + result.append(mThemePackageName); + result.append('('); + result.append(mThemeId); + result.append(')'); + } else { + result.append("system"); + } + return result.toString(); + } + + @Override + public synchronized int hashCode() { + return mThemeId.hashCode() + mThemePackageName.hashCode(); + } + + public String getThemeId() { + return mThemeId; + } + + public String getThemePackageName() { + return mThemePackageName; + } + + /** + * Represents the theme that the device booted into. This is used to + * simulate a "default" configuration based on the user's last known + * preference until the theme is switched at runtime. + */ + public static CustomTheme getBootTheme() { + return sBootTheme; + } + + /** + * Represents the system framework theme, perceived by the system as there + * being no theme applied. + */ + public static CustomTheme getSystemTheme() { + return sSystemTheme; + } +} diff --git a/core/java/android/content/res/PackageRedirectionMap.aidl b/core/java/android/content/res/PackageRedirectionMap.aidl new file mode 100644 index 0000000..4f47525 --- /dev/null +++ b/core/java/android/content/res/PackageRedirectionMap.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2011, T-Mobile USA, Inc. + * + * 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 PackageRedirectionMap; diff --git a/core/java/android/content/res/PackageRedirectionMap.java b/core/java/android/content/res/PackageRedirectionMap.java new file mode 100644 index 0000000..55c4282 --- /dev/null +++ b/core/java/android/content/res/PackageRedirectionMap.java @@ -0,0 +1,90 @@ +package android.content.res; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Native transport for package asset redirection information coming from the + * AssetRedirectionManagerService. + * + * @hide + */ +public class PackageRedirectionMap implements Parcelable { + private final int mNativePointer; + + public static final Parcelable.Creator<PackageRedirectionMap> CREATOR + = new Parcelable.Creator<PackageRedirectionMap>() { + public PackageRedirectionMap createFromParcel(Parcel in) { + return new PackageRedirectionMap(in); + } + + public PackageRedirectionMap[] newArray(int size) { + return new PackageRedirectionMap[size]; + } + }; + + public PackageRedirectionMap() { + this(nativeConstructor()); + } + + private PackageRedirectionMap(Parcel in) { + this(nativeCreateFromParcel(in)); + } + + private PackageRedirectionMap(int nativePointer) { + if (nativePointer == 0) { + throw new RuntimeException(); + } + mNativePointer = nativePointer; + } + + @Override + protected void finalize() throws Throwable { + nativeDestructor(mNativePointer); + } + + public int getNativePointer() { + return mNativePointer; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + if (!nativeWriteToParcel(mNativePointer, dest)) { + throw new RuntimeException(); + } + } + + public int getPackageId() { + return nativeGetPackageId(mNativePointer); + } + + public void addRedirection(int fromIdent, int toIdent) { + nativeAddRedirection(mNativePointer, fromIdent, toIdent); + } + + // Used for debugging purposes only. + public int[] getRedirectionKeys() { + return nativeGetRedirectionKeys(mNativePointer); + } + + // Used for debugging purposes only. + public int lookupRedirection(int fromIdent) { + return nativeLookupRedirection(mNativePointer, fromIdent); + } + + private static native int nativeConstructor(); + private static native void nativeDestructor(int nativePointer); + + private static native int nativeCreateFromParcel(Parcel p); + private static native boolean nativeWriteToParcel(int nativePointer, Parcel p); + + private native void nativeAddRedirection(int nativePointer, int fromIdent, int toIdent); + private native int nativeGetPackageId(int nativePointer); + private native int[] nativeGetRedirectionKeys(int nativePointer); + private native int nativeLookupRedirection(int nativePointer, int fromIdent); +} diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 990c42c..51c81f5 100755 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1477,7 +1477,15 @@ public class Resources { mTmpConfig.locale = Locale.getDefault(); } configChanges = mConfiguration.updateFrom(mTmpConfig); - configChanges = ActivityInfo.activityInfoConfigToNative(configChanges); + + /* This is ugly, but modifying the activityInfoConfigToNative + * adapter would be messier */ + if ((configChanges & ActivityInfo.CONFIG_THEME_RESOURCE) != 0) { + configChanges = ActivityInfo.activityInfoConfigToNative(configChanges); + configChanges |= ActivityInfo.CONFIG_THEME_RESOURCE; + } else { + configChanges = ActivityInfo.activityInfoConfigToNative(configChanges); + } } if (mConfiguration.locale == null) { mConfiguration.locale = Locale.getDefault(); @@ -1539,6 +1547,18 @@ public class Resources { private void clearDrawableCache( LongSparseArray<WeakReference<ConstantState>> cache, int configChanges) { + /* + * Quick test to find out if the config change that occurred should + * trigger a full cache wipe. + */ + if (Configuration.needNewResources(configChanges, 0)) { + if (DEBUG_CONFIG) { + Log.d(TAG, "Clear drawable cache from config changes: 0x" + + Integer.toHexString(configChanges)); + } + cache.clear(); + return; + } int N = cache.size(); if (DEBUG_CONFIG) { Log.d(TAG, "Cleaning up drawables config changes: 0x" @@ -1890,7 +1910,13 @@ public class Resources { flushLayoutCache(); } } - + + public final void updateStringCache() { + synchronized (mTmpValue) { + mAssets.recreateStringBlocks(); + } + } + /*package*/ Drawable loadDrawable(TypedValue value, int id) throws NotFoundException { |