material-components-android
material-components-android copied to clipboard
[TabLayout] Default tab text appearance is incorrectly setting attributes for text appearance instead of style
Description:
When updating to 1.9.0 of material, we noticed an error when taking Paparazzi snapshot tests using a TabLayout. There was a change from 1.7.0 -> 1.9.0 where defaultTabTextAppearance was used.
Stacktrace
Jun 06, 2023 3:19:08 PM app.cash.paparazzi.internal.PaparazziLogger error
SEVERE: null: Style ResourceReference{namespace=apk/res-auto, type=attr, name=textAppearanceButton} is not of type STYLE (instead attr)
Jun 06, 2023 3:19:08 PM app.cash.paparazzi.internal.PaparazziLogger error
SEVERE: null: Style ResourceReference{namespace=apk/res-auto, type=attr, name=textAppearanceButton} is not of type STYLE (instead attr)
Jun 06, 2023 3:19:08 PM app.cash.paparazzi.internal.PaparazziLogger error
SEVERE: resources.resolve: Failed to find style with 2130969720
Cannot invoke "android.content.res.BridgeTypedArray.setTheme(android.content.res.Resources$Theme)" because "ta" is null
java.lang.NullPointerException: Cannot invoke "android.content.res.BridgeTypedArray.setTheme(android.content.res.Resources$Theme)" because "ta" is null
at android.content.res.Resources_Theme_Delegate.obtainStyledAttributes(Resources_Theme_Delegate.java:74)
at android.content.res.Resources$Theme.obtainStyledAttributes(Resources.java:1631)
at android.content.Context.obtainStyledAttributes(Context.java:874)
at android.widget.TextView.setTextAppearance(TextView.java:3965)
at androidx.appcompat.widget.AppCompatTextView.setTextAppearance(AppCompatTextView.java:216)
at android.widget.TextView.setTextAppearance(TextView.java:3954)
at androidx.core.widget.TextViewCompat.setTextAppearance(TextViewCompat.java:289)
...
at com.google.testing.junit.testparameterinjector.PluggableTestRunner$ContextMethodRule$1.evaluate(PluggableTestRunner.java:429)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:108)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
Expected behavior: Correctly load styles from attributes using something like this
val attrs = intArrayOf(defaultTabTextAppearance) // The array of attributes we're interested in.
val ta = context.obtainStyledAttributes(attrs) // Get the value referenced by the attributes in the array
val resId = ta.getResourceId(0, 0) // The first 0 is the index in the 'attrs' array.
ta.recycle() // Don't forget that! You can also use TypedArray.use { } extensions from android KTX.
TextViewCompat.setTextAppearance(textView, resId) // Utility method to set text appearance for all SDK versions
Source code: The code snippet which is causing this issue
class SampleTest {
@get:Rule
val paparazzi = Paparazzi(
deviceConfig = DeviceConfig.PIXEL_2.copy(fontScale = accessibilityTextSize.scale),
)
private val context: Context by lazy { paparazzi.context.wrapWithTheme { design.provide(this) } }
@Test
fun default() {
val view = TabLayout(context, null)
println("textAppearanceButton ID: " + com.google.android.material.R.attr.textAppearanceButton)
TextViewCompat.setTextAppearance(textView, com.google.android.material.R.attr.textAppearanceButton)
paparazzi.snapshot(view)
}
}
Minimal sample app repro: TBD
Android API version: 32 (via Paparazzi)
Material Library version: 1.9.0
Device: (Run via junit tests with Paparazzi)
Same problem. Also happens in version 1.8.0.
Bunch of render problems with this simple XML code:
<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab 1" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab 2" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab 3" />
</com.google.android.material.tabs.TabLayout>
Style ResourceReference{namespace=apk/res-auto, type=attr, name=textAppearanceTitleSmall} is not of type STYLE (instead attr)
java.lang.NullPointerException: Cannot invoke "android.content.res.BridgeTypedArray.setTheme(android.content.res.Resources$Theme)" because "ta" is null
Yes the version problem ; try switch to implementation "com.google.android.material:material:1.7.0"
This is still an issue with build 1.11.0