Skip to content

Commit b402cb3

Browse files
Material Design Teamdsn5ft
authored andcommitted
[M3][Color] Fix resources being re-harmonized when wrapContextIfAvailable() is used.
PiperOrigin-RevId: 446147925 (cherry picked from commit f0f07c5)
1 parent fcc1091 commit b402cb3

File tree

3 files changed

+45
-30
lines changed

3 files changed

+45
-30
lines changed

lib/java/com/google/android/material/color/HarmonizedColors.java

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
package com.google.android.material.color;
1818

19+
import com.google.android.material.R;
20+
1921
import android.content.Context;
20-
import android.content.ContextWrapper;
22+
import android.content.res.Configuration;
2123
import android.content.res.TypedArray;
2224
import android.content.res.loader.ResourcesLoader;
2325
import android.os.Build.VERSION;
@@ -68,9 +70,11 @@ public static void applyToContextIfAvailable(
6870
if (!isHarmonizedColorAvailable()) {
6971
return;
7072
}
71-
int themeOverlay = options.getThemeOverlayResourceId();
73+
Map<Integer, Integer> colorReplacementMap =
74+
createHarmonizedColorReplacementMap(context, options);
75+
int themeOverlay = options.getThemeOverlayResourceId(/* defaultThemeOverlay= */ 0);
7276

73-
if (addResourcesLoaderToContext(context, options) && themeOverlay != 0) {
77+
if (addResourcesLoaderToContext(context, colorReplacementMap) && themeOverlay != 0) {
7478
ThemeUtils.applyThemeOverlay(context, themeOverlay);
7579
}
7680
}
@@ -93,13 +97,19 @@ public static Context wrapContextIfAvailable(
9397
if (!isHarmonizedColorAvailable()) {
9498
return context;
9599
}
96-
int themeOverlay = options.getThemeOverlayResourceId();
97-
Context newContext =
98-
themeOverlay == 0
99-
? new ContextWrapper(context)
100-
: new ContextThemeWrapper(context, themeOverlay);
101-
102-
return addResourcesLoaderToContext(newContext, options) ? newContext : context;
100+
// Retrieve colors from original context passed in before the resources are overridden below.
101+
Map<Integer, Integer> colorReplacementMap =
102+
createHarmonizedColorReplacementMap(context, options);
103+
// Empty themeOverlay is used as default to prevent ContextThemeWrapper uses the default theme
104+
// of the application to wrap Context.
105+
int themeOverlay =
106+
options.getThemeOverlayResourceId(R.style.ThemeOverlay_Material3_HarmonizedColors_Empty);
107+
ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, themeOverlay);
108+
// Because ContextThemeWrapper does not provide a new set of resources, override config to
109+
// retrieve the new set of resources and to keep the original context's resources intact.
110+
themeWrapper.applyOverrideConfiguration(new Configuration());
111+
112+
return addResourcesLoaderToContext(themeWrapper, colorReplacementMap) ? themeWrapper : context;
103113
}
104114

105115
/**
@@ -115,31 +125,18 @@ public static boolean isHarmonizedColorAvailable() {
115125
return VERSION.SDK_INT >= VERSION_CODES.R;
116126
}
117127

118-
@RequiresApi(api = VERSION_CODES.R)
119-
private static boolean addResourcesLoaderToContext(
120-
Context context, HarmonizedColorsOptions options) {
121-
ResourcesLoader resourcesLoader =
122-
ColorResourcesLoaderCreator.create(
123-
context, createHarmonizedColorReplacementMap(context, options));
124-
if (resourcesLoader != null) {
125-
context.getResources().addLoaders(resourcesLoader);
126-
return true;
127-
}
128-
return false;
129-
}
130-
131128
@RequiresApi(api = VERSION_CODES.LOLLIPOP)
132129
private static Map<Integer, Integer> createHarmonizedColorReplacementMap(
133-
Context context, HarmonizedColorsOptions options) {
130+
Context originalContext, HarmonizedColorsOptions options) {
134131
Map<Integer, Integer> colorReplacementMap = new HashMap<>();
135132
int colorToHarmonizeWith =
136-
MaterialColors.getColor(context, options.getColorAttributeToHarmonizeWith(), TAG);
133+
MaterialColors.getColor(originalContext, options.getColorAttributeToHarmonizeWith(), TAG);
137134

138135
// Harmonize color resources.
139136
for (int colorResourceId : options.getColorResourceIds()) {
140137
int harmonizedColor =
141138
MaterialColors.harmonize(
142-
ContextCompat.getColor(context, colorResourceId), colorToHarmonizeWith);
139+
ContextCompat.getColor(originalContext, colorResourceId), colorToHarmonizeWith);
143140
colorReplacementMap.put(colorResourceId, harmonizedColor);
144141
}
145142

@@ -151,10 +148,11 @@ private static Map<Integer, Integer> createHarmonizedColorReplacementMap(
151148
// is not provided, look up resources value the theme attributes point to and
152149
// harmonize directly.
153150
int themeOverlay = colorAttributes.getThemeOverlay();
154-
TypedArray themeAttributesTypedArray = context.obtainStyledAttributes(attributes);
151+
TypedArray themeAttributesTypedArray = originalContext.obtainStyledAttributes(attributes);
155152
TypedArray themeOverlayAttributesTypedArray =
156153
themeOverlay != 0
157-
? new ContextThemeWrapper(context, themeOverlay).obtainStyledAttributes(attributes)
154+
? new ContextThemeWrapper(originalContext, themeOverlay)
155+
.obtainStyledAttributes(attributes)
158156
: null;
159157
addHarmonizedColorAttributesToReplacementMap(
160158
colorReplacementMap,
@@ -171,6 +169,18 @@ private static Map<Integer, Integer> createHarmonizedColorReplacementMap(
171169
return colorReplacementMap;
172170
}
173171

172+
@RequiresApi(api = VERSION_CODES.R)
173+
private static boolean addResourcesLoaderToContext(
174+
Context context, Map<Integer, Integer> colorReplacementMap) {
175+
ResourcesLoader resourcesLoader =
176+
ColorResourcesLoaderCreator.create(context, colorReplacementMap);
177+
if (resourcesLoader != null) {
178+
context.getResources().addLoaders(resourcesLoader);
179+
return true;
180+
}
181+
return false;
182+
}
183+
174184
// TypedArray.getType() requires API >= 21.
175185
@RequiresApi(api = VERSION_CODES.LOLLIPOP)
176186
private static void addHarmonizedColorAttributesToReplacementMap(

lib/java/com/google/android/material/color/HarmonizedColorsOptions.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@ public HarmonizedColorsOptions build() {
127127
}
128128

129129
@StyleRes
130-
int getThemeOverlayResourceId() {
131-
return this.colorAttributes != null ? colorAttributes.getThemeOverlay() : 0;
130+
int getThemeOverlayResourceId(@StyleRes int defaultThemeOverlay) {
131+
return (colorAttributes != null && colorAttributes.getThemeOverlay() != 0)
132+
? colorAttributes.getThemeOverlay()
133+
: defaultThemeOverlay;
132134
}
133135
}

lib/java/com/google/android/material/color/res/values/theme_overlay.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@
2323
<item name="colorOnErrorContainer">@color/material_harmonized_color_on_error_container</item>
2424
</style>
2525

26+
<!-- Used to provide an empty theme overlay placeholder for harmonization. -->
27+
<style name="ThemeOverlay.Material3.HarmonizedColors.Empty" parent="" />
28+
2629
</resources>

0 commit comments

Comments
 (0)