public static boolean containsNinePatch(Drawable drawable) { drawable = getWrapperDrawable(drawable); if (drawable instanceof NinePatchDrawable || drawable instanceof InsetDrawable || drawable instanceof LayerDrawable) { return true; } else if (drawable instanceof StateListDrawable) { final DrawableContainer.DrawableContainerState containerState = ((DrawableContainer.DrawableContainerState) drawable.getConstantState()); //can't getBaseApplication containState from drawable which is containing DrawableWrapperDonut //https://code.google.com/p/android/issues/detail?id=169920 if (containerState == null) { return true; } for (Drawable dr : containerState.getChildren()) { dr = getWrapperDrawable(dr); if (dr instanceof NinePatchDrawable || dr instanceof InsetDrawable || dr instanceof LayerDrawable) { return true; } } } return false; }
private static boolean setContainerConstantStateV9(DrawableContainer drawable, ConstantState constantState) { if (!sSetConstantStateMethodFetched) { try { sSetConstantStateMethod = DrawableContainer.class.getDeclaredMethod("setConstantState", new Class[]{DrawableContainerState.class}); sSetConstantStateMethod.setAccessible(true); } catch (NoSuchMethodException e) { Log.e(LOG_TAG, "Could not fetch setConstantState(). Oh well."); } sSetConstantStateMethodFetched = true; } if (sSetConstantStateMethod != null) { try { sSetConstantStateMethod.invoke(drawable, new Object[]{constantState}); return true; } catch (Exception e2) { Log.e(LOG_TAG, "Could not invoke setConstantState(). Oh well."); } } return false; }
private static boolean setContainerConstantStateV7(DrawableContainer drawable, ConstantState constantState) { if (!sDrawableContainerStateFieldFetched) { try { sDrawableContainerStateField = DrawableContainer.class.getDeclaredField("mDrawableContainerStateField"); sDrawableContainerStateField.setAccessible(true); } catch (NoSuchFieldException e) { Log.e(LOG_TAG, "Could not fetch mDrawableContainerStateField. Oh well."); } sDrawableContainerStateFieldFetched = true; } if (sDrawableContainerStateField != null) { try { sDrawableContainerStateField.set(drawable, constantState); return true; } catch (Exception e2) { Log.e(LOG_TAG, "Could not set mDrawableContainerStateField. Oh well."); } } return false; }
public static boolean containsNinePatch(Drawable drawable) { drawable = getWrapperDrawable(drawable); if (drawable instanceof NinePatchDrawable || drawable instanceof InsetDrawable || drawable instanceof LayerDrawable) { return true; } else if (drawable instanceof StateListDrawable) { final DrawableContainer.DrawableContainerState containerState = ((DrawableContainer.DrawableContainerState) drawable.getConstantState()); //can't get containState from drawable which is containing DrawableWrapperDonut //https://code.google.com/p/android/issues/detail?id=169920 if (containerState == null) { return true; } for (Drawable dr : containerState.getChildren()) { dr = getWrapperDrawable(dr); if (dr instanceof NinePatchDrawable || dr instanceof InsetDrawable || dr instanceof LayerDrawable) { return true; } } } return false; }
/** * Inflates the view and creates the ViewHolder * * @param parent Get the context from it * @param viewType Ignored * @return The created ViewHolder */ @Override public ButtonViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.multiplechoice_button, parent, false); // Clone drawable to allow modifications ToggleButton button = (ToggleButton) v.findViewById(R.id.toggleButton); StateListDrawable drawable = (StateListDrawable) button.getBackground(); drawable = (StateListDrawable) drawable.mutate(); button.setBackgroundDrawable(drawable.getConstantState().newDrawable()); drawable = (StateListDrawable) button.getBackground(); // Deep Clone (necessary for API Version 15 apparently) DrawableContainer.DrawableContainerState drawableContainerState = (DrawableContainer.DrawableContainerState) drawable.getConstantState(); for (int i = 0; i < drawableContainerState.getChildren().length; i++) { if (drawableContainerState.getChildren()[i] != null) { drawableContainerState.getChildren()[i] = drawableContainerState.getChildren()[i].getConstantState().newDrawable().mutate(); } } return new ButtonViewHolder(v); }
private static boolean shouldMutateBackground(Drawable drawable) { if (Build.VERSION.SDK_INT >= 16) { // For SDK 16+, we should be fine mutating the drawable return true; } if (drawable instanceof LayerDrawable) { return Build.VERSION.SDK_INT >= 16; } else if (drawable instanceof InsetDrawable) { return Build.VERSION.SDK_INT >= 14; } else if (drawable instanceof DrawableContainer) { // If we have a DrawableContainer, let's traverse it's child array final Drawable.ConstantState state = drawable.getConstantState(); if (state instanceof DrawableContainer.DrawableContainerState) { final DrawableContainer.DrawableContainerState containerState = (DrawableContainer.DrawableContainerState) state; for (Drawable child : containerState.getChildren()) { if (!shouldMutateBackground(child)) { return false; } } } } return true; }
public static Drawable wrapForTinting(Drawable drawable) { Object obj; label0: { if (!(drawable instanceof GradientDrawable)) { obj = drawable; if (!(drawable instanceof DrawableContainer)) { break label0; } } obj = new DrawableWrapperLollipop(drawable); } return ((Drawable) (obj)); }
/** * Check if two Drawables are equal. A regular check for a Drawable equals * just checks for the instance reference, while this check is doing a * deeper equals when dealing with {@link DrawableContainer} instances. In * these cases, the method will run equals on each of the child drawables in * the container (order is importance as well). * * @param d1 * @param d2 * @return <code>true</code> if the drawables are equal, <code>false</code> * otherwise. */ public static boolean isEquals(Drawable d1, Drawable d2) { if (d1 == d2) { return true; } if (d1 == null || d2 == null) { return false; } if (d1 instanceof DrawableContainer && d2 instanceof DrawableContainer) { // Try to match the content of those containers DrawableContainerState containerState1 = (DrawableContainerState) ((DrawableContainer) d1) .getConstantState(); DrawableContainerState containerState2 = (DrawableContainerState) ((DrawableContainer) d2) .getConstantState(); return Arrays.equals(containerState1.getChildren(), containerState2.getChildren()); } return d1.equals(d2); }
/** * Some drawable implementations have problems with mutation. This method returns false if * there is a known issue in the given drawable's implementation. */ public static boolean canSafelyMutateDrawable(@NonNull Drawable drawable) { if (Build.VERSION.SDK_INT < 15 && drawable instanceof InsetDrawable) { return false; } else if (Build.VERSION.SDK_INT < 15 && drawable instanceof GradientDrawable) { // GradientDrawable has a bug pre-ICS which results in mutate() resulting // in loss of color return false; } else if (Build.VERSION.SDK_INT < 17 && drawable instanceof LayerDrawable) { return false; } if (drawable instanceof DrawableContainer) { // If we have a DrawableContainer, let's traverse its child array final Drawable.ConstantState state = drawable.getConstantState(); if (state instanceof DrawableContainer.DrawableContainerState) { final DrawableContainer.DrawableContainerState containerState = (DrawableContainer.DrawableContainerState) state; for (final Drawable child : containerState.getChildren()) { if (!canSafelyMutateDrawable(child)) { return false; } } } } else if (drawable instanceof android.support.v4.graphics.drawable.DrawableWrapper) { return canSafelyMutateDrawable( ((android.support.v4.graphics.drawable.DrawableWrapper) drawable) .getWrappedDrawable()); } /*else if (drawable instanceof android.support.v7.graphics.drawable.DrawableWrapper) { return canSafelyMutateDrawable( ((android.support.v7.graphics.drawable.DrawableWrapper) drawable) .getWrappedDrawable()); }*/ else if (drawable instanceof ScaleDrawable) { return canSafelyMutateDrawable(((ScaleDrawable) drawable).getDrawable()); } return true; }
private void ensureBackgroundDrawableStateWorkaround() { final int sdk = Build.VERSION.SDK_INT; if (sdk != 21 && sdk != 22) { // The workaround is only required on API 21-22 return; } final Drawable bg = mEditText.getBackground(); if (bg == null) { return; } if (!mHasReconstructedEditTextBackground) { // This is gross. There is an issue in the platform which affects container Drawables // where the first drawable retrieved from resources will propagate any changes // (like color filter) to all instances from the cache. We'll try to workaround it... final Drawable newBg = bg.getConstantState().newDrawable(); if (bg instanceof DrawableContainer) { // If we have a Drawable container, we can try and set it's constant state via // reflection from the new Drawable mHasReconstructedEditTextBackground = com.commonsware.cwac.crossport.design.widget.DrawableUtils.setContainerConstantState( (DrawableContainer) bg, newBg.getConstantState()); } if (!mHasReconstructedEditTextBackground) { // If we reach here then we just need to set a brand new instance of the Drawable // as the background. This has the unfortunate side-effect of wiping out any // user set padding, but I'd hope that use of custom padding on an EditText // is limited. ViewCompat.setBackground(mEditText, newBg); mHasReconstructedEditTextBackground = true; } } }
protected boolean isCompatTintEnabled() { if (VERSION.SDK_INT != 21) { return false; } Drawable drawable = this.mDrawable; if ((drawable instanceof GradientDrawable) || (drawable instanceof DrawableContainer) || (drawable instanceof InsetDrawable)) { return true; } return false; }
private void ensureBackgroundDrawableStateWorkaround() { Drawable bg = this.mEditText.getBackground(); if (bg != null && !this.mHasReconstructedEditTextBackground) { Drawable newBg = bg.getConstantState().newDrawable(); if (bg instanceof DrawableContainer) { this.mHasReconstructedEditTextBackground = DrawableUtils.setContainerConstantState((DrawableContainer) bg, newBg.getConstantState()); } if (!this.mHasReconstructedEditTextBackground) { this.mEditText.setBackgroundDrawable(newBg); this.mHasReconstructedEditTextBackground = true; } } }
/** * Some drawable implementations have problems with mutation. This method returns false if * there is a known issue in the given drawable's implementation. */ public static boolean canSafelyMutateDrawable(@NonNull Drawable drawable) { if (Build.VERSION.SDK_INT < 15 && drawable instanceof InsetDrawable) { return false; } else if (Build.VERSION.SDK_INT < 15 && drawable instanceof GradientDrawable) { // GradientDrawable has a bug pre-ICS which results in mutate() resulting // in loss of color return false; } else if (Build.VERSION.SDK_INT < 17 && drawable instanceof LayerDrawable) { return false; } if (drawable instanceof DrawableContainer) { // If we have a DrawableContainer, let's traverse it's child array final Drawable.ConstantState state = drawable.getConstantState(); if (state instanceof DrawableContainer.DrawableContainerState) { final DrawableContainer.DrawableContainerState containerState = (DrawableContainer.DrawableContainerState) state; for (final Drawable child : containerState.getChildren()) { if (!canSafelyMutateDrawable(child)) { return false; } } } } else if (drawable instanceof android.support.v4.graphics.drawable.DrawableWrapper) { return canSafelyMutateDrawable( ((android.support.v4.graphics.drawable.DrawableWrapper) drawable) .getWrappedDrawable()); } else if (drawable instanceof android.support.v7.graphics.drawable.DrawableWrapper) { return canSafelyMutateDrawable( ((android.support.v7.graphics.drawable.DrawableWrapper) drawable) .getWrappedDrawable()); } else if (drawable instanceof ScaleDrawable) { return canSafelyMutateDrawable(((ScaleDrawable) drawable).getDrawable()); } return true; }
public static boolean m2634b(Drawable drawable) { if (drawable instanceof LayerDrawable) { return VERSION.SDK_INT >= 16; } else if (drawable instanceof InsetDrawable) { return VERSION.SDK_INT >= 14; } else { if (drawable instanceof StateListDrawable) { return VERSION.SDK_INT >= 8; } else { if (drawable instanceof GradientDrawable) { return VERSION.SDK_INT >= 14; } else { if (!(drawable instanceof DrawableContainer)) { return drawable instanceof C0063q ? m2634b(((C0063q) drawable).m469a()) : drawable instanceof C0244a ? m2634b(((C0244a) drawable).m1984a()) : drawable instanceof ScaleDrawable ? m2634b(((ScaleDrawable) drawable).getDrawable()) : true; } else { ConstantState constantState = drawable.getConstantState(); if (!(constantState instanceof DrawableContainerState)) { return true; } for (Drawable b : ((DrawableContainerState) constantState).getChildren()) { if (!m2634b(b)) { return false; } } return true; } } } } }
protected boolean m487c() { if (VERSION.SDK_INT != 21) { return false; } Drawable drawable = this.c; return (drawable instanceof GradientDrawable) || (drawable instanceof DrawableContainer) || (drawable instanceof InsetDrawable); }
@Override protected boolean isCompatTintEnabled() { if (Build.VERSION.SDK_INT == 21) { final Drawable drawable = mDrawable; return drawable instanceof GradientDrawable || drawable instanceof DrawableContainer || drawable instanceof InsetDrawable; } return false; }
static boolean setContainerConstantState(DrawableContainer drawable, Drawable.ConstantState constantState) { if (Build.VERSION.SDK_INT >= 9) { // We can use getDeclaredMethod() on v9+ return setContainerConstantStateV9(drawable, constantState); } else { // Else we'll just have to set the field directly return setContainerConstantStateV7(drawable, constantState); } }
private void ensureBackgroundDrawableStateWorkaround() { final Drawable bg = mEditText.getBackground(); if (bg == null) { return; } if (!mHasReconstructedEditTextBackground) { // This is gross. There is an issue in the platform which affects container Drawables // where the first drawable retrieved from resources will propogate any changes // (like color filter) to all instances from the cache. We'll try to workaround it... final Drawable newBg = bg.getConstantState().newDrawable(); if (bg instanceof DrawableContainer) { // If we have a Drawable container, we can try and set it's constant state via // reflection from the new Drawable mHasReconstructedEditTextBackground = DrawableUtils.setContainerConstantState( (DrawableContainer) bg, newBg.getConstantState()); } if (!mHasReconstructedEditTextBackground) { // If we reach here then we just need to set a brand new instance of the Drawable // as the background. This has the unfortunate side-effect of wiping out any // user set padding, but I'd hope that use of custom padding on an EditText // is limited. mEditText.setBackgroundDrawable(newBg); mHasReconstructedEditTextBackground = true; } } }
/** * Some drawable implementations have problems with mutation. This method returns false if * there is a known issue in the given drawable's implementation. */ static boolean canSafelyMutateDrawable(@NonNull Drawable drawable) { if (drawable instanceof LayerDrawable) { return Build.VERSION.SDK_INT >= 16; } else if (drawable instanceof InsetDrawable) { return Build.VERSION.SDK_INT >= 14; } else if (drawable instanceof StateListDrawable) { // StateListDrawable has a bug in mutate() on API 7 return Build.VERSION.SDK_INT >= 8; } else if (drawable instanceof GradientDrawable) { // GradientDrawable has a bug pre-ICS which results in mutate() resulting // in loss of color return Build.VERSION.SDK_INT >= 14; } else if (drawable instanceof DrawableContainer) { // If we have a DrawableContainer, let's traverse it's child array final Drawable.ConstantState state = drawable.getConstantState(); if (state instanceof DrawableContainer.DrawableContainerState) { final DrawableContainer.DrawableContainerState containerState = (DrawableContainer.DrawableContainerState) state; for (Drawable child : containerState.getChildren()) { if (!canSafelyMutateDrawable(child)) { return false; } } } } else if (drawable instanceof android.support.v4ox.graphics.drawable.DrawableWrapper) { return canSafelyMutateDrawable( ((android.support.v4ox.graphics.drawable.DrawableWrapper) drawable) .getWrappedDrawable()); } else if (drawable instanceof android.support.v7ox.graphics.drawable.DrawableWrapper) { return canSafelyMutateDrawable( ((android.support.v7ox.graphics.drawable.DrawableWrapper) drawable) .getWrappedDrawable()); } return true; }
private void ensureBackgroundDrawableStateWorkaround() { final int sdk = Build.VERSION.SDK_INT; if (sdk != 21 && sdk != 22) { // The workaround is only required on API 21-22 return; } final Drawable bg = editText.getBackground(); if (bg == null) { return; } if (!hasReconstructedEditTextBackground) { // This is gross. There is an issue in the platform which affects container Drawables // where the first drawable retrieved from resources will propagate any changes // (like color filter) to all instances from the cache. We'll try to workaround it... final Drawable newBg = bg.getConstantState().newDrawable(); if (bg instanceof DrawableContainer) { // If we have a Drawable container, we can try and set it's constant state via // reflection from the new Drawable hasReconstructedEditTextBackground = DrawableUtils.setContainerConstantState( (DrawableContainer) bg, newBg.getConstantState()); } if (!hasReconstructedEditTextBackground) { // If we reach here then we just need to set a brand new instance of the Drawable // as the background. This has the unfortunate side-effect of wiping out any // user set padding, but I'd hope that use of custom padding on an EditText // is limited. ViewCompat.setBackground(editText, newBg); hasReconstructedEditTextBackground = true; } } }
private void ensureBackgroundDrawableStateWorkaround() { final int sdk = Build.VERSION.SDK_INT; if (sdk != 21 && sdk != 22) { // The workaround is only required on API 21-22 return; } final Drawable bg = editText.getBackground(); if (bg == null) { return; } if (!hasReconstructedEditTextBackground) { // This is gross. There is an issue in the platform which affects container Drawables // where the first drawable retrieved from resources will propagate any changes // (like color filter) to all instances from the cache. We'll try to work around it... final Drawable newBg = bg.getConstantState().newDrawable(); if (bg instanceof DrawableContainer) { // If we have a Drawable container, we can try and set its constant state via // reflection from the new Drawable hasReconstructedEditTextBackground = DrawableUtils.setContainerConstantState( (DrawableContainer) bg, newBg.getConstantState()); } if (!hasReconstructedEditTextBackground) { // If we reach here then we just need to set a brand new instance of the Drawable // as the background. This has the unfortunate side-effect of wiping out any // user set padding, but I'd hope that use of custom padding on an EditText // is limited. ViewCompat.setBackground(editText, newBg); hasReconstructedEditTextBackground = true; // Re-apply box background mode to set the EditText's box padding if in box mode. onApplyBoxBackgroundMode(); } } }
private static Bitmap getBitmapFromDrawable(Drawable drawable) { if (drawable == null) { return null; } if (drawable instanceof DrawableContainer) { return getBitmapFromDrawable(drawable.getCurrent()); } else if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } else { return null; } }
private static boolean shouldMutateBackground(Drawable paramDrawable) { if (Build.VERSION.SDK_INT >= 16) {} for (;;) { return true; if ((paramDrawable instanceof LayerDrawable)) { if (Build.VERSION.SDK_INT < 16) { return false; } } else if ((paramDrawable instanceof InsetDrawable)) { if (Build.VERSION.SDK_INT < 14) { return false; } } else if ((paramDrawable instanceof DrawableContainer)) { Drawable.ConstantState localConstantState = paramDrawable.getConstantState(); if ((localConstantState instanceof DrawableContainer.DrawableContainerState)) { Drawable[] arrayOfDrawable = ((DrawableContainer.DrawableContainerState)localConstantState).getChildren(); int i = arrayOfDrawable.length; for (int j = 0; j < i; j++) { if (!shouldMutateBackground(arrayOfDrawable[j])) { return false; } } } } } }
public Drawable wrap(Drawable paramDrawable) { if (((paramDrawable instanceof GradientDrawable)) || ((paramDrawable instanceof DrawableContainer))) { paramDrawable = new DrawableWrapperLollipop(paramDrawable); } return paramDrawable; }
public Drawable c(Drawable paramDrawable) { if (((paramDrawable instanceof GradientDrawable)) || ((paramDrawable instanceof DrawableContainer))) { paramDrawable = new gx(paramDrawable); } return paramDrawable; }
private static void forceStateChangeOnChildrenCompat(Drawable drawable) { Drawable.ConstantState drawableState = drawable.getConstantState(); if (drawableState instanceof DrawableContainer.DrawableContainerState) { DrawableContainer.DrawableContainerState drawableContainerState = (DrawableContainer.DrawableContainerState) drawableState; Drawable[] children = drawableContainerState.getChildren(); if (children != null) { for (Drawable child : children) { forceStateChange(child, true); } } } }
@TargetApi(Build.VERSION_CODES.KITKAT) private static void forceStateChangeOnChildren(Drawable drawable) { Drawable.ConstantState drawableState = drawable.getConstantState(); if (drawableState instanceof DrawableContainer.DrawableContainerState) { DrawableContainer.DrawableContainerState drawableContainerState = (DrawableContainer.DrawableContainerState) drawableState; for (int i = 0; i < drawableContainerState.getChildCount(); i++) { Drawable child = drawableContainerState.getChild(i); forceStateChange(child, true); } } }
public ClassDescStateListDrawable(ClassDescDrawableMgr classMgr, ClassDescElementDrawableContainer parent) { super(classMgr, "selector", parent); this.methodGetStateListState = new MethodContainer<DrawableContainer.DrawableContainerState>(StateListDrawable.class,"getStateListState"); this.methodGetStateListStateIsConstantSize = new MethodContainer<Void>(DrawableContainer.class.getName() + "$DrawableContainerState","setConstantSize",boolean.class); }
@SuppressWarnings("unchecked") protected void init() { super.init(); // https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html // https://developer.android.com/guide/topics/resources/animation-resource.html // https://developer.android.com/guide/topics/graphics/drawable-animation.html addAttrDescAN(new AttrDescReflecMethodBoolean(this, "oneshot", "setOneShot", false)); addAttrDescAN(new AttrDescReflecFieldMethodBoolean(this, "variablePadding", "mAnimationState", MiscUtil.resolveClass(DrawableContainer.class.getName() + "$DrawableContainerState"), "setVariablePadding", false)); // está arriba: addAttrDescAN(new AttrDescDrawable_Drawable_visible<AnimationDrawable>(this)); }
public static void assertEquals(AnimationDrawable a,AnimationDrawable b) { assertEqualsDrawableContainer(a, b); // android:oneshot assertEquals(a.isOneShot(), b.isOneShot()); // android:visible assertEquals(a.isVisible(), b.isVisible()); Drawable.ConstantState a_state = a.getConstantState(); Drawable.ConstantState b_state = b.getConstantState(); // android:variablePadding Class classDrawableContainerState = TestUtil.resolveClass(DrawableContainer.class.getName() + "$DrawableContainerState"); assertEquals(TestUtil.getField(a_state, classDrawableContainerState, "mVariablePadding"), TestUtil.getField(b_state, classDrawableContainerState, "mVariablePadding")); // <item> // android:drawable (o child element drawable) se testea en assertEqualsDrawableContainer // android:duration Class classState = TestUtil.resolveClass(AnimationDrawable.class.getName() + "$AnimationState"); int[] a_durations = (int[])TestUtil.getField(a_state, classState, "mDurations"); int[] b_durations = (int[])TestUtil.getField(b_state, classState, "mDurations"); assertEquals(a_durations,b_durations); }
private static void assertEqualsDrawableContainer(DrawableContainer a,DrawableContainer b) { assertEqualsDrawable(a, b); Drawable.ConstantState a_state = a.getConstantState(); Drawable.ConstantState b_state = b.getConstantState(); // <item> // android:drawable (o child element drawable) Class classState = TestUtil.resolveClass(DrawableContainer.class.getName() + "$DrawableContainerState"); Drawable[] a_drawables = (Drawable[])TestUtil.getField(a_state, classState, "mDrawables"); Drawable[] b_drawables = (Drawable[])TestUtil.getField(b_state, classState, "mDrawables"); assertEquals(a_drawables.length,b_drawables.length); for(int i = 0; i < a_drawables.length; i++) { // No se porqué a veces no coinciden en número de imágenes en a (el compilado) hay más que en b, al menos chequeamos que los comunes coinciden (los índices con data en b deben coincidir con el dato en a) if (a_drawables[i] != null && b_drawables[i] != null) assertEquals(a_drawables[i], b_drawables[i]); /* Falla curiosamente cuando se testea dos veces, el compilado CAMBIA if (b_drawables[i] != null && a_drawables[i] == null) // Si b (dinámico) está definido DEBE estarlo a (compilado) assertTrue(false); */ } }
private void ensureBackgroundDrawableStateWorkaround() { final int sdk = Build.VERSION.SDK_INT; if (sdk != 21 && sdk != 22) { // The workaround is only required on API 21-22 return; } final Drawable bg = mEditText.getBackground(); if (bg == null) { return; } if (!mHasReconstructedEditTextBackground) { // This is gross. There is an issue in the platform which affects container Drawables // where the first drawable retrieved from resources will propagate any changes // (like color filter) to all instances from the cache. We'll try to workaround it... final Drawable newBg = bg.getConstantState().newDrawable(); if (bg instanceof DrawableContainer) { // If we have a Drawable container, we can try and set it's constant state via // reflection from the new Drawable mHasReconstructedEditTextBackground = DrawableUtils.setContainerConstantState( (DrawableContainer) bg, newBg.getConstantState()); } if (!mHasReconstructedEditTextBackground) { // If we reach here then we just need to set a brand new instance of the Drawable // as the background. This has the unfortunate side-effect of wiping out any // user set padding, but I'd hope that use of custom padding on an EditText // is limited. ViewCompat.setBackground(mEditText, newBg); mHasReconstructedEditTextBackground = true; } } }
static boolean setContainerConstantState(DrawableContainer drawable, Drawable.ConstantState constantState) { // We can use getDeclaredMethod() on v9+ return setContainerConstantStateV9(drawable, constantState); }
static boolean canSafelyMutateDrawable(@NonNull Drawable drawable) { if (drawable instanceof LayerDrawable) { if (VERSION.SDK_INT >= 16) { return true; } return false; } else if (drawable instanceof InsetDrawable) { if (VERSION.SDK_INT < 14) { return false; } return true; } else if (drawable instanceof StateListDrawable) { if (VERSION.SDK_INT < 8) { return false; } return true; } else if (drawable instanceof GradientDrawable) { if (VERSION.SDK_INT < 14) { return false; } return true; } else if (drawable instanceof DrawableContainer) { ConstantState state = drawable.getConstantState(); if (!(state instanceof DrawableContainerState)) { return true; } for (Drawable child : ((DrawableContainerState) state).getChildren()) { if (!canSafelyMutateDrawable(child)) { return false; } } return true; } else if (drawable instanceof DrawableWrapper) { return canSafelyMutateDrawable(((DrawableWrapper) drawable).getWrappedDrawable()); } else { if (drawable instanceof android.support.v7.graphics.drawable.DrawableWrapper) { return canSafelyMutateDrawable(((android.support.v7.graphics.drawable.DrawableWrapper) drawable).getWrappedDrawable()); } return true; } }
static boolean setContainerConstantState(DrawableContainer drawable, ConstantState constantState) { if (VERSION.SDK_INT >= 9) { return setContainerConstantStateV9(drawable, constantState); } return setContainerConstantStateV7(drawable, constantState); }
public void initialize(Context context, AttributeSet attrs) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { this.setBackground(getResources().getDrawable(R.drawable.toggle_background, null)); } else { this.setBackground(getResources().getDrawable(R.drawable.toggle_background)); } StateListDrawable stateListDrawable = (StateListDrawable) this.getBackground(); DrawableContainer.DrawableContainerState dcs = (DrawableContainer.DrawableContainerState) stateListDrawable.getConstantState(); Drawable[] drawableItems = dcs.getChildren(); GradientDrawable unChecked = (GradientDrawable) drawableItems[0]; GradientDrawable checked = (GradientDrawable) drawableItems[1]; TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomToggleButton); // getting all the attributes values set from the typed array i.e from user int toggleOnColor = typedArray.getColor(R.styleable.CustomToggleButton_checkedColor, Color.parseColor("#FF4081")); int toggleOffColor = typedArray.getColor(R.styleable.CustomToggleButton_uncheckedColor, Color.parseColor("#FF4081")); float borderWidth = typedArray.getDimension(R.styleable.CustomToggleButton_borderWidth, 4.0f); float radius = typedArray.getDimension(R.styleable.CustomToggleButton_radius, 15.0f); int checkedTextColor = typedArray.getColor(R.styleable.CustomToggleButton_checkedTextColor, getResources().getColor(R.color.CheckedTextColor)); int uncheckedTextColor = typedArray.getColor(R.styleable.CustomToggleButton_uncheckedTextColor, getResources().getColor(R.color.uncheckedTextColor)); Log.d(TAG, "initialize: " + borderWidth); ColorStateList colorStateList = new ColorStateList( new int[][]{ new int[]{android.R.attr.state_checked}, new int[]{-android.R.attr.state_checked} }, new int[]{ checkedTextColor, uncheckedTextColor } ); this.setTextColor(colorStateList); checked.setStroke(Math.round(borderWidth), toggleOnColor); checked.setColor(toggleOnColor); checked.setCornerRadius(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, radius, getResources().getDisplayMetrics())); unChecked.setStroke(Math.round(borderWidth), toggleOffColor); unChecked.setCornerRadius(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, radius, getResources().getDisplayMetrics())); }
@Override protected void onDraw(Canvas canvas) { float factor; if (mProgress == 0 || mProgress == 1) { factor = 1; } else { long elapsed = System.currentTimeMillis() - mProgressSetTime; if (elapsed < 0) { factor = 0; } else if (elapsed > mSmoothAnimDuration) { factor = 1; } else { factor = elapsed / (float) mSmoothAnimDuration; } } mSmoothProgress = mStartProgress + factor * (mProgress - mStartProgress); // Draw background if (null != mDrbBackground) { mDrbBackground.draw(canvas); } // Draw progress if (null != mDrbProgress) { if (mDrbProgress instanceof NinePatchDrawable || (mDrbProgress instanceof DrawableContainer && ((DrawableContainer) mDrbProgress).getCurrent() instanceof NinePatchDrawable)) { if (mSmoothProgress == 0) { mDrbProgress.setBounds(0, 0, 0, 0); } else { mDrbProgress.setBounds(0, mRawProgressBounds.top, (int) (mRawProgressBounds.left + (mRawProgressBounds.width() - mProgressDrbMinWidth) * mSmoothProgress) + mProgressDrbMinWidth, mRawProgressBounds.bottom); } } mDrbProgress.draw(canvas); } // Draw progress text if (mProgressTextVisible) { mSb.delete(0, mSb.length()); if (StringUtils.isEmpty(mText)) { mSb.append((int) (mSmoothProgress * 100)); mSb.append('%'); } else { mSb.append(mText); } String text = mSb.toString(); mTextPaint.setAntiAlias(true); mTextPaint.setColor(mProgressTextColor); mTextPaint.setTextSize(mProgressTextSize); mTextPaint.setTypeface(mTypeface); mTextPaint.setTextAlign(Align.CENTER); FontMetrics fm = mTextPaint.getFontMetrics(); int fontH = (int) (Math.abs(fm.descent - fm.ascent)); canvas.drawText(text, getWidth() >> 1, ((getHeight() - getPaddingTop() - getPaddingBottom()) >> 1) + (fontH >> 1), mTextPaint); } if (factor != 1) { invalidate(); } notifyProgressChange(mSmoothProgress, mProgress); }