material-components / material-components-android

Modular and customizable Material Design UI components for Android
Apache License 2.0
16.35k stars 3.07k forks source link

[MaterialDatePicker] Button colors are not showing correctly #3090

Closed leinardi closed 1 year ago

leinardi commented 1 year ago

Description: The button colors are not showing correctly on API < 30. The text and background color are pink, like the color attribute from the theme was not set. But the rest of the UI of the Dialog seems fine.

API 25: image

API 29: image

API 30: image

Expected behavior: Screenshots and/or description of expected behavior

Source code: The App theme is extending Theme.Material3.DayNight.NoActionBar but it's setting only colorPrimary, colorPrimaryDark and colorAccent (since this is a Compose only app, I'm trying to keep the XML theme attributes to the minimum).

Minimal sample app repro: Repro project available here: https://github.com/leinardi/Forlago/tree/date-piker

Android API version: The issue happens on API < 30 (tested on 29 and 25)

Material Library version: 1.7.0

Device: Emulator (Nexus 5)

drchen commented 1 year ago

That's a very interesting issue.....

We probably need to take a deep look into the interoperability between MDC Views components and the Compose framework.

Thanks for the report!!

dsn5ft commented 1 year ago

Hi @leinardi, I don't have any real answers yet but wanted to provide an update and see if you can help us a bit more.

First, I was able to clone your project and reproduce your issue, on an emulator running API level 29 (Q):

image

Then, in order to try to narrow down the issue, I created a simple project which combines Compose and the Material Views-based library:

Interestingly, when running the above project on the same API level 29 (Q) device, I don't see the issue with the date picker button colors:

image

This implies that there's something else in your project configuration that could be contributing to the issue. Since your project is pretty large, I think we'll need some help from you to pare it down and determine the actual minimal conditions required to reproduce the issue (either by using a branch in your repo or by adding to my project until the issue shows up).

Let us know if you have any questions or ideas as to what from your project could be contributing to the issue.

leinardi commented 1 year ago

OK, I made some changes to your simple project and I managed to reproduce the issue... and it's very weird: it happens only if you use androidx.core:core-splashscreen and set WindowCompat.setDecorFitsSystemWindows(window, false)! :exploding_head:

If you disable the splash screen and set WindowCompat.setDecorFitsSystemWindows(window, false) it works fine. Same if you keep the splash screen but do not set WindowCompat.setDecorFitsSystemWindows(window, false)...

leinardi commented 1 year ago

Hi @dsn5ft, any clue on why this issue happens and why it affects only the buttons?

dsn5ft commented 1 year ago

Wow great find regarding the splashscreen + setDecorFitsSystemWindows!

I have no idea why this combination of things would result in the buttons not being able to parse the colors correctly, but will think about it a bit more and send to another team if necessary.

leinardi commented 1 year ago

Hi, any update on this issue? Was it moved to a different team? Is there another issue that we can track to get updates?

dsn5ft commented 1 year ago

@leinardi I have a couple of potentially interesting findings:

  1. I was able to simplify / minimize your diff a bit to reproduce the issue (https://github.com/dsn5ft/basic-m3-compose-with-mdc/compare/main...splash-screen-setup)
  2. I made a separate minimal M3 project without Compose, so basically just combining the MDC and SplashScreen setup, and was also able to reproduce the issue there. So this seems to have nothing to do with Compose.
  3. If I move the WindowCompat.setDecorFitsSystemWindows(window, false) to be before super.onCreate(savedInstanceState), it seems to get rid of the issue. Although now that I think about it, I'm not sure if WindowCompat.setDecorFitsSystemWindows(window, false) has to be after onCreate in order to do anything? I can't really tell in my project. Can you try in your projects and see if a) that fixes the issues and b) it's still going edge-to-edge as you expect?
dsn5ft commented 1 year ago

Also just for reference, I do see this warning which shows the ColorStateList from MaterialDatePicker not being able to inflate correctly. It's likely do to some sort of context / theming issue in the way that the postSplashScreenTheme works:

2022-12-07 12:44:21.854 15165-15165 ResourcesCompat         com.example.basicm3compose           W  Failed to inflate ColorStateList, leaving it to the framework
                                                                                                    java.lang.UnsupportedOperationException: Failed to resolve attribute at index 0: TypedValue{t=0x2/d=0x7f0300cb a=-1}
                                                                                                        at android.content.res.TypedArray.getColor(TypedArray.java:527)
                                                                                                        at androidx.core.content.res.ColorStateListInflaterCompat.inflate(ColorStateListInflaterCompat.java:160)
                                                                                                        at androidx.core.content.res.ColorStateListInflaterCompat.createFromXmlInner(ColorStateListInflaterCompat.java:125)
                                                                                                        at androidx.core.content.res.ColorStateListInflaterCompat.createFromXml(ColorStateListInflaterCompat.java:104)
                                                                                                        at androidx.core.content.res.ResourcesCompat.inflateColorStateList(ResourcesCompat.java:262)
                                                                                                        at androidx.core.content.res.ResourcesCompat.getColorStateList(ResourcesCompat.java:236)
                                                                                                        at androidx.core.content.ContextCompat.getColorStateList(ContextCompat.java:519)
                                                                                                        at androidx.appcompat.content.res.AppCompatResources.getColorStateList(AppCompatResources.java:48)
                                                                                                        at androidx.appcompat.widget.TintTypedArray.getColorStateList(TintTypedArray.java:179)
                                                                                                        at androidx.appcompat.widget.AppCompatBackgroundHelper.loadFromAttributes(AppCompatBackgroundHelper.java:66)
                                                                                                        at androidx.appcompat.widget.AppCompatButton.<init>(AppCompatButton.java:85)
                                                                                                        at androidx.appcompat.widget.AppCompatButton.<init>(AppCompatButton.java:75)
                                                                                                        at androidx.appcompat.app.AppCompatViewInflater.createButton(AppCompatViewInflater.java:211)
                                                                                                        at androidx.appcompat.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:129)
                                                                                                        at androidx.appcompat.app.AppCompatDelegateImpl.createView(AppCompatDelegateImpl.java:1569)
                                                                                                        at androidx.appcompat.app.AppCompatDelegateImpl.onCreateView(AppCompatDelegateImpl.java:1620)
                                                                                                        at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:242)
                                                                                                        at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1061)
                                                                                                        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:997)
                                                                                                        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
                                                                                                        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
                                                                                                        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
                                                                                                        at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1263)
                                                                                                        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1119)
                                                                                                        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
                                                                                                        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1126)
                                                                                                        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
                                                                                                        at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
                                                                                                        at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
                                                                                                        at android.view.LayoutInflater.inflate(LayoutInflater.java:481)
                                                                                                        at com.google.android.material.datepicker.MaterialDatePicker.onCreateView(MaterialDatePicker.java:235)
                                                                                                        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
                                                                                                        at androidx.fragment.app.DialogFragment.performCreateView(DialogFragment.java:489)
                                                                                                        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
                                                                                                        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
                                                                                                        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
                                                                                                        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
                                                                                                        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
                                                                                                        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3138)
                                                                                                        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
                                                                                                        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
                                                                                                        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
                                                                                                        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:248)
                                                                                                        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1425)
                                                                                                        at android.app.Activity.performStart(Activity.java:7825)
2022-12-07 12:44:21.854 15165-15165 ResourcesCompat         com.example.basicm3compose           W      at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3294)
                                                                                                        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
                                                                                                        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:107)
                                                                                                        at android.os.Looper.loop(Looper.java:214)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:7356)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
2022-12-07 12:44:21.856 15165-15165 ResourcesCompat         com.example.basicm3compose           W  Failed to inflate ColorStateList, leaving it to the framework
                                                                                                    java.lang.UnsupportedOperationException: Failed to resolve attribute at index 0: TypedValue{t=0x2/d=0x7f0300cb a=-1}
                                                                                                        at android.content.res.TypedArray.getColor(TypedArray.java:527)
                                                                                                        at androidx.core.content.res.ColorStateListInflaterCompat.inflate(ColorStateListInflaterCompat.java:160)
                                                                                                        at androidx.core.content.res.ColorStateListInflaterCompat.createFromXmlInner(ColorStateListInflaterCompat.java:125)
                                                                                                        at androidx.core.content.res.ColorStateListInflaterCompat.createFromXml(ColorStateListInflaterCompat.java:104)
                                                                                                        at androidx.core.content.res.ResourcesCompat.inflateColorStateList(ResourcesCompat.java:262)
                                                                                                        at androidx.core.content.res.ResourcesCompat.getColorStateList(ResourcesCompat.java:236)
                                                                                                        at androidx.core.content.ContextCompat.getColorStateList(ContextCompat.java:519)
                                                                                                        at androidx.appcompat.content.res.AppCompatResources.getColorStateList(AppCompatResources.java:48)
                                                                                                        at androidx.appcompat.widget.TintTypedArray.getColorStateList(TintTypedArray.java:179)
                                                                                                        at androidx.appcompat.widget.AppCompatBackgroundHelper.loadFromAttributes(AppCompatBackgroundHelper.java:66)
                                                                                                        at androidx.appcompat.widget.AppCompatButton.<init>(AppCompatButton.java:85)
                                                                                                        at androidx.appcompat.widget.AppCompatButton.<init>(AppCompatButton.java:75)
                                                                                                        at androidx.appcompat.app.AppCompatViewInflater.createButton(AppCompatViewInflater.java:211)
                                                                                                        at androidx.appcompat.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:129)
                                                                                                        at androidx.appcompat.app.AppCompatDelegateImpl.createView(AppCompatDelegateImpl.java:1569)
                                                                                                        at androidx.appcompat.app.AppCompatDelegateImpl.onCreateView(AppCompatDelegateImpl.java:1620)
                                                                                                        at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:242)
                                                                                                        at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1061)
                                                                                                        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:997)
                                                                                                        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
                                                                                                        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
                                                                                                        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
                                                                                                        at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1263)
                                                                                                        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1119)
                                                                                                        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
                                                                                                        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1126)
                                                                                                        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
                                                                                                        at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
                                                                                                        at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
                                                                                                        at android.view.LayoutInflater.inflate(LayoutInflater.java:481)
                                                                                                        at com.google.android.material.datepicker.MaterialDatePicker.onCreateView(MaterialDatePicker.java:235)
                                                                                                        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
                                                                                                        at androidx.fragment.app.DialogFragment.performCreateView(DialogFragment.java:489)
                                                                                                        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
                                                                                                        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
                                                                                                        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
                                                                                                        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
                                                                                                        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
                                                                                                        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3138)
                                                                                                        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
                                                                                                        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
                                                                                                        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
                                                                                                        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:248)
                                                                                                        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1425)
                                                                                                        at android.app.Activity.performStart(Activity.java:7825)
2022-12-07 12:44:21.856 15165-15165 ResourcesCompat         com.example.basicm3compose           W      at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3294)
                                                                                                        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
                                                                                                        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:107)
                                                                                                        at android.os.Looper.loop(Looper.java:214)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:7356)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
leinardi commented 1 year ago

3. If I move the WindowCompat.setDecorFitsSystemWindows(window, false) to be before super.onCreate(savedInstanceState), it seems to get rid of the issue. Although now that I think about it, I'm not sure if WindowCompat.setDecorFitsSystemWindows(window, false) has to be after onCreate in order to do anything? I can't really tell in my project. Can you try in your projects and see if a) that fixes the issues and b) it's still going edge-to-edge as you expect?

Hey good catch! Moving WindowCompat.setDecorFitsSystemWindows(window, false) before the onCreate() seems to fix it! And I don't see any other side effects: the app is still edge-to-edge :partying_face:

dsn5ft commented 1 year ago

Great! Actually, looking at the SplashScreen guide it seems like the installSplashScreen call is meant to be before onCreate():

https://developer.android.com/develop/ui/views/launch/splash-screen/migrate#migrate_your_splash_screen_implementation

And looking at the edge-to-edge guide, the setDecorFitsSystemWindows is supposed to be after onCreate():

https://developer.android.com/develop/ui/views/layout/edge-to-edge

I tried this in my sample app and that setup fixes the issue as well.

Also, I chatted with someone who works on the SplashScreen library, and they confirmed the above setup is correct. This issue had something to do with the timing of the DecorView creation in PhoneWindow and the theme inflation, so the order with respect to onCreate() is important.

leinardi commented 1 year ago

Oh damn, I completely missed that requirement 😅 Now I've added a comment to avoid the same mistake in the future. Thank you for digging deeper and providing the proper solution!