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

Commit 756220bd authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Add API to create new contexts with custom configurations.

This allows you to, say, make a Context whose configuration
is set to a different density than the actual density of the device.

The main API is Context.createConfigurationContext().  There is
also a new API on ContextThemeWrapper that allows you to apply
an override context before its resources are retrieved, which
addresses some feature requests from developers to be able to
customize the context their app is running in.

Change-Id: I88364986660088521e24b567e2fda22fb7042819
parent 863b19bc
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -5262,6 +5262,7 @@ package android.content {
    method public abstract int checkUriPermission(android.net.Uri, int, int, int);
    method public abstract int checkUriPermission(android.net.Uri, int, int, int);
    method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
    method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
    method public abstract deprecated void clearWallpaper() throws java.io.IOException;
    method public abstract deprecated void clearWallpaper() throws java.io.IOException;
    method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
    method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method public abstract java.lang.String[] databaseList();
    method public abstract java.lang.String[] databaseList();
    method public abstract boolean deleteDatabase(java.lang.String);
    method public abstract boolean deleteDatabase(java.lang.String);
@@ -5406,6 +5407,7 @@ package android.content {
    method public int checkUriPermission(android.net.Uri, int, int, int);
    method public int checkUriPermission(android.net.Uri, int, int, int);
    method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
    method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
    method public void clearWallpaper() throws java.io.IOException;
    method public void clearWallpaper() throws java.io.IOException;
    method public android.content.Context createConfigurationContext(android.content.res.Configuration);
    method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method public java.lang.String[] databaseList();
    method public java.lang.String[] databaseList();
    method public boolean deleteDatabase(java.lang.String);
    method public boolean deleteDatabase(java.lang.String);
@@ -21147,6 +21149,7 @@ package android.test.mock {
    method public int checkUriPermission(android.net.Uri, int, int, int);
    method public int checkUriPermission(android.net.Uri, int, int, int);
    method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
    method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
    method public void clearWallpaper();
    method public void clearWallpaper();
    method public android.content.Context createConfigurationContext(android.content.res.Configuration);
    method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method public java.lang.String[] databaseList();
    method public java.lang.String[] databaseList();
    method public boolean deleteDatabase(java.lang.String);
    method public boolean deleteDatabase(java.lang.String);
@@ -23351,6 +23354,7 @@ package android.view {
  public class ContextThemeWrapper extends android.content.ContextWrapper {
  public class ContextThemeWrapper extends android.content.ContextWrapper {
    ctor public ContextThemeWrapper();
    ctor public ContextThemeWrapper();
    ctor public ContextThemeWrapper(android.content.Context, int);
    ctor public ContextThemeWrapper(android.content.Context, int);
    method public void applyOverrideConfiguration(android.content.res.Configuration);
    method protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean);
    method protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean);
  }
  }
+64 −17
Original line number Original line Diff line number Diff line
@@ -1471,13 +1471,25 @@ public final class ActivityThread {


    private static class ResourcesKey {
    private static class ResourcesKey {
        final private String mResDir;
        final private String mResDir;
        final private Configuration mOverrideConfiguration;
        final private float mScale;
        final private float mScale;
        final private int mHash;
        final private int mHash;


        ResourcesKey(String resDir, float scale) {
        ResourcesKey(String resDir, Configuration overrideConfiguration, float scale) {
            mResDir = resDir;
            mResDir = resDir;
            if (overrideConfiguration != null) {
                if (Configuration.EMPTY.equals(overrideConfiguration)) {
                    overrideConfiguration = null;
                }
            }
            mOverrideConfiguration = overrideConfiguration;
            mScale = scale;
            mScale = scale;
            mHash = mResDir.hashCode() << 2 + (int) (mScale * 2);
            int hash = 17;
            hash = 31 * hash + mResDir.hashCode();
            hash = 31 * hash + (mOverrideConfiguration != null
                    ? mOverrideConfiguration.hashCode() : 0);
            hash = 31 * hash + Float.floatToIntBits(mScale);
            mHash = hash;
        }
        }


        @Override
        @Override
@@ -1491,7 +1503,21 @@ public final class ActivityThread {
                return false;
                return false;
            }
            }
            ResourcesKey peer = (ResourcesKey) obj;
            ResourcesKey peer = (ResourcesKey) obj;
            return mResDir.equals(peer.mResDir) && mScale == peer.mScale;
            if (!mResDir.equals(peer.mResDir)) {
                return false;
            }
            if (mOverrideConfiguration != peer.mOverrideConfiguration) {
                if (mOverrideConfiguration == null || peer.mOverrideConfiguration == null) {
                    return false;
                }
                if (!mOverrideConfiguration.equals(peer.mOverrideConfiguration)) {
                    return false;
                }
            }
            if (mScale != peer.mScale) {
                return false;
            }
            return true;
        }
        }
    }
    }


@@ -1562,8 +1588,10 @@ public final class ActivityThread {
     * @param compInfo the compability info. It will use the default compatibility info when it's
     * @param compInfo the compability info. It will use the default compatibility info when it's
     * null.
     * null.
     */
     */
    Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo) {
    Resources getTopLevelResources(String resDir, Configuration overrideConfiguration,
        ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale);
            CompatibilityInfo compInfo) {
        ResourcesKey key = new ResourcesKey(resDir, overrideConfiguration,
                compInfo.applicationScale);
        Resources r;
        Resources r;
        synchronized (mPackages) {
        synchronized (mPackages) {
            // Resources is app scale dependent.
            // Resources is app scale dependent.
@@ -1595,7 +1623,14 @@ public final class ActivityThread {


        //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
        //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
        DisplayMetrics metrics = getDisplayMetricsLocked(null, false);
        DisplayMetrics metrics = getDisplayMetricsLocked(null, false);
        r = new Resources(assets, metrics, getConfiguration(), compInfo);
        Configuration config;
        if (key.mOverrideConfiguration != null) {
            config = new Configuration(getConfiguration());
            config.updateFrom(key.mOverrideConfiguration);
        } else {
            config = getConfiguration();
        }
        r = new Resources(assets, metrics, config, compInfo);
        if (false) {
        if (false) {
            Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
            Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
                    + r.getConfiguration() + " appScale="
                    + r.getConfiguration() + " appScale="
@@ -1621,8 +1656,10 @@ public final class ActivityThread {
    /**
    /**
     * Creates the top level resources for the given package.
     * Creates the top level resources for the given package.
     */
     */
    Resources getTopLevelResources(String resDir, LoadedApk pkgInfo) {
    Resources getTopLevelResources(String resDir, Configuration overrideConfiguration,
        return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo.get());
            LoadedApk pkgInfo) {
        return getTopLevelResources(resDir, overrideConfiguration,
                pkgInfo.mCompatibilityInfo.get());
    }
    }


    final Handler getHandler() {
    final Handler getHandler() {
@@ -3676,17 +3713,27 @@ public final class ActivityThread {
        ApplicationPackageManager.configurationChanged();
        ApplicationPackageManager.configurationChanged();
        //Slog.i(TAG, "Configuration changed in " + currentPackageName());
        //Slog.i(TAG, "Configuration changed in " + currentPackageName());


        Iterator<WeakReference<Resources>> it =
        Configuration tmpConfig = null;
            mActiveResources.values().iterator();

        //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
        Iterator<Map.Entry<ResourcesKey, WeakReference<Resources>>> it =
        //    mActiveResources.entrySet().iterator();
                mActiveResources.entrySet().iterator();
        while (it.hasNext()) {
        while (it.hasNext()) {
            WeakReference<Resources> v = it.next();
            Map.Entry<ResourcesKey, WeakReference<Resources>> entry = it.next();
            Resources r = v.get();
            Resources r = entry.getValue().get();
            if (r != null) {
            if (r != null) {
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
                        + r + " config to: " + config);
                        + r + " config to: " + config);
                Configuration override = entry.getKey().mOverrideConfiguration;
                if (override != null) {
                    if (tmpConfig == null) {
                        tmpConfig = new Configuration();
                    }
                    tmpConfig.setTo(config);
                    tmpConfig.updateFrom(override);
                    r.updateConfiguration(tmpConfig, dm, compat);
                } else {
                    r.updateConfiguration(config, dm, compat);
                    r.updateConfiguration(config, dm, compat);
                }
                //Slog.i(TAG, "Updated app resources " + v.getKey()
                //Slog.i(TAG, "Updated app resources " + v.getKey()
                //        + " " + r + ": " + r.getConfiguration());
                //        + " " + r + ": " + r.getConfiguration());
            } else {
            } else {
+1 −1
Original line number Original line Diff line number Diff line
@@ -713,7 +713,7 @@ final class ApplicationPackageManager extends PackageManager {
        }
        }
        Resources r = mContext.mMainThread.getTopLevelResources(
        Resources r = mContext.mMainThread.getTopLevelResources(
            app.uid == Process.myUid() ? app.sourceDir
            app.uid == Process.myUid() ? app.sourceDir
            : app.publicSourceDir, mContext.mPackageInfo);
            : app.publicSourceDir, null, mContext.mPackageInfo);
        if (r != null) {
        if (r != null) {
            return r;
            return r;
        }
        }
+14 −8
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources;
import android.database.DatabaseErrorHandler;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase;
@@ -525,7 +526,7 @@ class ContextImpl extends Context {


    @Override
    @Override
    public AssetManager getAssets() {
    public AssetManager getAssets() {
        return mResources.getAssets();
        return getResources().getAssets();
    }
    }


    @Override
    @Override
@@ -1590,6 +1591,16 @@ class ContextImpl extends Context {
            "Application package " + packageName + " not found");
            "Application package " + packageName + " not found");
    }
    }


    @Override
    public Context createConfigurationContext(Configuration overrideConfiguration) {
        ContextImpl c = new ContextImpl();
        c.init(mPackageInfo, null, mMainThread);
        c.mResources = mMainThread.getTopLevelResources(
                mPackageInfo.getResDir(), overrideConfiguration,
                mResources.getCompatibilityInfo());
        return c;
    }

    @Override
    @Override
    public boolean isRestricted() {
    public boolean isRestricted() {
        return mRestricted;
        return mRestricted;
@@ -1659,12 +1670,11 @@ class ContextImpl extends Context {
                        " compatiblity info:" + container.getDisplayMetrics());
                        " compatiblity info:" + container.getDisplayMetrics());
            }
            }
            mResources = mainThread.getTopLevelResources(
            mResources = mainThread.getTopLevelResources(
                    mPackageInfo.getResDir(), container.getCompatibilityInfo());
                    mPackageInfo.getResDir(), null, container.getCompatibilityInfo());
        }
        }
        mMainThread = mainThread;
        mMainThread = mainThread;
        mContentResolver = new ApplicationContentResolver(this, mainThread);
        mContentResolver = new ApplicationContentResolver(this, mainThread);

        mActivityToken = activityToken;
        setActivityToken(activityToken);
    }
    }


    final void init(Resources resources, ActivityThread mainThread) {
    final void init(Resources resources, ActivityThread mainThread) {
@@ -1691,10 +1701,6 @@ class ContextImpl extends Context {
        return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
        return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
    }
    }


    final void setActivityToken(IBinder token) {
        mActivityToken = token;
    }

    final void setOuterContext(Context context) {
    final void setOuterContext(Context context) {
        mOuterContext = context;
        mOuterContext = context;
    }
    }
+1 −1
Original line number Original line Diff line number Diff line
@@ -471,7 +471,7 @@ public final class LoadedApk {


    public Resources getResources(ActivityThread mainThread) {
    public Resources getResources(ActivityThread mainThread) {
        if (mResources == null) {
        if (mResources == null) {
            mResources = mainThread.getTopLevelResources(mResDir, this);
            mResources = mainThread.getTopLevelResources(mResDir, null, this);
        }
        }
        return mResources;
        return mResources;
    }
    }
Loading