Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 38544aab authored by Josh Guilfoyle's avatar Josh Guilfoyle
Browse files

Pass the high-level theme resource id into the redirection table layer.

This is necessary to provide the high-level style redirection heuristics
(previously this was hacked to assume the Androidian's theme style id).
parent f1068694
Loading
Loading
Loading
Loading
+71 −30
Original line number Diff line number Diff line
@@ -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,22 +265,81 @@ 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 &lt;theme&gt; 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.
     *
@@ -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;
+2 −2
Original line number Diff line number Diff line
@@ -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).
+6 −6
Original line number Diff line number Diff line
@@ -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",
+4 −2
Original line number Diff line number Diff line
@@ -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;
+18 −30
Original line number Diff line number Diff line
@@ -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()