material-components / material-components/material-components-android

[TabLayout] Default tab text appearance is incorrectly setting attributes for text appearance instead of style

Open
#3,440 3 comments 8 reactions 1 assignee View on GitHub

@imhappi is already working on this.

Since Jan 4, 2024.

bug Widget: Tab
Dominant language
Java
Stars
17.4k
Forks
3.2k
PR merge metrics
No merged PRs in 30d

Description

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)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.