Merge "Allow multiple Resources associated with an Activity" into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d17f96ae00
@@ -1993,7 +1993,7 @@ class ContextImpl extends Context {
|
|||||||
ContextImpl context = new ContextImpl(null, mainThread,
|
ContextImpl context = new ContextImpl(null, mainThread,
|
||||||
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
|
packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
|
||||||
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
|
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
|
||||||
context.mResourcesManager.getDisplayMetricsLocked());
|
context.mResourcesManager.getDisplayMetrics());
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2065,16 +2065,34 @@ class ContextImpl extends Context {
|
|||||||
|| overrideConfiguration != null
|
|| overrideConfiguration != null
|
||||||
|| (compatInfo != null && compatInfo.applicationScale
|
|| (compatInfo != null && compatInfo.applicationScale
|
||||||
!= resources.getCompatibilityInfo().applicationScale)) {
|
!= resources.getCompatibilityInfo().applicationScale)) {
|
||||||
resources = mResourcesManager.getResources(
|
|
||||||
activityToken,
|
if (container != null) {
|
||||||
packageInfo.getResDir(),
|
// This is a nested Context, so it can't be a base Activity context.
|
||||||
packageInfo.getSplitResDirs(),
|
// Just create a regular Resources object associated with the Activity.
|
||||||
packageInfo.getOverlayDirs(),
|
resources = mResourcesManager.getResources(
|
||||||
packageInfo.getApplicationInfo().sharedLibraryFiles,
|
activityToken,
|
||||||
displayId,
|
packageInfo.getResDir(),
|
||||||
overrideConfiguration,
|
packageInfo.getSplitResDirs(),
|
||||||
compatInfo,
|
packageInfo.getOverlayDirs(),
|
||||||
packageInfo.getClassLoader());
|
packageInfo.getApplicationInfo().sharedLibraryFiles,
|
||||||
|
displayId,
|
||||||
|
overrideConfiguration,
|
||||||
|
compatInfo,
|
||||||
|
packageInfo.getClassLoader());
|
||||||
|
} else {
|
||||||
|
// This is not a nested Context, so it must be the root Activity context.
|
||||||
|
// All other nested Contexts will inherit the configuration set here.
|
||||||
|
resources = mResourcesManager.createBaseActivityResources(
|
||||||
|
activityToken,
|
||||||
|
packageInfo.getResDir(),
|
||||||
|
packageInfo.getSplitResDirs(),
|
||||||
|
packageInfo.getOverlayDirs(),
|
||||||
|
packageInfo.getApplicationInfo().sharedLibraryFiles,
|
||||||
|
displayId,
|
||||||
|
overrideConfiguration,
|
||||||
|
compatInfo,
|
||||||
|
packageInfo.getClassLoader());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mResources = resources;
|
mResources = resources;
|
||||||
|
|||||||
@@ -94,9 +94,18 @@ public class ResourcesManager {
|
|||||||
private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
|
private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each Activity may have only one Resources object.
|
* Resources and base configuration override associated with an Activity.
|
||||||
*/
|
*/
|
||||||
private final WeakHashMap<IBinder, WeakReference<Resources>> mActivityResourceReferences =
|
private static class ActivityResources {
|
||||||
|
public final Configuration overrideConfig = new Configuration();
|
||||||
|
public final ArrayList<WeakReference<Resources>> activityResources = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each Activity may has a base override configuration that is applied to each Resources object,
|
||||||
|
* which in turn may have their own override configuration specified.
|
||||||
|
*/
|
||||||
|
private final WeakHashMap<IBinder, ActivityResources> mActivityResourceReferences =
|
||||||
new WeakHashMap<>();
|
new WeakHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,18 +124,20 @@ public class ResourcesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Configuration getConfiguration() {
|
public Configuration getConfiguration() {
|
||||||
return mResConfiguration;
|
synchronized (this) {
|
||||||
|
return mResConfiguration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayMetrics getDisplayMetricsLocked() {
|
DisplayMetrics getDisplayMetrics() {
|
||||||
return getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
|
return getDisplayMetrics(Display.DEFAULT_DISPLAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Protected so that tests can override and returns something a fixed value.
|
* Protected so that tests can override and returns something a fixed value.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected DisplayMetrics getDisplayMetricsLocked(int displayId) {
|
protected DisplayMetrics getDisplayMetrics(int displayId) {
|
||||||
DisplayMetrics dm = new DisplayMetrics();
|
DisplayMetrics dm = new DisplayMetrics();
|
||||||
final Display display =
|
final Display display =
|
||||||
getAdjustedDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
|
getAdjustedDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
|
||||||
@@ -272,10 +283,9 @@ public class ResourcesManager {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
|
private ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
|
||||||
AssetManager assets = createAssetManager(key);
|
AssetManager assets = createAssetManager(key);
|
||||||
DisplayMetrics dm = getDisplayMetricsLocked(key.mDisplayId);
|
DisplayMetrics dm = getDisplayMetrics(key.mDisplayId);
|
||||||
Configuration config = generateConfig(key, dm);
|
Configuration config = generateConfig(key, dm);
|
||||||
ResourcesImpl impl = new ResourcesImpl(assets, dm, config, key.mCompatInfo);
|
ResourcesImpl impl = new ResourcesImpl(assets, dm, config, key.mCompatInfo);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@@ -290,7 +300,7 @@ public class ResourcesManager {
|
|||||||
* @param key The key to match.
|
* @param key The key to match.
|
||||||
* @return a ResourcesImpl if the key matches a cache entry, null otherwise.
|
* @return a ResourcesImpl if the key matches a cache entry, null otherwise.
|
||||||
*/
|
*/
|
||||||
private ResourcesImpl findResourcesImplForKey(@NonNull ResourcesKey key) {
|
private ResourcesImpl findResourcesImplForKeyLocked(@NonNull ResourcesKey key) {
|
||||||
WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.get(key);
|
WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.get(key);
|
||||||
ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
|
ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
|
||||||
if (impl != null && impl.getAssets().isUpToDate()) {
|
if (impl != null && impl.getAssets().isUpToDate()) {
|
||||||
@@ -303,7 +313,7 @@ public class ResourcesManager {
|
|||||||
* Find the ResourcesKey that this ResourcesImpl object is associated with.
|
* Find the ResourcesKey that this ResourcesImpl object is associated with.
|
||||||
* @return the ResourcesKey or null if none was found.
|
* @return the ResourcesKey or null if none was found.
|
||||||
*/
|
*/
|
||||||
private ResourcesKey findKeyForResourceImpl(@NonNull ResourcesImpl resourceImpl) {
|
private ResourcesKey findKeyForResourceImplLocked(@NonNull ResourcesImpl resourceImpl) {
|
||||||
final int refCount = mResourceImpls.size();
|
final int refCount = mResourceImpls.size();
|
||||||
for (int i = 0; i < refCount; i++) {
|
for (int i = 0; i < refCount; i++) {
|
||||||
WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
|
WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
|
||||||
@@ -315,36 +325,46 @@ public class ResourcesManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ActivityResources getOrCreateActivityResourcesStructLocked(
|
||||||
|
@NonNull IBinder activityToken) {
|
||||||
|
ActivityResources activityResources = mActivityResourceReferences.get(activityToken);
|
||||||
|
if (activityResources == null) {
|
||||||
|
activityResources = new ActivityResources();
|
||||||
|
mActivityResourceReferences.put(activityToken, activityResources);
|
||||||
|
}
|
||||||
|
return activityResources;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an existing Resources object tied to this Activity, or creates one if it doesn't exist
|
* Gets an existing Resources object tied to this Activity, or creates one if it doesn't exist
|
||||||
* or the class loader is different.
|
* or the class loader is different.
|
||||||
*/
|
*/
|
||||||
private Resources getOrCreateResourcesForActivityLocked(@NonNull IBinder activityToken,
|
private Resources getOrCreateResourcesForActivityLocked(@NonNull IBinder activityToken,
|
||||||
@NonNull ClassLoader classLoader, @NonNull ResourcesImpl impl) {
|
@NonNull ClassLoader classLoader, @NonNull ResourcesImpl impl) {
|
||||||
// This is a request tied to an Activity, meaning we will need to update all
|
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
|
||||||
// Activity related Resources to match this configuration.
|
activityToken);
|
||||||
WeakReference<Resources> weakResourceRef = mActivityResourceReferences.get(activityToken);
|
|
||||||
Resources resources = weakResourceRef != null ? weakResourceRef.get() : null;
|
final int refCount = activityResources.activityResources.size();
|
||||||
if (resources == null || !Objects.equals(resources.getClassLoader(), classLoader)) {
|
for (int i = 0; i < refCount; i++) {
|
||||||
resources = new Resources(classLoader);
|
WeakReference<Resources> weakResourceRef = activityResources.activityResources.get(i);
|
||||||
mActivityResourceReferences.put(activityToken, new WeakReference<>(resources));
|
Resources resources = weakResourceRef.get();
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "- creating new ref=" + resources);
|
if (resources != null
|
||||||
}
|
&& Objects.equals(resources.getClassLoader(), classLoader)
|
||||||
} else {
|
&& resources.getImpl() == impl) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "- using existing ref=" + resources);
|
Slog.d(TAG, "- using existing ref=" + resources);
|
||||||
|
}
|
||||||
|
return resources;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resources.getImpl() != impl) {
|
Resources resources = new Resources(classLoader);
|
||||||
if (DEBUG) {
|
resources.setImpl(impl);
|
||||||
Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
|
activityResources.activityResources.add(new WeakReference<>(resources));
|
||||||
}
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "- creating new ref=" + resources);
|
||||||
// Setting an impl is expensive because we update all ThemeImpl references.
|
Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
|
||||||
// too.
|
|
||||||
resources.setImpl(impl);
|
|
||||||
}
|
}
|
||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
@@ -359,7 +379,7 @@ public class ResourcesManager {
|
|||||||
final int refCount = mResourceReferences.size();
|
final int refCount = mResourceReferences.size();
|
||||||
for (int i = 0; i < refCount; i++) {
|
for (int i = 0; i < refCount; i++) {
|
||||||
WeakReference<Resources> weakResourceRef = mResourceReferences.get(i);
|
WeakReference<Resources> weakResourceRef = mResourceReferences.get(i);
|
||||||
Resources resources = weakResourceRef != null ? weakResourceRef.get() : null;
|
Resources resources = weakResourceRef.get();
|
||||||
if (resources != null &&
|
if (resources != null &&
|
||||||
Objects.equals(resources.getClassLoader(), classLoader) &&
|
Objects.equals(resources.getClassLoader(), classLoader) &&
|
||||||
resources.getImpl() == impl) {
|
resources.getImpl() == impl) {
|
||||||
@@ -381,6 +401,177 @@ public class ResourcesManager {
|
|||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates base resources for an Activity. Calls to
|
||||||
|
* {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
|
||||||
|
* CompatibilityInfo, ClassLoader)} with the same activityToken will have their override
|
||||||
|
* configurations merged with the one specified here.
|
||||||
|
*
|
||||||
|
* @param activityToken Represents an Activity.
|
||||||
|
* @param resDir The base resource path. Can be null (only framework resources will be loaded).
|
||||||
|
* @param splitResDirs An array of split resource paths. Can be null.
|
||||||
|
* @param overlayDirs An array of overlay paths. Can be null.
|
||||||
|
* @param libDirs An array of resource library paths. Can be null.
|
||||||
|
* @param displayId The ID of the display for which to create the resources.
|
||||||
|
* @param overrideConfig The configuration to apply on top of the base configuration. Can be
|
||||||
|
* null. This provides the base override for this Activity.
|
||||||
|
* @param compatInfo The compatibility settings to use. Cannot be null. A default to use is
|
||||||
|
* {@link CompatibilityInfo#DEFAULT_COMPATIBILITY_INFO}.
|
||||||
|
* @param classLoader The class loader to use when inflating Resources. If null, the
|
||||||
|
* {@link ClassLoader#getSystemClassLoader()} is used.
|
||||||
|
* @return a Resources object from which to access resources.
|
||||||
|
*/
|
||||||
|
public Resources createBaseActivityResources(@NonNull IBinder activityToken,
|
||||||
|
@Nullable String resDir,
|
||||||
|
@Nullable String[] splitResDirs,
|
||||||
|
@Nullable String[] overlayDirs,
|
||||||
|
@Nullable String[] libDirs,
|
||||||
|
int displayId,
|
||||||
|
@Nullable Configuration overrideConfig,
|
||||||
|
@NonNull CompatibilityInfo compatInfo,
|
||||||
|
@Nullable ClassLoader classLoader) {
|
||||||
|
final ResourcesKey key = new ResourcesKey(
|
||||||
|
resDir,
|
||||||
|
splitResDirs,
|
||||||
|
overlayDirs,
|
||||||
|
libDirs,
|
||||||
|
displayId,
|
||||||
|
overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
|
||||||
|
compatInfo);
|
||||||
|
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
|
||||||
|
activityToken);
|
||||||
|
|
||||||
|
if (overrideConfig != null) {
|
||||||
|
activityResources.overrideConfig.setTo(overrideConfig);
|
||||||
|
} else {
|
||||||
|
activityResources.overrideConfig.setToDefaults();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update any existing Activity Resources references.
|
||||||
|
updateResourcesForActivity(activityToken, overrideConfig);
|
||||||
|
|
||||||
|
// Now request an actual Resources object.
|
||||||
|
return getOrCreateResources(activityToken, key, classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an existing Resources object set with a ResourcesImpl object matching the given key,
|
||||||
|
* or creates one if it doesn't exist.
|
||||||
|
*
|
||||||
|
* @param activityToken The Activity this Resources object should be associated with.
|
||||||
|
* @param key The key describing the parameters of the ResourcesImpl object.
|
||||||
|
* @param classLoader The classloader to use for the Resources object.
|
||||||
|
* If null, {@link ClassLoader#getSystemClassLoader()} is used.
|
||||||
|
* @return A Resources object that gets updated when
|
||||||
|
* {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)}
|
||||||
|
* is called.
|
||||||
|
*/
|
||||||
|
private Resources getOrCreateResources(@Nullable IBinder activityToken,
|
||||||
|
@NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
|
||||||
|
final boolean findSystemLocales;
|
||||||
|
final boolean hasNonSystemLocales;
|
||||||
|
synchronized (this) {
|
||||||
|
findSystemLocales = (mSystemLocales == null || mSystemLocales.length == 0);
|
||||||
|
hasNonSystemLocales = mHasNonSystemLocales;
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Throwable here = new Throwable();
|
||||||
|
here.fillInStackTrace();
|
||||||
|
Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activityToken != null) {
|
||||||
|
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
|
||||||
|
activityToken);
|
||||||
|
|
||||||
|
// Clean up any dead references so they don't pile up.
|
||||||
|
ArrayUtils.unstableRemoveIf(activityResources.activityResources,
|
||||||
|
sEmptyReferencePredicate);
|
||||||
|
|
||||||
|
// Rebase the key's override config on top of the Activity's base override.
|
||||||
|
if (key.hasOverrideConfiguration()
|
||||||
|
&& !activityResources.overrideConfig.equals(Configuration.EMPTY)) {
|
||||||
|
final Configuration temp = new Configuration(activityResources.overrideConfig);
|
||||||
|
temp.updateFrom(key.mOverrideConfiguration);
|
||||||
|
key.mOverrideConfiguration.setTo(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
|
||||||
|
if (resourcesImpl != null) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "- using existing impl=" + resourcesImpl);
|
||||||
|
}
|
||||||
|
return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
|
||||||
|
resourcesImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will create the ResourcesImpl object outside of holding this lock.
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Clean up any dead references so they don't pile up.
|
||||||
|
ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
|
||||||
|
|
||||||
|
// Not tied to an Activity, find a shared Resources that has the right ResourcesImpl
|
||||||
|
ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
|
||||||
|
if (resourcesImpl != null) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "- using existing impl=" + resourcesImpl);
|
||||||
|
}
|
||||||
|
return getOrCreateResourcesLocked(classLoader, resourcesImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will create the ResourcesImpl object outside of holding this lock.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
|
||||||
|
ResourcesImpl resourcesImpl = createResourcesImpl(key);
|
||||||
|
|
||||||
|
final String[] systemLocales = findSystemLocales
|
||||||
|
? AssetManager.getSystem().getLocales() : null;
|
||||||
|
final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
|
||||||
|
// Avoid checking for non-pseudo-locales if we already know there were some from a previous
|
||||||
|
// Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
|
||||||
|
// since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
|
||||||
|
// able to affect mHasNonSystemLocales.
|
||||||
|
final boolean isPseudoLocalesOnly = hasNonSystemLocales ||
|
||||||
|
LocaleList.isPseudoLocalesOnly(nonSystemLocales);
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
if (mSystemLocales == null || mSystemLocales.length == 0) {
|
||||||
|
mSystemLocales = systemLocales;
|
||||||
|
}
|
||||||
|
mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
|
||||||
|
mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
|
||||||
|
|
||||||
|
ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
|
||||||
|
if (existingResourcesImpl != null) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
|
||||||
|
+ " new impl=" + resourcesImpl);
|
||||||
|
}
|
||||||
|
resourcesImpl.getAssets().close();
|
||||||
|
resourcesImpl = existingResourcesImpl;
|
||||||
|
} else {
|
||||||
|
// Add this ResourcesImpl to the cache.
|
||||||
|
mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Resources resources;
|
||||||
|
if (activityToken != null) {
|
||||||
|
resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
|
||||||
|
resourcesImpl);
|
||||||
|
} else {
|
||||||
|
resources = getOrCreateResourcesLocked(classLoader, resourcesImpl);
|
||||||
|
}
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates a new Resources object associated with the IBinder token. References returned
|
* Gets or creates a new Resources object associated with the IBinder token. References returned
|
||||||
* by this method live as long as the Activity, meaning they can be cached and used by the
|
* by this method live as long as the Activity, meaning they can be cached and used by the
|
||||||
@@ -425,92 +616,8 @@ public class ResourcesManager {
|
|||||||
displayId,
|
displayId,
|
||||||
overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
|
overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
|
||||||
compatInfo);
|
compatInfo);
|
||||||
|
|
||||||
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
|
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
|
||||||
|
return getOrCreateResources(activityToken, key, classLoader);
|
||||||
final boolean findSystemLocales;
|
|
||||||
final boolean hasNonSystemLocales;
|
|
||||||
synchronized (this) {
|
|
||||||
findSystemLocales = (mSystemLocales == null || mSystemLocales.length == 0);
|
|
||||||
hasNonSystemLocales = mHasNonSystemLocales;
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
Throwable here = new Throwable();
|
|
||||||
here.fillInStackTrace();
|
|
||||||
Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activityToken != null) {
|
|
||||||
ResourcesImpl resourcesImpl = findResourcesImplForKey(key);
|
|
||||||
if (resourcesImpl != null) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "- using existing impl=" + resourcesImpl);
|
|
||||||
}
|
|
||||||
return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
|
|
||||||
resourcesImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We will create the ResourcesImpl object outside of holding this lock.
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Clean up any dead references so they don't pile up.
|
|
||||||
ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
|
|
||||||
|
|
||||||
// Not tied to an Activity, find a shared Resources that has the right ResourcesImpl
|
|
||||||
ResourcesImpl resourcesImpl = findResourcesImplForKey(key);
|
|
||||||
if (resourcesImpl != null) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "- using existing impl=" + resourcesImpl);
|
|
||||||
}
|
|
||||||
return getOrCreateResourcesLocked(classLoader, resourcesImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We will create the ResourcesImpl object outside of holding this lock.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
|
|
||||||
ResourcesImpl resourcesImpl = createResourcesImpl(key);
|
|
||||||
|
|
||||||
final String[] systemLocales = findSystemLocales
|
|
||||||
? AssetManager.getSystem().getLocales() : null;
|
|
||||||
final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
|
|
||||||
// Avoid checking for non-pseudo-locales if we already know there were some from a previous
|
|
||||||
// Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
|
|
||||||
// since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
|
|
||||||
// able to affect mHasNonSystemLocales.
|
|
||||||
final boolean isPseudoLocalesOnly = hasNonSystemLocales ||
|
|
||||||
LocaleList.isPseudoLocalesOnly(nonSystemLocales);
|
|
||||||
|
|
||||||
synchronized (this) {
|
|
||||||
if (mSystemLocales == null || mSystemLocales.length == 0) {
|
|
||||||
mSystemLocales = systemLocales;
|
|
||||||
}
|
|
||||||
mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
|
|
||||||
mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
|
|
||||||
|
|
||||||
ResourcesImpl existingResourcesImpl = findResourcesImplForKey(key);
|
|
||||||
if (existingResourcesImpl != null) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
|
|
||||||
+ " new impl=" + resourcesImpl);
|
|
||||||
}
|
|
||||||
resourcesImpl.getAssets().close();
|
|
||||||
resourcesImpl = existingResourcesImpl;
|
|
||||||
} else {
|
|
||||||
// Add this ResourcesImpl to the cache.
|
|
||||||
mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
|
|
||||||
}
|
|
||||||
|
|
||||||
final Resources resources;
|
|
||||||
if (activityToken != null) {
|
|
||||||
resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
|
|
||||||
resourcesImpl);
|
|
||||||
} else {
|
|
||||||
resources = getOrCreateResourcesLocked(classLoader, resourcesImpl);
|
|
||||||
}
|
|
||||||
return resources;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -524,31 +631,78 @@ public class ResourcesManager {
|
|||||||
*/
|
*/
|
||||||
public void updateResourcesForActivity(@NonNull IBinder activityToken,
|
public void updateResourcesForActivity(@NonNull IBinder activityToken,
|
||||||
@Nullable Configuration overrideConfig) {
|
@Nullable Configuration overrideConfig) {
|
||||||
final ClassLoader classLoader;
|
|
||||||
final ResourcesKey oldKey;
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
// Extract the ResourcesKey that was last used to create the Resources for this
|
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
|
||||||
// activity.
|
activityToken);
|
||||||
WeakReference<Resources> weakResRef = mActivityResourceReferences.get(activityToken);
|
|
||||||
final Resources resources = weakResRef != null ? weakResRef.get() : null;
|
if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
|
||||||
if (resources == null) {
|
// They are the same, no work to do.
|
||||||
Slog.e(TAG, "can't update resources for uncached activity " + activityToken);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
classLoader = resources.getClassLoader();
|
// Grab a copy of the old configuration so we can create the delta's of each
|
||||||
oldKey = findKeyForResourceImpl(resources.getImpl());
|
// Resources object associated with this Activity.
|
||||||
if (oldKey == null) {
|
final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
|
||||||
Slog.e(TAG, "can't find ResourcesKey for resources impl=" + resources.getImpl());
|
|
||||||
return;
|
// Update the Activity's base override.
|
||||||
|
if (overrideConfig != null) {
|
||||||
|
activityResources.overrideConfig.setTo(overrideConfig);
|
||||||
|
} else {
|
||||||
|
activityResources.overrideConfig.setToDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean activityHasOverrideConfig =
|
||||||
|
!activityResources.overrideConfig.equals(Configuration.EMPTY);
|
||||||
|
|
||||||
|
// Rebase each Resources associated with this Activity.
|
||||||
|
final int refCount = activityResources.activityResources.size();
|
||||||
|
for (int i = 0; i < refCount; i++) {
|
||||||
|
WeakReference<Resources> weakResRef = activityResources.activityResources.get(i);
|
||||||
|
Resources resources = weakResRef.get();
|
||||||
|
if (resources == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the ResourcesKey that was last used to create the Resources for this
|
||||||
|
// activity.
|
||||||
|
final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
|
||||||
|
if (oldKey == null) {
|
||||||
|
Slog.e(TAG, "can't find ResourcesKey for resources impl="
|
||||||
|
+ resources.getImpl());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the new override configuration for this ResourcesKey.
|
||||||
|
final Configuration rebasedOverrideConfig = new Configuration();
|
||||||
|
if (overrideConfig != null) {
|
||||||
|
rebasedOverrideConfig.setTo(overrideConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
|
||||||
|
// Generate a delta between the old base Activity override configuration and
|
||||||
|
// the actual final override configuration that was used to figure out the real
|
||||||
|
// delta this Resources object wanted.
|
||||||
|
Configuration overrideOverrideConfig = Configuration.generateDelta(
|
||||||
|
oldConfig, oldKey.mOverrideConfiguration);
|
||||||
|
rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the new ResourcesKey with the rebased override config.
|
||||||
|
final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs,
|
||||||
|
oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
|
||||||
|
rebasedOverrideConfig, oldKey.mCompatInfo);
|
||||||
|
|
||||||
|
ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
|
||||||
|
if (resourcesImpl == null) {
|
||||||
|
resourcesImpl = createResourcesImpl(newKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourcesImpl != resources.getImpl()) {
|
||||||
|
// Set the ResourcesImpl, updating it for all users of this Resources object.
|
||||||
|
resources.setImpl(resourcesImpl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the Resources object with the new override config and all of the existing
|
|
||||||
// settings.
|
|
||||||
getResources(activityToken, oldKey.mResDir, oldKey.mSplitResDirs, oldKey.mOverlayDirs,
|
|
||||||
oldKey.mLibDirs, oldKey.mDisplayId, overrideConfig, oldKey.mCompatInfo,
|
|
||||||
classLoader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ void setDefaultLocalesLocked(@NonNull LocaleList locales) {
|
/* package */ void setDefaultLocalesLocked(@NonNull LocaleList locales) {
|
||||||
@@ -578,7 +732,7 @@ public class ResourcesManager {
|
|||||||
int changes = mResConfiguration.updateFrom(config);
|
int changes = mResConfiguration.updateFrom(config);
|
||||||
// Things might have changed in display manager, so clear the cached displays.
|
// Things might have changed in display manager, so clear the cached displays.
|
||||||
mDisplays.clear();
|
mDisplays.clear();
|
||||||
DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked();
|
DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
|
||||||
|
|
||||||
if (compat != null && (mResCompatibilityInfo == null ||
|
if (compat != null && (mResCompatibilityInfo == null ||
|
||||||
!mResCompatibilityInfo.equals(compat))) {
|
!mResCompatibilityInfo.equals(compat))) {
|
||||||
@@ -632,7 +786,7 @@ public class ResourcesManager {
|
|||||||
}
|
}
|
||||||
tmpConfig.setTo(localeAdjustedConfig);
|
tmpConfig.setTo(localeAdjustedConfig);
|
||||||
if (!isDefaultDisplay) {
|
if (!isDefaultDisplay) {
|
||||||
dm = getDisplayMetricsLocked(displayId);
|
dm = getDisplayMetrics(displayId);
|
||||||
applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
|
applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
|
||||||
}
|
}
|
||||||
if (hasOverrideConfiguration) {
|
if (hasOverrideConfiguration) {
|
||||||
|
|||||||
@@ -1251,6 +1251,15 @@
|
|||||||
<service android:name="android.os.BinderThreadPriorityService"
|
<service android:name="android.os.BinderThreadPriorityService"
|
||||||
android:process=":BinderThreadPriorityService" />
|
android:process=":BinderThreadPriorityService" />
|
||||||
|
|
||||||
|
<!-- Used by ApplyOverrideConfigurationTest -->
|
||||||
|
<activity android:name="android.app.activity.ApplyOverrideConfigurationActivity"
|
||||||
|
android:configChanges="orientation|screenSize">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<!-- Application components used for search manager tests -->
|
<!-- Application components used for search manager tests -->
|
||||||
|
|
||||||
<activity android:name="android.app.activity.SearchableActivity"
|
<activity android:name="android.app.activity.SearchableActivity"
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package android.app.activity;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
|
||||||
|
public class ApplyOverrideConfigurationActivity extends Activity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void attachBaseContext(Context newBase) {
|
||||||
|
super.attachBaseContext(newBase);
|
||||||
|
|
||||||
|
Configuration overrideConfig = new Configuration();
|
||||||
|
overrideConfig.smallestScreenWidthDp = ApplyOverrideConfigurationTest.OVERRIDE_WIDTH;
|
||||||
|
applyOverrideConfiguration(overrideConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package android.app.activity;
|
||||||
|
|
||||||
|
import android.app.UiAutomation;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.support.test.InstrumentationRegistry;
|
||||||
|
import android.support.test.filters.SmallTest;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.test.ActivityInstrumentationTestCase2;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ApplyOverrideConfigurationTest extends
|
||||||
|
ActivityInstrumentationTestCase2<ApplyOverrideConfigurationActivity> {
|
||||||
|
|
||||||
|
public static final int OVERRIDE_WIDTH = 9999;
|
||||||
|
|
||||||
|
public ApplyOverrideConfigurationTest() {
|
||||||
|
super(ApplyOverrideConfigurationActivity.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
|
||||||
|
getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConfigurationIsOverriden() throws Exception {
|
||||||
|
Configuration config = getActivity().getResources().getConfiguration();
|
||||||
|
assertEquals(OVERRIDE_WIDTH, config.smallestScreenWidthDp);
|
||||||
|
|
||||||
|
getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_90);
|
||||||
|
|
||||||
|
config = getActivity().getResources().getConfiguration();
|
||||||
|
assertEquals(OVERRIDE_WIDTH, config.smallestScreenWidthDp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
@Override
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ package android.content.res;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.app.ResourcesManager;
|
import android.app.ResourcesManager;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.support.test.filters.SmallTest;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.LocaleList;
|
import android.util.LocaleList;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
@@ -58,7 +58,7 @@ public class ResourcesManagerTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DisplayMetrics getDisplayMetricsLocked(int displayId) {
|
protected DisplayMetrics getDisplayMetrics(int displayId) {
|
||||||
return mDisplayMetrics;
|
return mDisplayMetrics;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -173,25 +173,12 @@ public class ResourcesManagerTest extends TestCase {
|
|||||||
|
|
||||||
// The implementations should be the same.
|
// The implementations should be the same.
|
||||||
assertSame(resources1.getImpl(), resources2.getImpl());
|
assertSame(resources1.getImpl(), resources2.getImpl());
|
||||||
|
|
||||||
final Configuration overrideConfig = new Configuration();
|
|
||||||
overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
|
||||||
Resources resources3 = mResourcesManager.getResources(
|
|
||||||
activity2, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
|
|
||||||
overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
|
|
||||||
|
|
||||||
// Since we requested new resources for activity2, the resource should be the same
|
|
||||||
// as the one returned before for activity2.
|
|
||||||
assertSame(resources2, resources3);
|
|
||||||
|
|
||||||
// But the implementation has changed.
|
|
||||||
assertNotSame(resources1.getImpl(), resources2.getImpl());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public void testThemesGetUpdatedWithNewImpl() {
|
public void testThemesGetUpdatedWithNewImpl() {
|
||||||
Binder activity1 = new Binder();
|
Binder activity1 = new Binder();
|
||||||
Resources resources1 = mResourcesManager.getResources(
|
Resources resources1 = mResourcesManager.createBaseActivityResources(
|
||||||
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
|
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
|
||||||
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
|
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
|
||||||
assertNotNull(resources1);
|
assertNotNull(resources1);
|
||||||
@@ -207,16 +194,59 @@ public class ResourcesManagerTest extends TestCase {
|
|||||||
|
|
||||||
final Configuration overrideConfig = new Configuration();
|
final Configuration overrideConfig = new Configuration();
|
||||||
overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||||
Resources resources2 = mResourcesManager.getResources(
|
mResourcesManager.updateResourcesForActivity(activity1, overrideConfig);
|
||||||
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY,
|
assertSame(resources1, theme.getResources());
|
||||||
overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
|
|
||||||
assertNotNull(resources2);
|
|
||||||
assertSame(resources1, resources2);
|
|
||||||
assertSame(resources2, theme.getResources());
|
|
||||||
|
|
||||||
// Make sure we can still access the data.
|
// Make sure we can still access the data.
|
||||||
assertTrue(theme.resolveAttribute(android.R.attr.windowNoTitle, value, true));
|
assertTrue(theme.resolveAttribute(android.R.attr.windowNoTitle, value, true));
|
||||||
assertEquals(TypedValue.TYPE_INT_BOOLEAN, value.type);
|
assertEquals(TypedValue.TYPE_INT_BOOLEAN, value.type);
|
||||||
assertTrue(value.data != 0);
|
assertTrue(value.data != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testMultipleResourcesForOneActivityGetUpdatedWhenActivityBaseUpdates() {
|
||||||
|
Binder activity1 = new Binder();
|
||||||
|
|
||||||
|
// Create a Resources for the Activity.
|
||||||
|
Configuration config1 = new Configuration();
|
||||||
|
config1.densityDpi = 280;
|
||||||
|
Resources resources1 = mResourcesManager.createBaseActivityResources(
|
||||||
|
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config1,
|
||||||
|
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
|
||||||
|
assertNotNull(resources1);
|
||||||
|
|
||||||
|
// Create a Resources based on the Activity.
|
||||||
|
Configuration config2 = new Configuration();
|
||||||
|
config2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
|
||||||
|
Resources resources2 = mResourcesManager.getResources(
|
||||||
|
activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config2,
|
||||||
|
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
|
||||||
|
assertNotNull(resources2);
|
||||||
|
|
||||||
|
assertNotSame(resources1, resources2);
|
||||||
|
assertNotSame(resources1.getImpl(), resources2.getImpl());
|
||||||
|
|
||||||
|
final Configuration expectedConfig1 = new Configuration();
|
||||||
|
expectedConfig1.setLocales(LocaleList.getAdjustedDefault());
|
||||||
|
expectedConfig1.densityDpi = 280;
|
||||||
|
assertEquals(expectedConfig1, resources1.getConfiguration());
|
||||||
|
|
||||||
|
// resources2 should be based on the Activity's override config, so the density should
|
||||||
|
// be the same as resources1.
|
||||||
|
final Configuration expectedConfig2 = new Configuration();
|
||||||
|
expectedConfig2.setLocales(LocaleList.getAdjustedDefault());
|
||||||
|
expectedConfig2.densityDpi = 280;
|
||||||
|
expectedConfig2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
|
||||||
|
assertEquals(expectedConfig2, resources2.getConfiguration());
|
||||||
|
|
||||||
|
// Now update the Activity base override, and both resources should update.
|
||||||
|
config1.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||||
|
mResourcesManager.updateResourcesForActivity(activity1, config1);
|
||||||
|
|
||||||
|
expectedConfig1.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||||
|
assertEquals(expectedConfig1, resources1.getConfiguration());
|
||||||
|
|
||||||
|
expectedConfig2.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||||
|
assertEquals(expectedConfig2, resources2.getConfiguration());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user