diff options
-rw-r--r-- | core/java/android/app/ActivityThread.java | 101 | ||||
-rw-r--r-- | core/java/android/content/res/AssetManager.java | 4 | ||||
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 12 | ||||
-rw-r--r-- | include/utils/AssetManager.h | 6 | ||||
-rw-r--r-- | libs/utils/AssetManager.cpp | 48 |
5 files changed, 101 insertions, 70 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 06250fc..e0b2ba2 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -44,6 +44,7 @@ import android.content.pm.InstrumentationInfo; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; +import android.content.pm.ThemeInfo; import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; @@ -235,9 +236,7 @@ public final class ActivityThread { } if (!TextUtils.isEmpty(config.customTheme.getThemePackageName())) { - if (!attachThemeAssets(assets, resDir, config.customTheme)) { - Log.e(TAG, "Failed to attach theme " + config.customTheme + " to resource '" + resDir + "'"); - } + attachThemeAssets(assets, config.customTheme, false); } } @@ -266,23 +265,82 @@ public final class ActivityThread { } } - private boolean attachThemeAssets(AssetManager assets, String resDir, CustomTheme theme) { - PackageInfo pi = getPackageInfo(theme.getThemePackageName(), 0); - if (pi != null) { - String themeResDir = pi.getResDir(); - int cookie = assets.addAssetPath(themeResDir); + /** + * Attach the necessary theme asset paths and meta information to convert an + * AssetManager to being globally "theme-aware". + * + * @param assets + * @param theme + * @param updating If true, this AssetManager has already been accessed and + * special steps must be taken to update the underlying resource + * table. + * @return true if the AssetManager is now theme-aware; false otherwise. + * This can fail, for example, if the theme package has been been + * removed and the theme manager has yet to revert formally back to + * the framework default. + */ + private boolean attachThemeAssets(AssetManager assets, CustomTheme theme, boolean updating) { + android.content.pm.PackageInfo pi = null; + try { + pi = getPackageManager().getPackageInfo(theme.getThemePackageName(), 0); + } catch (RemoteException e) { + } + if (pi != null && pi.applicationInfo != null && pi.themeInfos != null) { + /* + * It's important that this is called before + * updateResourcesWithAssetPath as it depends on the result of + * getThemePackageName to figure out what to do with the resource + * redirection table. + */ + assets.setThemePackageInfo(theme.getThemePackageName(), + findThemeResourceId(pi.themeInfos, theme)); + + String themeResDir = pi.applicationInfo.publicSourceDir; + int cookie; + if (updating) { + cookie = assets.updateResourcesWithAssetPath(themeResDir); + } else { + cookie = assets.addAssetPath(themeResDir); + } if (cookie != 0) { - assets.setThemePackageName(theme.getThemePackageName()); assets.setThemeCookie(cookie); return true; } else { - Log.e(TAG, "Unable to add theme resdir=" + themeResDir); + Log.e(TAG, "Unable to " + (updating ? "update" : "add") + " theme assets at " + + themeResDir); + + /* Roll back the theme package info. */ + assets.setThemePackageInfo(null, 0); } } return false; } /** + * Searches for the high-level theme resource id for the specific + * <theme> tag being applied. + * <p> + * An individual theme package can contain multiple <theme> tags, each + * representing a separate theme choice from the user's perspective, even + * though the most common case is for there to be only 1. + * + * @return The style resource id or 0 if no match was found. + */ + private int findThemeResourceId(ThemeInfo[] themeInfos, CustomTheme theme) { + String needle = theme.getThemeId(); + if (themeInfos != null && !TextUtils.isEmpty(needle)) { + int n = themeInfos.length; + for (int i = 0; i < n; i++) { + ThemeInfo info = themeInfos[i]; + if (needle.equals(info.themeId)) { + return info.styleResourceId; + } + } + } + return 0; + } + + /** * Creates the top level resources for the given package. * * @deprecated {@link #getTopLevelResources(String, PackageInfo, boolean)} @@ -4051,16 +4109,12 @@ public final class ActivityThread { String oldThemePackage = am.getThemePackageName(); int themeCookie = am.getThemeCookie(); if (!TextUtils.isEmpty(oldThemePackage) && themeCookie != 0) { - am.setThemePackageName(null); + am.setThemePackageInfo(null, 0); am.removeAssetPath(oldThemePackage, themeCookie); am.setThemeCookie(0); } - String newThemePackage = config.customTheme.getThemePackageName(); - String resDir = getPackageResDir(newThemePackage); - if (resDir != null) { - am.setThemePackageName(newThemePackage); - int newCookie = am.updateResourcesWithAssetPath(resDir); - am.setThemeCookie(newCookie); + if (!TextUtils.isEmpty(config.customTheme.getThemePackageName())) { + attachThemeAssets(am, config.customTheme, true); } } } @@ -4079,19 +4133,6 @@ public final class ActivityThread { return changes; } - private String getPackageResDir(String packageName) { - android.content.pm.PackageInfo pi; - try { - pi = getPackageManager().getPackageInfo(packageName, 0); - if (pi == null || pi.applicationInfo == null) - return null; - return pi.applicationInfo.publicSourceDir; - } catch (RemoteException e) { - Log.e("ActivityThread", "Exception in getPackageResDir", e); - } - return null; - } - final void handleConfigurationChanged(Configuration config) { ArrayList<ComponentCallbacks> callbacks = null; diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 6aca089..532572d 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -697,10 +697,10 @@ public final class AssetManager { public native final String getThemePackageName(); /** - * Sets package name for current theme (null is allowed). + * Sets package name and highest level style id for current theme (null, 0 is allowed). * {@hide} */ - public native final void setThemePackageName(String packageName); + public native final void setThemePackageInfo(String packageName, int styleId); /** * Get asset cookie for current theme (may return 0). diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index da91bd7..0cabc9a 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -1767,8 +1767,8 @@ static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, return AssetManager::getGlobalCount(); } -static void android_content_AssetManager_setThemePackageName(JNIEnv* env, jobject clazz, - jstring packageName) +static void android_content_AssetManager_setThemePackageInfo(JNIEnv* env, jobject clazz, + jstring packageName, jint styleId) { AssetManager* am = assetManagerForJavaObject(env, clazz); if (am == NULL) { @@ -1777,10 +1777,10 @@ static void android_content_AssetManager_setThemePackageName(JNIEnv* env, jobjec if (packageName != NULL) { const char* packageName8 = env->GetStringUTFChars(packageName, NULL); - am->setThemePackageName(packageName8); + am->setThemePackageInfo(packageName8, styleId); env->ReleaseStringUTFChars(packageName, packageName8); } else { - am->setThemePackageName(NULL); + am->setThemePackageInfo(NULL, styleId); } } @@ -1966,8 +1966,8 @@ static JNINativeMethod gAssetManagerMethods[] = { (void*) android_content_AssetManager_splitThemePackage }, // Dynamic theme package support. - { "setThemePackageName", "(Ljava/lang/String;)V", - (void*) android_content_AssetManager_setThemePackageName }, + { "setThemePackageInfo", "(Ljava/lang/String;I)V", + (void*) android_content_AssetManager_setThemePackageInfo }, { "getThemePackageName", "()Ljava/lang/String;", (void*) android_content_AssetManager_getThemePackageName }, { "removeAssetPath", "(Ljava/lang/String;I)Z", diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h index fe92e87..89020de 100644 --- a/include/utils/AssetManager.h +++ b/include/utils/AssetManager.h @@ -198,7 +198,7 @@ public: */ void getLocales(Vector<String8>* locales) const; - void setThemePackageName(const char* packageName); + void setThemePackageInfo(const char* packageName, uint32_t styleId); const char* getThemePackageName(); /* @@ -222,7 +222,8 @@ private: SharedBuffer* generateRedirections(SharedBuffer* entriesByTypeBuf, ResTable* rt, const char* themePackageName, const char16_t* resPackageName); bool generateAndWriteRedirections(ResTable* rt, const char* themePackageName, - const char16_t* resPackageName, const char* redirPath, bool isFramework) const; + uint32_t themeStyleId, const char16_t* resPackageName, const char* redirPath, + bool isFramework) const; void loadRedirectionMappings(ResTable* rt) const; void updateResTableFromAssetPath(ResTable* rt, const asset_path& ap, void* cookie) const; Asset* openInPathLocked(const char* fileName, AccessMode mode, @@ -344,6 +345,7 @@ private: // If non-null, represents the theme package from which to construct the // resource redirection map used by ResTable. char* mThemePackageName; + uint32_t mThemeStyleId; mutable ResTable* mResources; ResTable_config* mConfig; diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 94f0fcd..eb8e62e 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -515,33 +515,15 @@ static bool writeRedirections(const char* redirPath, SharedBuffer* entriesByType // for testing. This code should be generalized and follow a much better OO // structure. static SharedBuffer* generateFrameworkRedirections(SharedBuffer* entriesByTypeBuf, ResTable* rt, - const char* themePackageName, const char* redirPath) + const char* themePackageName, uint32_t styleId, const char* redirPath) { - REDIRECT_NOISY(LOGW("generateFrameworkRedirections: themePackageName=%s\n", themePackageName)); - - // HACK HACK HACK - if (strcmp(themePackageName, "com.tmobile.theme.Androidian") != 0) { - LOGW("EEP, UNEXPECTED PACKAGE!"); - return entriesByTypeBuf; - } + REDIRECT_NOISY(LOGW("generateFrameworkRedirections: themePackageName=%s, styleId=0x%08x\n", themePackageName, styleId)); rt->lock(); // Load up a bag for the user-supplied theme. - String16 type("style"); - String16 name("Androidian"); - String16 package(themePackageName); - uint32_t ident = rt->identifierForName(name.string(), name.size(), type.string(), type.size(), - package.string(), package.size()); - if (ident == 0) { - LOGW("unable to locate theme identifier %s:%s/%s\n", String8(package).string(), - String8(type).string(), String8(name).string()); - rt->unlock(); - return entriesByTypeBuf; - } - const ResTable::bag_entry* themeEnt = NULL; - ssize_t N = rt->getBagLocked(ident, &themeEnt); + ssize_t N = rt->getBagLocked(styleId, &themeEnt); const ResTable::bag_entry* endThemeEnt = themeEnt + N; // ...and a bag for the framework default. @@ -550,7 +532,7 @@ static SharedBuffer* generateFrameworkRedirections(SharedBuffer* entriesByTypeBu const ResTable::bag_entry* endFrameworkEnt = frameworkEnt + N; // The first entry should be for the theme itself. - entriesByTypeBuf = addToEntriesByTypeBuffer(entriesByTypeBuf, 0x01030005, ident); + entriesByTypeBuf = addToEntriesByTypeBuffer(entriesByTypeBuf, 0x01030005, styleId); // Now compare them and infer resource redirections for attributes that // remap to different styles. This works by essentially lining up all the @@ -560,7 +542,7 @@ static SharedBuffer* generateFrameworkRedirections(SharedBuffer* entriesByTypeBu // the one in the theme. This lets us do things like automatically find // redirections for @android:style/Widget.Button by looking at how the // theme overrides the android:attr/buttonStyle attribute. - REDIRECT_NOISY(LOGW("delta between 0x01030005 and 0x%08x:\n", ident)); + REDIRECT_NOISY(LOGW("delta between 0x01030005 and 0x%08x:\n", styleId)); for (; frameworkEnt < endFrameworkEnt; frameworkEnt++) { if (frameworkEnt->map.value.dataType != Res_value::TYPE_REFERENCE) { continue; @@ -723,8 +705,9 @@ SharedBuffer* AssetManager::generateRedirections(SharedBuffer* entriesByTypeBuf, } bool AssetManager::generateAndWriteRedirections(ResTable* rt, - const char* themePackageName, const char16_t* resPackageName, - const char* redirPath, bool isFramework) const + const char* themePackageName, uint32_t themeStyleId, + const char16_t* resPackageName, const char* redirPath, + bool isFramework) const { // FIXME: the const is a lie!!! AssetManager* am = (AssetManager*)this; @@ -732,7 +715,8 @@ bool AssetManager::generateAndWriteRedirections(ResTable* rt, SharedBuffer* buf = NULL; if (isFramework) { // Special framework theme heuristic... - buf = generateFrameworkRedirections(buf, rt, themePackageName, redirPath); + buf = generateFrameworkRedirections(buf, rt, themePackageName, + themeStyleId, redirPath); } // Generate redirections from the package XML. buf = am->generateRedirections(buf, rt, themePackageName, resPackageName); @@ -778,7 +762,8 @@ void AssetManager::loadRedirectionMappings(ResTable* rt) const if (lstat(redirPath.string(), &statbuf) != 0) { generateAndWriteRedirections(rt, mThemePackageName, - resPackageName, redirPath.string(), false); + mThemeStyleId, resPackageName, redirPath.string(), + false); } rt->addRedirections(packageId, redirPath.string()); @@ -795,7 +780,7 @@ void AssetManager::loadRedirectionMappings(ResTable* rt) const if (lstat(frameworkRedirPath.string(), &statbuf) != 0) { generateAndWriteRedirections(rt, mThemePackageName, - String16("android").string(), + mThemeStyleId, String16("android").string(), frameworkRedirPath.string(), true); } @@ -2205,17 +2190,20 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const } /* - * Set the currently applied theme package name. + * Set the currently applied theme package name and the high-level theme style + * identifier (the one to replace @android:style/Theme). May be set to NULL, 0 + * to indicate that this AssetManager does not have an added theme package. * * This information is used when constructing the ResTable's resource * redirection map. */ -void AssetManager::setThemePackageName(const char* packageName) +void AssetManager::setThemePackageInfo(const char* packageName, uint32_t styleId) { if (mThemePackageName != NULL) { delete[] mThemePackageName; } mThemePackageName = strdupNew(packageName); + mThemeStyleId = styleId; } const char* AssetManager::getThemePackageName() |