Skip to content

Commit

Permalink
Workaround chip compositing bug that dropped stated_pressed and state…
Browse files Browse the repository at this point in the history
…_focused.

PiperOrigin-RevId: 260577585
  • Loading branch information
wcshi authored and dsn5ft committed Jul 29, 2019
1 parent 24a3fd4 commit d60fb3f
Show file tree
Hide file tree
Showing 7 changed files with 10 additions and 393 deletions.
38 changes: 10 additions & 28 deletions lib/java/com/google/android/material/chip/ChipDrawable.java
Expand Up @@ -162,18 +162,7 @@ public class ChipDrawable extends MaterialShapeDrawable
private static final boolean DEBUG = false;
private static final int[] DEFAULT_STATE = new int[] {android.R.attr.state_enabled};
private static final String NAMESPACE_APP = "http://schemas.android.com/apk/res-auto";
private static final int[][] states =
new int[][] {
new int[] {
android.R.attr.state_enabled, android.R.attr.state_selected,
},
new int[] {
android.R.attr.state_enabled, android.R.attr.state_checked,
},
new int[] {android.R.attr.state_enabled, android.R.attr.state_checkable},
new int[] {android.R.attr.state_enabled},
new int[] {} // default
};

private static final ShapeDrawable closeIconRippleMask = new ShapeDrawable(new OvalShape());

// Visuals
Expand Down Expand Up @@ -254,6 +243,7 @@ public class ChipDrawable extends MaterialShapeDrawable

@ColorInt private int currentChipSurfaceColor;
@ColorInt private int currentChipBackgroundColor;
@ColorInt private int currentCompositeSurfaceBackgroundColor;
@ColorInt private int currentChipStrokeColor;
@ColorInt private int currentCompatRippleColor;
@ColorInt private int currentTextColor;
Expand Down Expand Up @@ -996,6 +986,14 @@ private boolean onStateChange(int[] chipState, int[] closeIconState) {
invalidate = true;
}

int newCompositeSurfaceBackgroundColor =
MaterialColors.layer(newChipSurfaceColor, newChipBackgroundColor);
if (currentCompositeSurfaceBackgroundColor != newCompositeSurfaceBackgroundColor) {
currentCompositeSurfaceBackgroundColor = newCompositeSurfaceBackgroundColor;
setFillColor(ColorStateList.valueOf(currentCompositeSurfaceBackgroundColor));
invalidate = true;
}

int newChipStrokeColor =
chipStrokeColor != null
? chipStrokeColor.getColorForState(chipState, currentChipStrokeColor)
Expand Down Expand Up @@ -1294,11 +1292,6 @@ private void updateCompatRippleColor() {
private void setChipSurfaceColor(@Nullable ColorStateList chipSurfaceColor) {
if (this.chipSurfaceColor != chipSurfaceColor) {
this.chipSurfaceColor = chipSurfaceColor;
if (isShapeThemingEnabled) {
if (chipSurfaceColor != null && chipBackgroundColor != null) {
setFillColor(compositeSurfaceBackgroundColor(chipBackgroundColor, chipSurfaceColor));
}
}
onStateChange(getState());
}
}
Expand Down Expand Up @@ -1356,21 +1349,10 @@ public void setChipBackgroundColorResource(@ColorRes int id) {
public void setChipBackgroundColor(@Nullable ColorStateList chipBackgroundColor) {
if (this.chipBackgroundColor != chipBackgroundColor) {
this.chipBackgroundColor = chipBackgroundColor;
if (isShapeThemingEnabled) {
if (chipSurfaceColor != null && chipBackgroundColor != null) {
setFillColor(compositeSurfaceBackgroundColor(chipBackgroundColor, chipSurfaceColor));
}
}
onStateChange(getState());
}
}

private ColorStateList compositeSurfaceBackgroundColor(
@NonNull ColorStateList backgroundColor, @NonNull ColorStateList surfaceColor) {
return MaterialColors.layer(
surfaceColor, currentChipSurfaceColor, backgroundColor, currentChipBackgroundColor, states);
}

/**
* Returns this chip's minimum height.
*
Expand Down
121 changes: 0 additions & 121 deletions lib/java/com/google/android/material/color/MaterialColors.java
Expand Up @@ -18,21 +18,15 @@
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;

import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import com.google.android.material.resources.MaterialAttributes;
import androidx.core.graphics.ColorUtils;
import android.util.StateSet;
import android.util.TypedValue;
import android.view.View;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
* A utility class for common color variants used in Material themes.
Expand Down Expand Up @@ -144,119 +138,4 @@ public static int layer(
public static int layer(@ColorInt int backgroundColor, @ColorInt int overlayColor) {
return ColorUtils.compositeColors(overlayColor, backgroundColor);
}

/**
* Calculates a color state list that represents the layering of the {@code overlayColor} on top
* of the {@code backgroundColor} for the given set of {@code states}. CAUTION: More specific
* states that have the same color value as a more generic state may be dropped, see example
* below:
* <p>states:
* <pre>
* {selected, enabled},
* {checked, enabled},
* {enabled},
* default
* </pre>
* <p>Overlay CSL:
* <pre>
* "" TRANSPARENT
* </pre>
* <p>Scenario 1
* <p>Background CSL:
* <pre>
* checked RED
* "" GREEN
* </pre>
*
* <p>Current result:
* <pre>
* enabled, checked RED
* enabled GREEN
* </pre>
*
* <p>Color for state {enabled, checked, selected} --> returns RED # correct
*
* <p>Result if iterating top down through CSL to composite each state color:
* <pre>
* enabled, selected GREEN
* enabled, checked RED
* enabled GREEN
* </pre>
*
* <p>Color for state {enabled, checked, selected} --> returns GREEN #incorrect
*
* <p>Scenario 2
* Background CSL:
* <pre>
* selected GREEN
* checked RED
* "" GREEN
* </pre>
* <p>Current result:
* <pre>
* enabled, checked RED
* enabled GREEN
* </pre>
* <p>Color for state {enabled, checked, selected} --> returns RED # incorrect
*
* <p>Result if iterating top down through CSL to composite each state color:
* <pre>
* enabled, selected GREEN
* enabled, checked RED
* enabled GREEN
* </pre>
* <p>Color for state {enabled, checked, selected} --> returns GREEN # correct
*/
public static ColorStateList layer(
ColorStateList backgroundColor,
@ColorInt int defaultBackgroundColor,
ColorStateList overlayColor,
@ColorInt int defaultOverlayColor,
int[][] states) {
List<Integer> uniqueColors = new ArrayList<>();
List<int[]> uniqueStateSet = new ArrayList<>();

// Iterates bottom to top, from least to most specific states.
for (int i = states.length - 1; i >= 0; i--) {
int[] curState = states[i];
int layeredStateColor =
MaterialColors.layer(
backgroundColor.getColorForState(curState, defaultBackgroundColor),
overlayColor.getColorForState(curState, defaultOverlayColor));

if (shouldAddColorForState(uniqueColors, layeredStateColor, uniqueStateSet, curState)) {
// Add to the front of the list in original CSL order.
uniqueColors.add(0, layeredStateColor);
uniqueStateSet.add(0, curState);
}
}

// Convert lists to arrays.
int numStates = uniqueColors.size();
int[] colors = new int[numStates];
int[][] colorStates = new int[numStates][];
for (int i = 0; i < numStates; i++) {
colors[i] = uniqueColors.get(i);
colorStates[i] = uniqueStateSet.get(i);
}
return new ColorStateList(colorStates, colors);
}

/**
* Returns whether the specified @{code color} should be added to a ColorStateList for the
* specified {@code state} or if the existing color set and state set already cover it.
*/
private static boolean shouldAddColorForState(
List<Integer> colorSet, @ColorInt int color, List<int[]> stateSet, @Nullable int[] state) {
new HashSet<Integer>(colorSet);
if (!colorSet.contains(color)) {
return true;
}
for (int[] stateSetItem : stateSet) {
if (StateSet.stateSetMatches(stateSetItem, state)) {
return (colorSet.get(stateSet.indexOf(stateSetItem)) != color);
}
}
return true;
}
}

This file was deleted.

This file was deleted.

0 comments on commit d60fb3f

Please sign in to comment.