Skip to content

Commit

Permalink
[Internal] Merge DrawableUtils classes
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 466426273
  • Loading branch information
leticiarossi authored and dsn5ft committed Aug 10, 2022
1 parent 7d64767 commit 00dfeac
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
import androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback;
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.internal.DrawableUtils;
import com.google.android.material.drawable.DrawableUtils;
import com.google.android.material.internal.ThemeEnforcement;
import com.google.android.material.internal.ViewUtils;
import com.google.android.material.resources.MaterialResources;
Expand Down
142 changes: 142 additions & 0 deletions lib/java/com/google/android/material/drawable/DrawableUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@
import android.content.res.Resources.NotFoundException;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.Gravity;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand All @@ -41,6 +44,7 @@
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

Expand Down Expand Up @@ -135,4 +139,142 @@ public static void setRippleDrawableRadius(@Nullable RippleDrawable drawable, in
}
}
}

/**
* Wraps and mutates the passed in drawable so that it may be used for tinting if a tintList is
* present. Also applies the tintMode if present.
*/
@Nullable
public static Drawable createTintableDrawableIfNeeded(
@Nullable Drawable drawable, @Nullable ColorStateList tintList, @Nullable Mode tintMode) {
return createTintableMutatedDrawableIfNeeded(
drawable, tintList, tintMode, /* forceMutate= */ false);
}

/**
* Wraps and mutates the passed in drawable so that it may be used for tinting if a tintList is
* present. Also applies the tintMode if present. If there's not a tintList and the API level is <
* 21, it'll still mutate the drawable.
*
* <p>Use this method instead of the above if the passed in drawable will be a child of a {@link
* LayerDrawable} in APIs < 21, its tintList may be null, and it may be mutated, in order to
* prevent issue where the drawable may not have its constant state set up properly.
*/
@Nullable
public static Drawable createTintableMutatedDrawableIfNeeded(
@Nullable Drawable drawable, @Nullable ColorStateList tintList, @Nullable Mode tintMode) {
return createTintableMutatedDrawableIfNeeded(
drawable, tintList, tintMode, VERSION.SDK_INT < VERSION_CODES.LOLLIPOP);
}

@Nullable
private static Drawable createTintableMutatedDrawableIfNeeded(
@Nullable Drawable drawable,
@Nullable ColorStateList tintList,
@Nullable Mode tintMode,
boolean forceMutate) {
if (drawable == null) {
return null;
}
if (tintList != null) {
drawable = DrawableCompat.wrap(drawable).mutate();
if (tintMode != null) {
DrawableCompat.setTintMode(drawable, tintMode);
}
} else if (forceMutate) {
drawable.mutate();
}
return drawable;
}

/**
* Composites two drawables, returning a drawable instance of {@link LayerDrawable}, with the
* second on top of the first. If any of the drawables is null, this method will return the other.
*
* @param bottomLayerDrawable the drawable to be on the first layer (bottom)
* @param topLayerDrawable the drawable to be on the second layer (top)
*/
@Nullable
public static Drawable compositeTwoLayeredDrawable(
@Nullable Drawable bottomLayerDrawable, @Nullable Drawable topLayerDrawable) {
if (bottomLayerDrawable == null) {
return topLayerDrawable;
}
if (topLayerDrawable == null) {
return bottomLayerDrawable;
}
LayerDrawable drawable =
new LayerDrawable(new Drawable[] {bottomLayerDrawable, topLayerDrawable});
int topLayerNewWidth;
int topLayerNewHeight;
if (topLayerDrawable.getIntrinsicWidth() == -1 || topLayerDrawable.getIntrinsicHeight() == -1) {
// If there's no intrinsic width or height, keep bottom layer's size.
topLayerNewWidth = bottomLayerDrawable.getIntrinsicWidth();
topLayerNewHeight = bottomLayerDrawable.getIntrinsicHeight();
} else if (topLayerDrawable.getIntrinsicWidth() <= bottomLayerDrawable.getIntrinsicWidth()
&& topLayerDrawable.getIntrinsicHeight() <= bottomLayerDrawable.getIntrinsicHeight()) {
// If the top layer is smaller than the bottom layer in both its width and height, keep top
// layer's size.
topLayerNewWidth = topLayerDrawable.getIntrinsicWidth();
topLayerNewHeight = topLayerDrawable.getIntrinsicHeight();
} else {
float topLayerRatio =
(float) topLayerDrawable.getIntrinsicWidth() / topLayerDrawable.getIntrinsicHeight();
float bottomLayerRatio =
(float) bottomLayerDrawable.getIntrinsicWidth()
/ bottomLayerDrawable.getIntrinsicHeight();
if (topLayerRatio >= bottomLayerRatio) {
// If the top layer is wider in ratio than the bottom layer, shrink it according to its
// width.
topLayerNewWidth = bottomLayerDrawable.getIntrinsicWidth();
topLayerNewHeight = (int) (topLayerNewWidth / topLayerRatio);
} else {
// If the top layer is taller in ratio than the bottom layer, shrink it according to its
// height.
topLayerNewHeight = bottomLayerDrawable.getIntrinsicHeight();
topLayerNewWidth = (int) (topLayerRatio * topLayerNewHeight);
}
}
// Centers the top layer inside the bottom layer. Before M there's no layer gravity support, we
// need to use layer insets to adjust the top layer position manually.
if (VERSION.SDK_INT >= VERSION_CODES.M) {
drawable.setLayerSize(1, topLayerNewWidth, topLayerNewHeight);
drawable.setLayerGravity(1, Gravity.CENTER);
} else {
int horizontalInset = (bottomLayerDrawable.getIntrinsicWidth() - topLayerNewWidth) / 2;
int verticalInset = (bottomLayerDrawable.getIntrinsicHeight() - topLayerNewHeight) / 2;
drawable.setLayerInset(1, horizontalInset, verticalInset, horizontalInset, verticalInset);
}
return drawable;
}

/** Returns a new state that adds the checked state to the input state. */
@NonNull
public static int[] getCheckedState(@NonNull int[] state) {
for (int i = 0; i < state.length; i++) {
if (state[i] == android.R.attr.state_checked) {
return state;
} else if (state[i] == 0) {
int[] newState = state.clone();
newState[i] = android.R.attr.state_checked;
return newState;
}
}
int[] newState = Arrays.copyOf(state, state.length + 1);
newState[state.length] = android.R.attr.state_checked;
return newState;
}

/** Returns a new state that removes the checked state from the input state. */
@NonNull
public static int[] getUncheckedState(@NonNull int[] state) {
int[] newState = new int[state.length];
int i = 0;
for (int subState : state) {
if (subState != android.R.attr.state_checked) {
newState[i++] = subState;
}
}
return newState;
}
}
181 changes: 0 additions & 181 deletions lib/java/com/google/android/material/internal/DrawableUtils.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.DrawableCompat;
import com.google.android.material.internal.DrawableUtils;
import com.google.android.material.drawable.DrawableUtils;
import com.google.android.material.internal.ThemeEnforcement;
import com.google.android.material.internal.ViewUtils;

Expand Down

0 comments on commit 00dfeac

Please sign in to comment.