From 0356d7c391c4aa64e54a5aa398d58def673d0114 Mon Sep 17 00:00:00 2001 From: conradchen Date: Mon, 16 May 2022 21:17:28 -0400 Subject: [PATCH] [ChipGroup] Fix ChipGroup.getCheckedChipIds() returns wrong state In the Chip implementation, onCheckedChangeListener was called before onCheckedChangeListenerInternal. This causes an issue that in onCheckedChangeListener's callback, the checkable group's checked state is not updated yet, therefore ChipGroup.getCheckedChipIds() will return the outdated checked state. Fixes this by overriding Chip.setOnCheckedChangeListener to get full control of the execution order between onCheckedChangeListener and onCheckedChangeListenerInternal. Resolves https://github.com/material-components/material-components-android/issues/2691 PiperOrigin-RevId: 449100861 (cherry picked from commit 413a0479574b66be74f42bf9e8a11e1245c72a09) --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../google/android/material/chip/Chip.java | 30 +- .../material/appbar/MaterialToolbarTest.java | 2 +- .../material/badge/BadgeDrawableTest.java | 2 +- .../material/badge/BadgeUtilsTest.java | 2 +- .../BottomNavigationViewTest.java | 2 +- .../bottomsheet/BottomSheetBehaviorTest.java | 2 +- .../material/button/MaterialButtonTest.java | 2 +- .../button/MaterialButtonToggleGroupTest.java | 2 +- .../checkbox/MaterialCheckBoxTest.java | 2 +- .../android/material/chip/ChipGroupTest.java | 45 ++- .../android/material/chip/ChipTest.java | 2 +- .../material/color/DynamicColorsTest.java | 279 ++++++++++++++++++ .../material/color/MaterialColorsTest.java | 2 +- .../datepicker/CalendarStyleTest.java | 2 +- .../CompositeDateValidatorAnyTest.java | 2 +- .../CompositeDateValidatorTest.java | 2 +- .../DateValidatorPointBackwardTest.java | 2 +- .../DateValidatorPointForwardTest.java | 2 +- .../material/datepicker/MonthAdapterTest.java | 2 +- .../datepicker/MonthsPagerAdapterTest.java | 2 +- .../datepicker/RangeDateSelectorTest.java | 2 +- .../datepicker/SingleDateSelectorTest.java | 2 +- .../material/datepicker/UtcDatesTest.java | 2 +- .../MaterialDividerItemDecorationTest.java | 2 +- .../ElevationOverlayProviderTest.java | 2 +- .../ExtendedFloatingActionButtonTest.java | 2 +- .../floatingactionbutton/FabTest.java | 2 +- .../material/internal/ContextUtilsTest.java | 2 +- .../internal/ParcelableSparseArrayTest.java | 2 +- .../ParcelableSparseBooleanArrayTest.java | 2 +- .../ParcelableSparseIntArrayTest.java | 2 +- .../material/motion/MotionUtilsTest.java | 150 ++++++++++ .../navigation/NavigationBarItemViewTest.java | 2 +- .../radiobutton/MaterialRadioButtonTest.java | 2 +- .../resources/MaterialResourcesTest.java | 2 +- .../material/resources/ResourceLoadTest.java | 2 +- .../shape/MaterialShapeDrawableTest.java | 2 +- .../shape/ShapeAppearanceModelTest.java | 2 +- .../slider/RangeSliderConfigTest.java | 2 +- .../material/slider/SliderConfigTest.java | 2 +- .../material/slider/SliderEventTest.java | 2 +- .../material/slider/SliderKeyTestCommon.java | 2 +- .../slider/SliderRoundingErrorTest.java | 2 +- .../material/slider/SliderStateTest.java | 2 +- .../material/slider/SliderTouchTest.java | 2 +- .../material/snackbar/SnackbarTest.java | 2 +- .../ExposedDropdownMenuAccessibilityTest.java | 2 +- .../TextInputLayoutAccessibilityTest.java | 90 ++++++ .../textview/MaterialTextViewTest.java | 2 +- .../theme/MaterialThemeOverlayTest.java | 2 +- .../android/material/theme/ThemeTest.java | 2 +- .../timepicker/ClockHandViewTouchTest.java | 2 +- .../TimePickerTextInputKeyControllerTest.java | 2 +- 55 files changed, 636 insertions(+), 58 deletions(-) create mode 100644 lib/javatests/com/google/android/material/color/DynamicColorsTest.java create mode 100644 lib/javatests/com/google/android/material/motion/MotionUtilsTest.java create mode 100644 lib/javatests/com/google/android/material/textfield/TextInputLayoutAccessibilityTest.java diff --git a/build.gradle b/build.gradle index dcd3a842e11..52f66a2d798 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' + classpath 'com.android.tools.build:gradle:7.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 088a275f37e..0892193d347 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip diff --git a/lib/java/com/google/android/material/chip/Chip.java b/lib/java/com/google/android/material/chip/Chip.java index c85dda446e7..53972da6b50 100644 --- a/lib/java/com/google/android/material/chip/Chip.java +++ b/lib/java/com/google/android/material/chip/Chip.java @@ -16,6 +16,7 @@ package com.google.android.material.chip; +import android.widget.CompoundButton.OnCheckedChangeListener; import com.google.android.material.R; import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; @@ -54,6 +55,7 @@ import android.view.ViewParent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.CompoundButton; import androidx.annotation.AnimatorRes; import androidx.annotation.BoolRes; import androidx.annotation.CallSuper; @@ -151,6 +153,7 @@ public class Chip extends AppCompatCheckBox @Nullable private RippleDrawable ripple; @Nullable private OnClickListener onCloseIconClickListener; + @Nullable private CompoundButton.OnCheckedChangeListener onCheckedChangeListener; @Nullable private MaterialCheckable.OnCheckedChangeListener onCheckedChangeListenerInternal; private boolean deferredCheckedValue; private boolean closeIconPressed; @@ -251,6 +254,19 @@ public Chip(Context context, AttributeSet attrs, int defStyleAttr) { setMinHeight(minTouchTargetSize); } lastLayoutDirection = ViewCompat.getLayoutDirection(this); + + super.setOnCheckedChangeListener( + new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (onCheckedChangeListenerInternal != null) { + onCheckedChangeListenerInternal.onCheckedChanged(Chip.this, isChecked); + } + if (onCheckedChangeListener != null) { + onCheckedChangeListener.onCheckedChanged(buttonView, isChecked); + } + } + }); } @Override @@ -707,17 +723,17 @@ public void setChecked(boolean checked) { // Defer the setChecked() call until after initialization. deferredCheckedValue = checked; } else if (chipDrawable.isCheckable()) { - boolean wasChecked = isChecked(); super.setChecked(checked); - - if (wasChecked != checked) { - if (onCheckedChangeListenerInternal != null) { - onCheckedChangeListenerInternal.onCheckedChanged(this, checked); - } - } } } + @Override + public void setOnCheckedChangeListener( + @Nullable CompoundButton.OnCheckedChangeListener listener) { + // Do not call super here - the wrapped listener set in the constructor will call the listener. + onCheckedChangeListener = listener; + } + /** Register a callback to be invoked when the close icon is clicked. */ public void setOnCloseIconClickListener(OnClickListener listener) { this.onCloseIconClickListener = listener; diff --git a/lib/javatests/com/google/android/material/appbar/MaterialToolbarTest.java b/lib/javatests/com/google/android/material/appbar/MaterialToolbarTest.java index 2246da836b6..ee4032ac19d 100644 --- a/lib/javatests/com/google/android/material/appbar/MaterialToolbarTest.java +++ b/lib/javatests/com/google/android/material/appbar/MaterialToolbarTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.appbar; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java b/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java index 942f986a5af..a818ef4d2a6 100644 --- a/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java +++ b/lib/javatests/com/google/android/material/badge/BadgeDrawableTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.badge; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/badge/BadgeUtilsTest.java b/lib/javatests/com/google/android/material/badge/BadgeUtilsTest.java index d31197bfb78..593e29fa81c 100644 --- a/lib/javatests/com/google/android/material/badge/BadgeUtilsTest.java +++ b/lib/javatests/com/google/android/material/badge/BadgeUtilsTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.badge; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/bottomnavigation/BottomNavigationViewTest.java b/lib/javatests/com/google/android/material/bottomnavigation/BottomNavigationViewTest.java index ab64b1fee78..5b39a921cfd 100644 --- a/lib/javatests/com/google/android/material/bottomnavigation/BottomNavigationViewTest.java +++ b/lib/javatests/com/google/android/material/bottomnavigation/BottomNavigationViewTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.bottomnavigation; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/bottomsheet/BottomSheetBehaviorTest.java b/lib/javatests/com/google/android/material/bottomsheet/BottomSheetBehaviorTest.java index a5bb0f956b6..e2896331e1e 100644 --- a/lib/javatests/com/google/android/material/bottomsheet/BottomSheetBehaviorTest.java +++ b/lib/javatests/com/google/android/material/bottomsheet/BottomSheetBehaviorTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.bottomsheet; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/button/MaterialButtonTest.java b/lib/javatests/com/google/android/material/button/MaterialButtonTest.java index 6bca637637c..d8107d06747 100644 --- a/lib/javatests/com/google/android/material/button/MaterialButtonTest.java +++ b/lib/javatests/com/google/android/material/button/MaterialButtonTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.button; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/button/MaterialButtonToggleGroupTest.java b/lib/javatests/com/google/android/material/button/MaterialButtonToggleGroupTest.java index e7598362858..5243dfd5d52 100644 --- a/lib/javatests/com/google/android/material/button/MaterialButtonToggleGroupTest.java +++ b/lib/javatests/com/google/android/material/button/MaterialButtonToggleGroupTest.java @@ -16,7 +16,7 @@ package com.google.android.material.button; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.view.View.GONE; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; diff --git a/lib/javatests/com/google/android/material/checkbox/MaterialCheckBoxTest.java b/lib/javatests/com/google/android/material/checkbox/MaterialCheckBoxTest.java index 5875705ce7b..b6ce903b066 100644 --- a/lib/javatests/com/google/android/material/checkbox/MaterialCheckBoxTest.java +++ b/lib/javatests/com/google/android/material/checkbox/MaterialCheckBoxTest.java @@ -16,7 +16,7 @@ package com.google.android.material.checkbox; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/chip/ChipGroupTest.java b/lib/javatests/com/google/android/material/chip/ChipGroupTest.java index a0b43b679d9..76b272af1a6 100644 --- a/lib/javatests/com/google/android/material/chip/ChipGroupTest.java +++ b/lib/javatests/com/google/android/material/chip/ChipGroupTest.java @@ -15,8 +15,9 @@ */ package com.google.android.material.chip; -import com.google.android.material.R; +import com.google.android.material.test.R; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -24,6 +25,7 @@ import android.content.Context; import androidx.appcompat.app.AppCompatActivity; import android.view.View; +import android.widget.CompoundButton; import androidx.core.view.ViewCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat; @@ -196,6 +198,29 @@ public void onCheckedChanged(ChipGroup group, List checkedIds) { assertThat(checkedIds).contains(second.getId()); } + @Test + public void multipleSelection_chipListener() { + chipgroup.setSingleSelection(false); + + Chip first = (Chip) chipgroup.getChildAt(0); + first.setOnCheckedChangeListener(this::onChipCheckedStateChanged); + + Chip second = (Chip) chipgroup.getChildAt(1); + second.setOnCheckedChangeListener(this::onChipCheckedStateChanged); + + first.performClick(); + getInstrumentation().waitForIdleSync(); + + assertThat(checkedChangeCallCount).isEqualTo(1); + assertThat(checkedIds).containsExactly(first.getId()); + + second.performClick(); + getInstrumentation().waitForIdleSync(); + + assertThat(checkedChangeCallCount).isEqualTo(2); + assertThat(checkedIds).containsExactly(first.getId(), second.getId()); + } + @Test public void multiSelection_withSelectionRequired_unSelectsIfTwo() { chipgroup.setSingleSelection(false); @@ -260,4 +285,22 @@ public void isNotSingleLine_initializesAccessibilityNodeInfo() { assertEquals(1, itemInfo.getRowIndex()); assertTrue(itemInfo.isSelected()); } + + @Test + public void getChipAccessibilityClassName_multipleChecked_buttonName() { + Chip chip = (Chip) chipgroup.getChildAt(0); + assertEquals("android.widget.Button", chip.getAccessibilityClassName().toString()); + } + + @Test + public void getChipAccessibilityClassName_singleChecked_radioButtonName() { + chipgroup.setSingleSelection(true); + Chip chip = (Chip) chipgroup.getChildAt(0); + assertEquals("android.widget.RadioButton", chip.getAccessibilityClassName().toString()); + } + + private void onChipCheckedStateChanged(CompoundButton chip, boolean checked) { + checkedChangeCallCount++; + checkedIds = chipgroup.getCheckedChipIds(); + } } diff --git a/lib/javatests/com/google/android/material/chip/ChipTest.java b/lib/javatests/com/google/android/material/chip/ChipTest.java index c3c5a61570d..e5ed1f5a3f5 100644 --- a/lib/javatests/com/google/android/material/chip/ChipTest.java +++ b/lib/javatests/com/google/android/material/chip/ChipTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.chip; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.android.material.internal.ViewUtils.dpToPx; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/color/DynamicColorsTest.java b/lib/javatests/com/google/android/material/color/DynamicColorsTest.java new file mode 100644 index 00000000000..cf6f79427f0 --- /dev/null +++ b/lib/javatests/com/google/android/material/color/DynamicColorsTest.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.material.color; + +import com.google.android.material.test.R; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static com.google.common.truth.Truth.assertThat; + +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import android.os.Build; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import androidx.appcompat.view.ContextThemeWrapper; +import com.google.android.material.color.DynamicColors.Precondition; +import com.google.android.material.resources.MaterialAttributes; +import com.google.common.collect.ImmutableList; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.ParameterizedRobolectricTestRunner; +import org.robolectric.ParameterizedRobolectricTestRunner.Parameter; +import org.robolectric.ParameterizedRobolectricTestRunner.Parameters; +import org.robolectric.Robolectric; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowContextThemeWrapper; +import org.robolectric.util.ReflectionHelpers; + +/** Tests the logic of {@link com.google.android.material.color.DynamicColors} utility class. */ +@RunWith(ParameterizedRobolectricTestRunner.class) +public class DynamicColorsTest { + @Parameter(0) + public String testName; + + @Parameter(1) + public int baseTheme; + + private final MockApplication mockApplication = new MockApplication(); + + private Activity mockActivity; + + @Parameters(name = "{0}") + public static ImmutableList getTestData() { + return ImmutableList.builder() + .add(new Object[] {"Test dynamic colors with Light Theme", R.style.Theme_Material3_Light}) + .build(); + } + + @Before + public void prepareTestActivity() { + setDynamicColorAvailability(true); + setSdkVersion(VERSION_CODES.S); + mockActivity = Robolectric.buildActivity(Activity.class).get(); + mockActivity.setTheme(baseTheme); + } + + @Test + public void testApplyOnApplicationWithDefaultTheme() { + DynamicColors.applyToActivitiesIfAvailable(mockApplication); + mockApplication.capturedCallbacks.onActivityPreCreated(mockActivity, new Bundle()); + + // TODO(b/230848477): Update tests to make sure dynamic colors theme overlay is indeed applied. + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnApplicationWithCustomTheme() { + final int mockThemeOverlay = 0xABCDABCD; + DynamicColors.applyToActivitiesIfAvailable(mockApplication, mockThemeOverlay); + mockApplication.capturedCallbacks.onActivityPreCreated(mockActivity, new Bundle()); + + // TODO(b/230848477): Update tests to make sure dynamic colors theme overlay is indeed applied. + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnApplicationWithPreconditionFalse() { + final MockPrecondition mockPrecondition = new MockPrecondition(); + DynamicColors.applyToActivitiesIfAvailable(mockApplication, mockPrecondition); + mockApplication.capturedCallbacks.onActivityPreCreated(mockActivity, new Bundle()); + + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnApplicationWithPreconditionTrue() { + final MockPrecondition mockPrecondition = new MockPrecondition(); + mockPrecondition.shouldApplyDynamicColors = true; + DynamicColors.applyToActivitiesIfAvailable(mockApplication, mockPrecondition); + mockApplication.capturedCallbacks.onActivityPreCreated(mockActivity, new Bundle()); + + // TODO(b/230848477): Update tests to make sure dynamic colors theme overlay is indeed applied. + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnApplicationWithCustomThemeAndPrecondition() { + final int mockThemeOverlay = 0xABCDABCD; + final MockPrecondition mockPrecondition = new MockPrecondition(); + mockPrecondition.shouldApplyDynamicColors = true; + DynamicColors.applyToActivitiesIfAvailable( + mockApplication, mockThemeOverlay, mockPrecondition); + mockApplication.capturedCallbacks.onActivityPreCreated(mockActivity, new Bundle()); + + // TODO(b/230848477): Update tests to make sure dynamic colors theme overlay is indeed applied. + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnApplicationWithNoDynamicColorAvailable() { + setDynamicColorAvailability(false); + final int mockThemeOverlay = 0xABCDABCD; + final MockPrecondition mockPrecondition = new MockPrecondition(); + mockPrecondition.shouldApplyDynamicColors = true; + DynamicColors.applyToActivitiesIfAvailable( + mockApplication, mockThemeOverlay, mockPrecondition); + mockApplication.capturedCallbacks.onActivityPreCreated(mockActivity, new Bundle()); + + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnApplicationWithLowSdkVersion() { + setSdkVersion(VERSION_CODES.Q); + final int mockThemeOverlay = 0xABCDABCD; + final MockPrecondition mockPrecondition = new MockPrecondition(); + mockPrecondition.shouldApplyDynamicColors = true; + DynamicColors.applyToActivitiesIfAvailable( + mockApplication, mockThemeOverlay, mockPrecondition); + mockApplication.capturedCallbacks.onActivityPreCreated(mockActivity, new Bundle()); + + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnActivityWithDefaultTheme() { + DynamicColors.applyIfAvailable(mockActivity); + + // TODO(b/230848477): Update tests to make sure dynamic colors theme overlay is indeed applied. + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnActivityWithCustomTheme() { + final int mockThemeOverlay = 0xABCDABCD; + DynamicColors.applyIfAvailable(mockActivity, mockThemeOverlay); + + // TODO(b/230848477): Update tests to make sure dynamic colors theme overlay is indeed applied. + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnActivityWithPreconditionFalse() { + final MockPrecondition mockPrecondition = new MockPrecondition(); + DynamicColors.applyIfAvailable(mockActivity, mockPrecondition); + + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnActivityWithPreconditionTrue() { + final MockPrecondition mockPrecondition = new MockPrecondition(); + mockPrecondition.shouldApplyDynamicColors = true; + DynamicColors.applyIfAvailable(mockActivity, mockPrecondition); + + // TODO(b/230848477): Update tests to make sure dynamic colors theme overlay is indeed applied. + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testApplyOnActivityWithNoDynamicColorAvailable() { + setDynamicColorAvailability(false); + final int mockThemeOverlay = 0xABCDABCD; + DynamicColors.applyIfAvailable(mockActivity, mockThemeOverlay); + + assertThat(getThemeResId(mockActivity)).isEqualTo(baseTheme); + } + + @Test + public void testIsDynamicColorAvailable() { + setDynamicColorAvailability(true); + setSdkVersion(VERSION_CODES.S); + assertThat(DynamicColors.isDynamicColorAvailable()).isTrue(); + } + + @Test + public void testIsDynamicColorAvailableWithNoDynamicColorAvailable() { + setDynamicColorAvailability(false); + assertThat(DynamicColors.isDynamicColorAvailable()).isFalse(); + } + + @Test + public void testIsDynamicColorAvailableWithLowSdkVersion() { + setSdkVersion(VERSION_CODES.Q); + assertThat(DynamicColors.isDynamicColorAvailable()).isFalse(); + } + + @Test + public void testWrapContextWithDefaultTheme() { + Context context = DynamicColors.wrapContextIfAvailable(mockActivity); + + assertThat(getThemeResId(context)) + .isEqualTo(resolveAttribute(baseTheme, R.attr.dynamicColorThemeOverlay)); + } + + @Test + public void testWrapContextWithCustomTheme() { + final int mockThemeOverlay = 0xABCDABCD; + Context context = DynamicColors.wrapContextIfAvailable(mockActivity, mockThemeOverlay); + + assertThat(getThemeResId(context)).isEqualTo(mockThemeOverlay); + } + + @Test + public void testWrapContextWithNoDynamicColorAvailable() { + setDynamicColorAvailability(false); + final int mockThemeOverlay = 0xABCDABCD; + Context context = DynamicColors.wrapContextIfAvailable(mockActivity, mockThemeOverlay); + + assertThat(getThemeResId(context)).isEqualTo(baseTheme); + } + + private void setDynamicColorAvailability(boolean available) { + ReflectionHelpers.setStaticField( + Build.class, "MANUFACTURER", available ? "Google" : "Unsupported OEM"); + } + + private void setSdkVersion(int sdkVersion) { + ReflectionHelpers.setStaticField( + Build.VERSION.class, "SDK_INT", sdkVersion); + } + + @SuppressWarnings("RestrictTo") + private static int resolveAttribute(int theme, int attribute) { + return MaterialAttributes.resolveOrThrow( + new ContextThemeWrapper(getApplicationContext(), theme), + attribute, + "missing in theme"); + } + + private static int getThemeResId(Context activity) { + ShadowContextThemeWrapper shadowContextThemeWrapper = Shadow.extract(activity); + return shadowContextThemeWrapper.callGetThemeResId(); + } + + private static class MockApplication extends Application { + private ActivityLifecycleCallbacks capturedCallbacks; + + @Override + public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) { + capturedCallbacks = callback; + } + } + + private static class MockPrecondition implements Precondition { + private boolean shouldApplyDynamicColors; + + @Override + public boolean shouldApplyDynamicColors(Activity activity, int theme) { + return shouldApplyDynamicColors; + } + } +} diff --git a/lib/javatests/com/google/android/material/color/MaterialColorsTest.java b/lib/javatests/com/google/android/material/color/MaterialColorsTest.java index 5450e000014..a24c095f644 100644 --- a/lib/javatests/com/google/android/material/color/MaterialColorsTest.java +++ b/lib/javatests/com/google/android/material/color/MaterialColorsTest.java @@ -16,7 +16,7 @@ package com.google.android.material.color; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/datepicker/CalendarStyleTest.java b/lib/javatests/com/google/android/material/datepicker/CalendarStyleTest.java index 28ee4c7080a..dea5aad3290 100644 --- a/lib/javatests/com/google/android/material/datepicker/CalendarStyleTest.java +++ b/lib/javatests/com/google/android/material/datepicker/CalendarStyleTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static org.junit.Assert.assertEquals; diff --git a/lib/javatests/com/google/android/material/datepicker/CompositeDateValidatorAnyTest.java b/lib/javatests/com/google/android/material/datepicker/CompositeDateValidatorAnyTest.java index e8968b99027..6ae8da1f84e 100644 --- a/lib/javatests/com/google/android/material/datepicker/CompositeDateValidatorAnyTest.java +++ b/lib/javatests/com/google/android/material/datepicker/CompositeDateValidatorAnyTest.java @@ -16,7 +16,7 @@ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/datepicker/CompositeDateValidatorTest.java b/lib/javatests/com/google/android/material/datepicker/CompositeDateValidatorTest.java index 5e71575b122..170fd82fe5a 100644 --- a/lib/javatests/com/google/android/material/datepicker/CompositeDateValidatorTest.java +++ b/lib/javatests/com/google/android/material/datepicker/CompositeDateValidatorTest.java @@ -16,7 +16,7 @@ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/datepicker/DateValidatorPointBackwardTest.java b/lib/javatests/com/google/android/material/datepicker/DateValidatorPointBackwardTest.java index 0af517c41b2..d58500d69cf 100644 --- a/lib/javatests/com/google/android/material/datepicker/DateValidatorPointBackwardTest.java +++ b/lib/javatests/com/google/android/material/datepicker/DateValidatorPointBackwardTest.java @@ -16,7 +16,7 @@ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/datepicker/DateValidatorPointForwardTest.java b/lib/javatests/com/google/android/material/datepicker/DateValidatorPointForwardTest.java index 42489972884..02ad41d6f21 100644 --- a/lib/javatests/com/google/android/material/datepicker/DateValidatorPointForwardTest.java +++ b/lib/javatests/com/google/android/material/datepicker/DateValidatorPointForwardTest.java @@ -16,7 +16,7 @@ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/datepicker/MonthAdapterTest.java b/lib/javatests/com/google/android/material/datepicker/MonthAdapterTest.java index 2ca42ab342e..9dcd5f4b5eb 100644 --- a/lib/javatests/com/google/android/material/datepicker/MonthAdapterTest.java +++ b/lib/javatests/com/google/android/material/datepicker/MonthAdapterTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; diff --git a/lib/javatests/com/google/android/material/datepicker/MonthsPagerAdapterTest.java b/lib/javatests/com/google/android/material/datepicker/MonthsPagerAdapterTest.java index 33ed4ed039c..531ebe7562d 100644 --- a/lib/javatests/com/google/android/material/datepicker/MonthsPagerAdapterTest.java +++ b/lib/javatests/com/google/android/material/datepicker/MonthsPagerAdapterTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static org.junit.Assert.assertEquals; diff --git a/lib/javatests/com/google/android/material/datepicker/RangeDateSelectorTest.java b/lib/javatests/com/google/android/material/datepicker/RangeDateSelectorTest.java index 8a8dc04252f..4b11d9833ce 100644 --- a/lib/javatests/com/google/android/material/datepicker/RangeDateSelectorTest.java +++ b/lib/javatests/com/google/android/material/datepicker/RangeDateSelectorTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/datepicker/SingleDateSelectorTest.java b/lib/javatests/com/google/android/material/datepicker/SingleDateSelectorTest.java index 87c1d63ae18..7e9914d1c6b 100644 --- a/lib/javatests/com/google/android/material/datepicker/SingleDateSelectorTest.java +++ b/lib/javatests/com/google/android/material/datepicker/SingleDateSelectorTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; diff --git a/lib/javatests/com/google/android/material/datepicker/UtcDatesTest.java b/lib/javatests/com/google/android/material/datepicker/UtcDatesTest.java index 76d849d416a..54c34a4c516 100644 --- a/lib/javatests/com/google/android/material/datepicker/UtcDatesTest.java +++ b/lib/javatests/com/google/android/material/datepicker/UtcDatesTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.datepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static org.junit.Assert.assertEquals; diff --git a/lib/javatests/com/google/android/material/divider/MaterialDividerItemDecorationTest.java b/lib/javatests/com/google/android/material/divider/MaterialDividerItemDecorationTest.java index df036e65c01..46a66e14016 100644 --- a/lib/javatests/com/google/android/material/divider/MaterialDividerItemDecorationTest.java +++ b/lib/javatests/com/google/android/material/divider/MaterialDividerItemDecorationTest.java @@ -16,7 +16,7 @@ package com.google.android.material.divider; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/elevation/ElevationOverlayProviderTest.java b/lib/javatests/com/google/android/material/elevation/ElevationOverlayProviderTest.java index dd907e15afd..d1527e05c2a 100644 --- a/lib/javatests/com/google/android/material/elevation/ElevationOverlayProviderTest.java +++ b/lib/javatests/com/google/android/material/elevation/ElevationOverlayProviderTest.java @@ -16,7 +16,7 @@ package com.google.android.material.elevation; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/floatingactionbutton/ExtendedFloatingActionButtonTest.java b/lib/javatests/com/google/android/material/floatingactionbutton/ExtendedFloatingActionButtonTest.java index 55d06ed3557..8739991e440 100644 --- a/lib/javatests/com/google/android/material/floatingactionbutton/ExtendedFloatingActionButtonTest.java +++ b/lib/javatests/com/google/android/material/floatingactionbutton/ExtendedFloatingActionButtonTest.java @@ -16,7 +16,7 @@ package com.google.android.material.floatingactionbutton; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/floatingactionbutton/FabTest.java b/lib/javatests/com/google/android/material/floatingactionbutton/FabTest.java index 88a81e95421..359983807c0 100644 --- a/lib/javatests/com/google/android/material/floatingactionbutton/FabTest.java +++ b/lib/javatests/com/google/android/material/floatingactionbutton/FabTest.java @@ -16,7 +16,7 @@ package com.google.android.material.floatingactionbutton; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static com.google.android.material.floatingactionbutton.FloatingActionButton.SIZE_MINI; diff --git a/lib/javatests/com/google/android/material/internal/ContextUtilsTest.java b/lib/javatests/com/google/android/material/internal/ContextUtilsTest.java index 2058e9d2f6d..651ae042a33 100644 --- a/lib/javatests/com/google/android/material/internal/ContextUtilsTest.java +++ b/lib/javatests/com/google/android/material/internal/ContextUtilsTest.java @@ -16,7 +16,7 @@ package com.google.android.material.internal; -import com.google.android.material.R; +import com.google.android.material.test.R; import android.app.Activity; import android.content.ContextWrapper; diff --git a/lib/javatests/com/google/android/material/internal/ParcelableSparseArrayTest.java b/lib/javatests/com/google/android/material/internal/ParcelableSparseArrayTest.java index d97fe341785..4ccf9805319 100644 --- a/lib/javatests/com/google/android/material/internal/ParcelableSparseArrayTest.java +++ b/lib/javatests/com/google/android/material/internal/ParcelableSparseArrayTest.java @@ -16,7 +16,7 @@ package com.google.android.material.internal; -import com.google.android.material.R; +import com.google.android.material.test.R; import android.os.Bundle; import android.os.Parcel; diff --git a/lib/javatests/com/google/android/material/internal/ParcelableSparseBooleanArrayTest.java b/lib/javatests/com/google/android/material/internal/ParcelableSparseBooleanArrayTest.java index 6597a2e9212..32743b1910d 100644 --- a/lib/javatests/com/google/android/material/internal/ParcelableSparseBooleanArrayTest.java +++ b/lib/javatests/com/google/android/material/internal/ParcelableSparseBooleanArrayTest.java @@ -16,7 +16,7 @@ package com.google.android.material.internal; -import com.google.android.material.R; +import com.google.android.material.test.R; import android.os.Parcel; import org.junit.Assert; diff --git a/lib/javatests/com/google/android/material/internal/ParcelableSparseIntArrayTest.java b/lib/javatests/com/google/android/material/internal/ParcelableSparseIntArrayTest.java index e55abfd5006..6ed59b64750 100644 --- a/lib/javatests/com/google/android/material/internal/ParcelableSparseIntArrayTest.java +++ b/lib/javatests/com/google/android/material/internal/ParcelableSparseIntArrayTest.java @@ -16,7 +16,7 @@ package com.google.android.material.internal; -import com.google.android.material.R; +import com.google.android.material.test.R; import android.os.Parcel; import org.junit.Assert; diff --git a/lib/javatests/com/google/android/material/motion/MotionUtilsTest.java b/lib/javatests/com/google/android/material/motion/MotionUtilsTest.java new file mode 100644 index 00000000000..ca488039e01 --- /dev/null +++ b/lib/javatests/com/google/android/material/motion/MotionUtilsTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.material.motion; + +import com.google.android.material.test.R; + +import static com.google.common.truth.Truth.assertThat; + +import android.animation.TimeInterpolator; +import android.os.Build.VERSION_CODES; +import androidx.appcompat.app.AppCompatActivity; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; +import android.view.animation.PathInterpolator; +import androidx.annotation.RequiresApi; +import androidx.test.core.app.ApplicationProvider; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.android.controller.ActivityController; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.internal.DoNotInstrument; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = VERSION_CODES.LOLLIPOP) +@DoNotInstrument +@RequiresApi(api = VERSION_CODES.LOLLIPOP) +public class MotionUtilsTest { + + private ActivityController activityController; + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + @Test + public void testResolvesThemeInterpolator() { + assertThemeInterpolatorIsInstanceOf( + R.style.Theme_Material3_DayNight, + R.attr.motionEasingStandardInterpolator, + LinearInterpolator.class); + } + + @Test + public void testCustomInterpolator_resolvesThemeInterpolator() { + assertThemeInterpolatorIsInstanceOf( + R.style.Theme_Material3_DayNight_CustomInterpolator, + R.attr.motionEasingStandardInterpolator, + LinearInterpolator.class); + } + + @Test + public void testCustomAnimInterpolator_resolvesThemeInterpolator() { + assertThemeInterpolatorIsInstanceOf( + R.style.Theme_Material3_DayNight_CustomAnimInterpolator, + R.attr.motionEasingStandardInterpolator, + LinearInterpolator.class); + } + + @Test + public void testResolvesLegacyInterpolator() { + assertThemeInterpolatorIsInstanceOf( + R.style.Theme_Material3_DayNight, R.attr.motionEasingStandard, PathInterpolator.class); + } + + @Test + public void testMaterialComponentsTheme_resolveUnavailableInterpolatorReturnsDefault() { + createActivityAndSetTheme(R.style.Theme_MaterialComponents_DayNight); + + DefaultDummyInterpolator defaultInterpolator = new DefaultDummyInterpolator(); + TimeInterpolator standardInterpolator = + MotionUtils.resolveThemeInterpolator( + activityController.get().getApplicationContext(), + R.attr.motionEasingStandardInterpolator, + defaultInterpolator); + assertThat(standardInterpolator).isEqualTo(defaultInterpolator); + } + + @Test + public void testMaterialComponentsTheme_resolvesLegacyInterpolator() { + assertThemeInterpolatorIsInstanceOf( + R.style.Theme_MaterialComponents_DayNight, + R.attr.motionEasingStandard, + PathInterpolator.class); + } + + @Test + public void testMaterialComponentsThemeIncorrectLegacyAttrType_shouldThrowException() { + createActivityAndSetTheme( + R.style.Theme_MaterialComponents_DayNight_IncorrectLegacyEasingAttrType); + + // ThrowingRunnable used by assertThrows is not available until gradle 4.13 + thrown.expect(IllegalArgumentException.class); + MotionUtils.resolveThemeInterpolator( + activityController.get().getApplicationContext(), + R.attr.motionEasingStandard, + new DefaultDummyInterpolator()); + } + + @Test + public void testMaterialComponentsThemeIncorrectLegacyFormatting_shouldThrowException() { + createActivityAndSetTheme( + R.style.Theme_MaterialComponents_DayNight_IncorrectLegacyEasingFormat); + + // ThrowingRunnable used by assertThrows is not available until gradle 4.13 + thrown.expect(IllegalArgumentException.class); + MotionUtils.resolveThemeInterpolator( + activityController.get().getApplicationContext(), + R.attr.motionEasingStandard, + new DefaultDummyInterpolator()); + } + + private void createActivityAndSetTheme(int themeId) { + ApplicationProvider.getApplicationContext().setTheme(themeId); + activityController = Robolectric.buildActivity(AppCompatActivity.class).create(); + } + + private void assertThemeInterpolatorIsInstanceOf(int theme, int attrId, Class expectedClass) { + createActivityAndSetTheme(theme); + DefaultDummyInterpolator defaultInterpolator = new DefaultDummyInterpolator(); + TimeInterpolator themeInterpolator = + MotionUtils.resolveThemeInterpolator( + activityController.get().getApplicationContext(), attrId, defaultInterpolator); + assertThat(themeInterpolator).isNotEqualTo(defaultInterpolator); + // Robolectric's shadow of Android's AnimationUtils always returns a LinearInterpolator. + assertThat(themeInterpolator).isInstanceOf(expectedClass); + } + + private static class DefaultDummyInterpolator implements Interpolator { + @Override + public float getInterpolation(float input) { + return 0; + } + } +} diff --git a/lib/javatests/com/google/android/material/navigation/NavigationBarItemViewTest.java b/lib/javatests/com/google/android/material/navigation/NavigationBarItemViewTest.java index ba96488a1dc..238fd18f8f6 100644 --- a/lib/javatests/com/google/android/material/navigation/NavigationBarItemViewTest.java +++ b/lib/javatests/com/google/android/material/navigation/NavigationBarItemViewTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.navigation; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.os.Build.VERSION_CODES.O; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/radiobutton/MaterialRadioButtonTest.java b/lib/javatests/com/google/android/material/radiobutton/MaterialRadioButtonTest.java index b0d841f2b18..b34b4cf9066 100644 --- a/lib/javatests/com/google/android/material/radiobutton/MaterialRadioButtonTest.java +++ b/lib/javatests/com/google/android/material/radiobutton/MaterialRadioButtonTest.java @@ -16,7 +16,7 @@ package com.google.android.material.radiobutton; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/resources/MaterialResourcesTest.java b/lib/javatests/com/google/android/material/resources/MaterialResourcesTest.java index 21ecc20c122..ef1f1a8ab88 100644 --- a/lib/javatests/com/google/android/material/resources/MaterialResourcesTest.java +++ b/lib/javatests/com/google/android/material/resources/MaterialResourcesTest.java @@ -16,7 +16,7 @@ package com.google.android.material.resources; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.content.Context.WINDOW_SERVICE; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/resources/ResourceLoadTest.java b/lib/javatests/com/google/android/material/resources/ResourceLoadTest.java index 58f11089b39..10ad80cfacb 100644 --- a/lib/javatests/com/google/android/material/resources/ResourceLoadTest.java +++ b/lib/javatests/com/google/android/material/resources/ResourceLoadTest.java @@ -16,7 +16,7 @@ package com.google.android.material.resources; -import com.google.android.material.R; +import com.google.android.material.test.R; import static org.junit.Assert.assertEquals; diff --git a/lib/javatests/com/google/android/material/shape/MaterialShapeDrawableTest.java b/lib/javatests/com/google/android/material/shape/MaterialShapeDrawableTest.java index ba9e2da184d..5f14eff542b 100644 --- a/lib/javatests/com/google/android/material/shape/MaterialShapeDrawableTest.java +++ b/lib/javatests/com/google/android/material/shape/MaterialShapeDrawableTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.shape; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/shape/ShapeAppearanceModelTest.java b/lib/javatests/com/google/android/material/shape/ShapeAppearanceModelTest.java index 9d114b4cc61..134e942c466 100644 --- a/lib/javatests/com/google/android/material/shape/ShapeAppearanceModelTest.java +++ b/lib/javatests/com/google/android/material/shape/ShapeAppearanceModelTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.shape; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/slider/RangeSliderConfigTest.java b/lib/javatests/com/google/android/material/slider/RangeSliderConfigTest.java index fabf9df4190..96396504fa4 100644 --- a/lib/javatests/com/google/android/material/slider/RangeSliderConfigTest.java +++ b/lib/javatests/com/google/android/material/slider/RangeSliderConfigTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.slider; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.os.Looper.getMainLooper; import static com.google.android.material.slider.BaseSlider.UNIT_PX; diff --git a/lib/javatests/com/google/android/material/slider/SliderConfigTest.java b/lib/javatests/com/google/android/material/slider/SliderConfigTest.java index 4f208d03046..eaad074eab1 100644 --- a/lib/javatests/com/google/android/material/slider/SliderConfigTest.java +++ b/lib/javatests/com/google/android/material/slider/SliderConfigTest.java @@ -15,7 +15,7 @@ */ package com.google.android.material.slider; -import com.google.android.material.R; +import com.google.android.material.test.R; import static org.robolectric.annotation.LooperMode.Mode.LEGACY; diff --git a/lib/javatests/com/google/android/material/slider/SliderEventTest.java b/lib/javatests/com/google/android/material/slider/SliderEventTest.java index d613e528197..52f506cec3b 100644 --- a/lib/javatests/com/google/android/material/slider/SliderEventTest.java +++ b/lib/javatests/com/google/android/material/slider/SliderEventTest.java @@ -16,7 +16,7 @@ package com.google.android.material.slider; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.android.material.slider.SliderHelper.dragSliderBetweenValues; import static com.google.android.material.slider.SliderHelper.touchSliderAtValue; diff --git a/lib/javatests/com/google/android/material/slider/SliderKeyTestCommon.java b/lib/javatests/com/google/android/material/slider/SliderKeyTestCommon.java index 612f4b7a06e..ee62c6f56a6 100644 --- a/lib/javatests/com/google/android/material/slider/SliderKeyTestCommon.java +++ b/lib/javatests/com/google/android/material/slider/SliderKeyTestCommon.java @@ -16,7 +16,7 @@ package com.google.android.material.slider; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.android.material.slider.SliderHelper.clickDpadCenter; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/slider/SliderRoundingErrorTest.java b/lib/javatests/com/google/android/material/slider/SliderRoundingErrorTest.java index d7479b2c8e3..5a2b443f0ef 100644 --- a/lib/javatests/com/google/android/material/slider/SliderRoundingErrorTest.java +++ b/lib/javatests/com/google/android/material/slider/SliderRoundingErrorTest.java @@ -16,7 +16,7 @@ package com.google.android.material.slider; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.android.material.slider.SliderHelper.touchSliderAtValue; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/slider/SliderStateTest.java b/lib/javatests/com/google/android/material/slider/SliderStateTest.java index bf986653a5b..49493b1637a 100644 --- a/lib/javatests/com/google/android/material/slider/SliderStateTest.java +++ b/lib/javatests/com/google/android/material/slider/SliderStateTest.java @@ -16,7 +16,7 @@ package com.google.android.material.slider; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/slider/SliderTouchTest.java b/lib/javatests/com/google/android/material/slider/SliderTouchTest.java index 1722d708108..d76f63ed914 100644 --- a/lib/javatests/com/google/android/material/slider/SliderTouchTest.java +++ b/lib/javatests/com/google/android/material/slider/SliderTouchTest.java @@ -16,7 +16,7 @@ package com.google.android.material.slider; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.android.material.slider.SliderHelper.calculateXPositionFromValue; import static com.google.android.material.slider.SliderHelper.dragSliderBetweenValues; diff --git a/lib/javatests/com/google/android/material/snackbar/SnackbarTest.java b/lib/javatests/com/google/android/material/snackbar/SnackbarTest.java index 7060c243f83..be3ea5f41f9 100644 --- a/lib/javatests/com/google/android/material/snackbar/SnackbarTest.java +++ b/lib/javatests/com/google/android/material/snackbar/SnackbarTest.java @@ -16,7 +16,7 @@ package com.google.android.material.snackbar; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.os.Build.VERSION_CODES.JELLY_BEAN; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/textfield/ExposedDropdownMenuAccessibilityTest.java b/lib/javatests/com/google/android/material/textfield/ExposedDropdownMenuAccessibilityTest.java index f33ffa9e261..91c4b38526a 100644 --- a/lib/javatests/com/google/android/material/textfield/ExposedDropdownMenuAccessibilityTest.java +++ b/lib/javatests/com/google/android/material/textfield/ExposedDropdownMenuAccessibilityTest.java @@ -16,7 +16,7 @@ package com.google.android.material.textfield; -import com.google.android.material.R; +import com.google.android.material.test.R; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; diff --git a/lib/javatests/com/google/android/material/textfield/TextInputLayoutAccessibilityTest.java b/lib/javatests/com/google/android/material/textfield/TextInputLayoutAccessibilityTest.java new file mode 100644 index 00000000000..f17bfede25a --- /dev/null +++ b/lib/javatests/com/google/android/material/textfield/TextInputLayoutAccessibilityTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.material.textfield; + +import com.google.android.material.test.R; + +import static com.google.android.material.textfield.TextInputLayout.END_ICON_CUSTOM; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import androidx.appcompat.app.AppCompatActivity; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import androidx.test.core.app.ApplicationProvider; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public final class TextInputLayoutAccessibilityTest { + + private TextInputLayout textInputLayout; + private final OnClickListener onClickListener = + new OnClickListener() { + @Override + public void onClick(View v) { + /* Do something */ + } + }; + + @Before + public void themeApplicationContext() { + ApplicationProvider.getApplicationContext() + .setTheme(R.style.Theme_Material3_DayNight_NoActionBar); + AppCompatActivity activity = Robolectric.buildActivity(AppCompatActivity.class).setup().get(); + View inflated = activity.getLayoutInflater().inflate(R.layout.test_text_input_layout, null); + ((ViewGroup) activity.findViewById(android.R.id.content)).addView(inflated); + textInputLayout = inflated.findViewById(R.id.text_input_layout); + } + + @Test + public void testPasswordEndIcon_importantForA11y() { + textInputLayout.setEndIconMode(TextInputLayout.END_ICON_PASSWORD_TOGGLE); + + assertThat(textInputLayout.getEndIconView().isImportantForAccessibility(), is(true)); + } + + @Test + public void testClearTextEndIcon_importantForA11y() { + textInputLayout.setEndIconMode(TextInputLayout.END_ICON_CLEAR_TEXT); + + assertThat(textInputLayout.getEndIconView().isImportantForAccessibility(), is(true)); + } + + @Test + public void testClickableCustomEndIcon_importantForA11y() { + textInputLayout.setEndIconMode(END_ICON_CUSTOM); + textInputLayout.setEndIconDrawable(new ColorDrawable(Color.GREEN)); + textInputLayout.setEndIconOnClickListener(onClickListener); + + assertThat(textInputLayout.getEndIconView().isImportantForAccessibility(), is(true)); + } + + @Test + public void testNonClickableCustomEndIcon_notImportantForA11y() { + textInputLayout.setEndIconMode(END_ICON_CUSTOM); + textInputLayout.setEndIconDrawable(new ColorDrawable(Color.GREEN)); + + assertThat(textInputLayout.getEndIconView().isImportantForAccessibility(), is(false)); + } +} diff --git a/lib/javatests/com/google/android/material/textview/MaterialTextViewTest.java b/lib/javatests/com/google/android/material/textview/MaterialTextViewTest.java index 32c06087e65..19e7ccbcf34 100644 --- a/lib/javatests/com/google/android/material/textview/MaterialTextViewTest.java +++ b/lib/javatests/com/google/android/material/textview/MaterialTextViewTest.java @@ -16,7 +16,7 @@ package com.google.android.material.textview; -import com.google.android.material.R; +import com.google.android.material.test.R; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/theme/MaterialThemeOverlayTest.java b/lib/javatests/com/google/android/material/theme/MaterialThemeOverlayTest.java index 730f5fe3e5f..fabcafd0ef9 100644 --- a/lib/javatests/com/google/android/material/theme/MaterialThemeOverlayTest.java +++ b/lib/javatests/com/google/android/material/theme/MaterialThemeOverlayTest.java @@ -16,7 +16,7 @@ package com.google.android.material.theme; -import com.google.android.material.R; +import com.google.android.material.test.R; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/theme/ThemeTest.java b/lib/javatests/com/google/android/material/theme/ThemeTest.java index 786fe1dbba8..ecbed55d092 100644 --- a/lib/javatests/com/google/android/material/theme/ThemeTest.java +++ b/lib/javatests/com/google/android/material/theme/ThemeTest.java @@ -16,7 +16,7 @@ package com.google.android.material.theme; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; diff --git a/lib/javatests/com/google/android/material/timepicker/ClockHandViewTouchTest.java b/lib/javatests/com/google/android/material/timepicker/ClockHandViewTouchTest.java index 27fe5ad66c8..65cc8d814c9 100644 --- a/lib/javatests/com/google/android/material/timepicker/ClockHandViewTouchTest.java +++ b/lib/javatests/com/google/android/material/timepicker/ClockHandViewTouchTest.java @@ -16,7 +16,7 @@ package com.google.android.material.timepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.os.Looper.getMainLooper; import static com.google.common.truth.Truth.assertThat; diff --git a/lib/javatests/com/google/android/material/timepicker/TimePickerTextInputKeyControllerTest.java b/lib/javatests/com/google/android/material/timepicker/TimePickerTextInputKeyControllerTest.java index 6310432d5d7..78783c31505 100644 --- a/lib/javatests/com/google/android/material/timepicker/TimePickerTextInputKeyControllerTest.java +++ b/lib/javatests/com/google/android/material/timepicker/TimePickerTextInputKeyControllerTest.java @@ -16,7 +16,7 @@ package com.google.android.material.timepicker; -import com.google.android.material.R; +import com.google.android.material.test.R; import static android.os.Looper.getMainLooper; import static com.google.common.truth.Truth.assertThat;