Skip to content

Commit 153fdee

Browse files
vicmnsleticiarossi
authored andcommitted
[MaterialButton] Material button lollipop shape fix
Resolves #2331 Resolves #1797 GIT_ORIGIN_REV_ID=cd176426395bf93f701c623c00947384aabf0706 PiperOrigin-RevId: 393405994
1 parent 619c95c commit 153fdee

File tree

3 files changed

+64
-30
lines changed

3 files changed

+64
-30
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ ext {
2424
targetSdkVersion = 31
2525

2626
androidXVersions = [
27-
annotation : '1.0.1',
27+
annotation : '1.2.0',
2828
appCompat : '1.1.0',
2929
cardView : '1.0.0',
3030
constraintlayout : '2.0.1',

lib/java/com/google/android/material/button/MaterialButtonHelper.java

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import android.os.Build.VERSION_CODES;
3434
import androidx.core.graphics.drawable.DrawableCompat;
3535
import androidx.core.view.ViewCompat;
36+
import androidx.annotation.ChecksSdkIntAtLeast;
3637
import androidx.annotation.Dimension;
3738
import androidx.annotation.NonNull;
3839
import androidx.annotation.Nullable;
@@ -50,7 +51,11 @@
5051
@RestrictTo(LIBRARY_GROUP)
5152
class MaterialButtonHelper {
5253

53-
private static final boolean IS_LOLLIPOP = VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP;
54+
@ChecksSdkIntAtLeast(api = VERSION_CODES.LOLLIPOP)
55+
private static final boolean IS_MIN_LOLLIPOP = VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP;
56+
57+
private static final boolean IS_LOLLIPOP =
58+
VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && VERSION.SDK_INT <= VERSION_CODES.LOLLIPOP_MR1;
5459
private final MaterialButton materialButton;
5560
@NonNull private ShapeAppearanceModel shapeAppearanceModel;
5661

@@ -218,7 +223,7 @@ private Drawable createBackground() {
218223
? MaterialColors.getColor(materialButton, R.attr.colorSurface)
219224
: Color.TRANSPARENT);
220225

221-
if (IS_LOLLIPOP) {
226+
if (IS_MIN_LOLLIPOP) {
222227
maskDrawable = new MaterialShapeDrawable(shapeAppearanceModel);
223228
DrawableCompat.setTint(maskDrawable, Color.WHITE);
224229
rippleDrawable =
@@ -255,12 +260,13 @@ void setBackgroundColor(int color) {
255260
void setRippleColor(@Nullable ColorStateList rippleColor) {
256261
if (this.rippleColor != rippleColor) {
257262
this.rippleColor = rippleColor;
258-
if (IS_LOLLIPOP && materialButton.getBackground() instanceof RippleDrawable) {
263+
if (IS_MIN_LOLLIPOP && materialButton.getBackground() instanceof RippleDrawable) {
259264
((RippleDrawable) materialButton.getBackground())
260265
.setColor(RippleUtils.sanitizeRippleDrawableColor(rippleColor));
261-
} else if (!IS_LOLLIPOP && materialButton.getBackground() instanceof RippleDrawableCompat) {
262-
((RippleDrawableCompat) materialButton.getBackground()).setTintList(
263-
RippleUtils.sanitizeRippleDrawableColor(rippleColor));
266+
} else if (!IS_MIN_LOLLIPOP
267+
&& materialButton.getBackground() instanceof RippleDrawableCompat) {
268+
((RippleDrawableCompat) materialButton.getBackground())
269+
.setTintList(RippleUtils.sanitizeRippleDrawableColor(rippleColor));
264270
}
265271
}
266272
}
@@ -326,7 +332,7 @@ int getCornerRadius() {
326332
@Nullable
327333
private MaterialShapeDrawable getMaterialShapeDrawable(boolean getSurfaceColorStrokeDrawable) {
328334
if (rippleDrawable != null && rippleDrawable.getNumberOfLayers() > 0) {
329-
if (IS_LOLLIPOP) {
335+
if (IS_MIN_LOLLIPOP) {
330336
InsetDrawable insetDrawable = (InsetDrawable) rippleDrawable.getDrawable(0);
331337
LayerDrawable layerDrawable = (LayerDrawable) insetDrawable.getDrawable();
332338
return (MaterialShapeDrawable)
@@ -359,14 +365,28 @@ private MaterialShapeDrawable getSurfaceColorStrokeDrawable() {
359365
}
360366

361367
private void updateButtonShape(@NonNull ShapeAppearanceModel shapeAppearanceModel) {
362-
if (getMaterialShapeDrawable() != null) {
363-
getMaterialShapeDrawable().setShapeAppearanceModel(shapeAppearanceModel);
364-
}
365-
if (getSurfaceColorStrokeDrawable() != null) {
366-
getSurfaceColorStrokeDrawable().setShapeAppearanceModel(shapeAppearanceModel);
367-
}
368-
if (getMaskDrawable() != null) {
369-
getMaskDrawable().setShapeAppearanceModel(shapeAppearanceModel);
368+
// There seems to be a bug to drawables that is affecting Lollipop, since invalidation is not
369+
// changing an existing drawable shape. This is a fallback.
370+
if (IS_LOLLIPOP && !backgroundOverwritten) {
371+
// Store padding before setting background, since background overwrites padding values
372+
int paddingStart = ViewCompat.getPaddingStart(materialButton);
373+
int paddingTop = materialButton.getPaddingTop();
374+
int paddingEnd = ViewCompat.getPaddingEnd(materialButton);
375+
int paddingBottom = materialButton.getPaddingBottom();
376+
updateBackground();
377+
// Set the stored padding values
378+
ViewCompat.setPaddingRelative(
379+
materialButton, paddingStart, paddingTop, paddingEnd, paddingBottom);
380+
} else {
381+
if (getMaterialShapeDrawable() != null) {
382+
getMaterialShapeDrawable().setShapeAppearanceModel(shapeAppearanceModel);
383+
}
384+
if (getSurfaceColorStrokeDrawable() != null) {
385+
getSurfaceColorStrokeDrawable().setShapeAppearanceModel(shapeAppearanceModel);
386+
}
387+
if (getMaskDrawable() != null) {
388+
getMaskDrawable().setShapeAppearanceModel(shapeAppearanceModel);
389+
}
370390
}
371391
}
372392

@@ -431,5 +451,4 @@ private void setVerticalInsets(@Dimension int newInsetTop, @Dimension int newIns
431451
public int getInsetTop() {
432452
return insetTop;
433453
}
434-
435454
}

lib/javatests/com/google/android/material/button/MaterialButtonTest.java

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import android.content.Context;
2323
import android.graphics.drawable.Drawable;
24+
import android.os.Build;
2425
import androidx.core.graphics.drawable.DrawableCompat;
2526
import android.view.View.MeasureSpec;
2627
import androidx.annotation.Nullable;
@@ -36,9 +37,7 @@
3637
import org.robolectric.RobolectricTestRunner;
3738
import org.robolectric.annotation.Config;
3839

39-
/**
40-
* Tests for {@link com.google.android.material.button.MaterialButton}.
41-
*/
40+
/** Tests for {@link com.google.android.material.button.MaterialButton}. */
4241
@RunWith(RobolectricTestRunner.class)
4342
public class MaterialButtonTest {
4443

@@ -64,9 +63,22 @@ public void testSetShapeAppearanceModel_setCornerRadius() {
6463

6564
ShapeAppearanceModel newShapeAppearanceModel = materialButton.getShapeAppearanceModel();
6665

66+
assertThat(shapeAppearanceModel).isSameInstanceAs(newShapeAppearanceModel);
6767
assertThatCornerSizesMatch(shapeAppearanceModel, newShapeAppearanceModel);
6868
}
6969

70+
@Test
71+
@Config(sdk = Build.VERSION_CODES.LOLLIPOP)
72+
public void testShapeRippleDrawableInLollipop() {
73+
MaterialButton materialButton = new MaterialButton(context);
74+
ShapeAppearanceModel shapeAppearanceModel = materialButton.getShapeAppearanceModel();
75+
76+
materialButton.setCornerRadius((int) LARGE_CORNER_SIZE);
77+
ShapeAppearanceModel newShapeAppearanceModel = materialButton.getShapeAppearanceModel();
78+
assertThat(shapeAppearanceModel).isNotSameInstanceAs(newShapeAppearanceModel);
79+
assertThat(shapeAppearanceModel).isNotEqualTo(newShapeAppearanceModel);
80+
}
81+
7082
@Test
7183
public void testSetShapeAppearanceModel() {
7284
MaterialButton materialButton = new MaterialButton(context);
@@ -140,16 +152,19 @@ public void setIcon_iconUpdated_whenCalledTwice() {
140152
@Config(minSdk = 23, maxSdk = 28)
141153
public void setIcon_iconNotUpdated_whenPositionChanged() {
142154
callCount = 0;
143-
MaterialButton materialButton = new MaterialButton(context) {
144-
145-
@Override
146-
public void setCompoundDrawablesRelative(@Nullable Drawable left,
147-
@Nullable Drawable top, @Nullable Drawable right,
148-
@Nullable Drawable bottom) {
149-
super.setCompoundDrawablesRelative(left, top, right, bottom);
150-
callCount++;
151-
}
152-
};
155+
MaterialButton materialButton =
156+
new MaterialButton(context) {
157+
158+
@Override
159+
public void setCompoundDrawablesRelative(
160+
@Nullable Drawable left,
161+
@Nullable Drawable top,
162+
@Nullable Drawable right,
163+
@Nullable Drawable bottom) {
164+
super.setCompoundDrawablesRelative(left, top, right, bottom);
165+
callCount++;
166+
}
167+
};
153168

154169
Drawable drawable = ContextCompat.getDrawable(context, android.R.drawable.btn_plus);
155170
setIcon(materialButton, makeMeasureSpec(200), drawable);

0 commit comments

Comments
 (0)