1616
1717package com .google .android .material .color ;
1818
19+ import com .google .android .material .R ;
20+
1921import android .content .Context ;
20- import android .content .ContextWrapper ;
22+ import android .content .res . Configuration ;
2123import android .content .res .TypedArray ;
2224import android .content .res .loader .ResourcesLoader ;
2325import 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 (
0 commit comments