[M3][Color] Fix resources being re-harmonized when wrapContextIfAvailable() is used.

PiperOrigin-RevId: 446147925
(cherry picked from commit f0f07c5cf207e82bcbf05636a0919a09597a44b3)
This commit is contained in:
Material Design Team 2022-05-03 05:46:22 -04:00 committed by Dan Nizri
parent fcc10914f2
commit b402cb3c03
3 changed files with 44 additions and 29 deletions

View File

@ -16,8 +16,10 @@
package com.google.android.material.color;
import com.google.android.material.R;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.content.res.loader.ResourcesLoader;
import android.os.Build.VERSION;
@ -68,9 +70,11 @@ public class HarmonizedColors {
if (!isHarmonizedColorAvailable()) {
return;
}
int themeOverlay = options.getThemeOverlayResourceId();
Map<Integer, Integer> colorReplacementMap =
createHarmonizedColorReplacementMap(context, options);
int themeOverlay = options.getThemeOverlayResourceId(/* defaultThemeOverlay= */ 0);
if (addResourcesLoaderToContext(context, options) && themeOverlay != 0) {
if (addResourcesLoaderToContext(context, colorReplacementMap) && themeOverlay != 0) {
ThemeUtils.applyThemeOverlay(context, themeOverlay);
}
}
@ -93,13 +97,19 @@ public class HarmonizedColors {
if (!isHarmonizedColorAvailable()) {
return context;
}
int themeOverlay = options.getThemeOverlayResourceId();
Context newContext =
themeOverlay == 0
? new ContextWrapper(context)
: new ContextThemeWrapper(context, themeOverlay);
// Retrieve colors from original context passed in before the resources are overridden below.
Map<Integer, Integer> colorReplacementMap =
createHarmonizedColorReplacementMap(context, options);
// Empty themeOverlay is used as default to prevent ContextThemeWrapper uses the default theme
// of the application to wrap Context.
int themeOverlay =
options.getThemeOverlayResourceId(R.style.ThemeOverlay_Material3_HarmonizedColors_Empty);
ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, themeOverlay);
// Because ContextThemeWrapper does not provide a new set of resources, override config to
// retrieve the new set of resources and to keep the original context's resources intact.
themeWrapper.applyOverrideConfiguration(new Configuration());
return addResourcesLoaderToContext(newContext, options) ? newContext : context;
return addResourcesLoaderToContext(themeWrapper, colorReplacementMap) ? themeWrapper : context;
}
/**
@ -115,31 +125,18 @@ public class HarmonizedColors {
return VERSION.SDK_INT >= VERSION_CODES.R;
}
@RequiresApi(api = VERSION_CODES.R)
private static boolean addResourcesLoaderToContext(
Context context, HarmonizedColorsOptions options) {
ResourcesLoader resourcesLoader =
ColorResourcesLoaderCreator.create(
context, createHarmonizedColorReplacementMap(context, options));
if (resourcesLoader != null) {
context.getResources().addLoaders(resourcesLoader);
return true;
}
return false;
}
@RequiresApi(api = VERSION_CODES.LOLLIPOP)
private static Map<Integer, Integer> createHarmonizedColorReplacementMap(
Context context, HarmonizedColorsOptions options) {
Context originalContext, HarmonizedColorsOptions options) {
Map<Integer, Integer> colorReplacementMap = new HashMap<>();
int colorToHarmonizeWith =
MaterialColors.getColor(context, options.getColorAttributeToHarmonizeWith(), TAG);
MaterialColors.getColor(originalContext, options.getColorAttributeToHarmonizeWith(), TAG);
// Harmonize color resources.
for (int colorResourceId : options.getColorResourceIds()) {
int harmonizedColor =
MaterialColors.harmonize(
ContextCompat.getColor(context, colorResourceId), colorToHarmonizeWith);
ContextCompat.getColor(originalContext, colorResourceId), colorToHarmonizeWith);
colorReplacementMap.put(colorResourceId, harmonizedColor);
}
@ -151,10 +148,11 @@ public class HarmonizedColors {
// is not provided, look up resources value the theme attributes point to and
// harmonize directly.
int themeOverlay = colorAttributes.getThemeOverlay();
TypedArray themeAttributesTypedArray = context.obtainStyledAttributes(attributes);
TypedArray themeAttributesTypedArray = originalContext.obtainStyledAttributes(attributes);
TypedArray themeOverlayAttributesTypedArray =
themeOverlay != 0
? new ContextThemeWrapper(context, themeOverlay).obtainStyledAttributes(attributes)
? new ContextThemeWrapper(originalContext, themeOverlay)
.obtainStyledAttributes(attributes)
: null;
addHarmonizedColorAttributesToReplacementMap(
colorReplacementMap,
@ -171,6 +169,18 @@ public class HarmonizedColors {
return colorReplacementMap;
}
@RequiresApi(api = VERSION_CODES.R)
private static boolean addResourcesLoaderToContext(
Context context, Map<Integer, Integer> colorReplacementMap) {
ResourcesLoader resourcesLoader =
ColorResourcesLoaderCreator.create(context, colorReplacementMap);
if (resourcesLoader != null) {
context.getResources().addLoaders(resourcesLoader);
return true;
}
return false;
}
// TypedArray.getType() requires API >= 21.
@RequiresApi(api = VERSION_CODES.LOLLIPOP)
private static void addHarmonizedColorAttributesToReplacementMap(

View File

@ -127,7 +127,9 @@ public class HarmonizedColorsOptions {
}
@StyleRes
int getThemeOverlayResourceId() {
return this.colorAttributes != null ? colorAttributes.getThemeOverlay() : 0;
int getThemeOverlayResourceId(@StyleRes int defaultThemeOverlay) {
return (colorAttributes != null && colorAttributes.getThemeOverlay() != 0)
? colorAttributes.getThemeOverlay()
: defaultThemeOverlay;
}
}

View File

@ -23,4 +23,7 @@
<item name="colorOnErrorContainer">@color/material_harmonized_color_on_error_container</item>
</style>
<!-- Used to provide an empty theme overlay placeholder for harmonization. -->
<style name="ThemeOverlay.Material3.HarmonizedColors.Empty" parent="" />
</resources>