Refresh opacity and statefulness on tint change

Also warns when LayerDrawable is created with an invalid child. This
is not guaranteed to fail, but it's usually a bad sign.

Bug: 33124798
Test: LayerDrawableTest, DrawableContainerTest
Change-Id: Ie3e4200b27a9814cee7f5711d7df9710db513953
This commit is contained in:
Alan Viverette
2017-04-04 13:31:59 +00:00
parent 36db127e47
commit ad7e748543
2 changed files with 44 additions and 14 deletions

View File

@@ -210,6 +210,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
/**
* Change the global fade duration when a new drawable is entering
* the scene.
*
* @param ms The amount of time to fade in milliseconds.
*/
public void setEnterFadeDuration(int ms) {
@@ -219,6 +220,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
/**
* Change the global fade duration when a new drawable is leaving
* the scene.
*
* @param ms The amount of time to fade in milliseconds.
*/
public void setExitFadeDuration(int ms) {
@@ -375,6 +377,13 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
@Override
public void invalidateDrawable(@NonNull Drawable who) {
// This may have been called as the result of a tint changing, in
// which case we may need to refresh the cached statefulness or
// opacity.
if (mDrawableContainerState != null) {
mDrawableContainerState.invalidateCache();
}
if (who == mCurrDrawable && getCallback() != null) {
getCallback().invalidateDrawable(this);
}
@@ -822,8 +831,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
mDrawables[pos] = dr;
mNumChildren++;
mChildrenChangingConfigurations |= dr.getChangingConfigurations();
mCheckedStateful = false;
mCheckedOpacity = false;
invalidateCache();
mConstantPadding = null;
mCheckedPadding = false;
@@ -833,6 +842,14 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
return pos;
}
/**
* Invalidates the cached opacity and statefulness.
*/
void invalidateCache() {
mCheckedOpacity = false;
mCheckedStateful = false;
}
final int getCapacity() {
return mDrawables.length;
}

View File

@@ -32,6 +32,7 @@ import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.LayoutDirection;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
@@ -66,6 +67,8 @@ import java.io.IOException;
* @attr ref android.R.styleable#LayerDrawableItem_id
*/
public class LayerDrawable extends Drawable implements Drawable.Callback {
private static final String LOG_TAG = "LayerDrawable";
/**
* Padding mode used to nest each layer inside the padding of the previous
* layer.
@@ -89,6 +92,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
*/
public static final int INSET_UNDEFINED = Integer.MIN_VALUE;
@NonNull
LayerState mLayerState;
private int[] mPaddingL;
@@ -170,13 +174,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
final LayerState state = mLayerState;
if (state == null) {
return;
}
// The density may have changed since the last update. This will
// apply scaling to any existing constant state properties.
final LayerState state = mLayerState;
final int density = Drawable.resolveDensity(r, 0);
state.setDensity(density);
@@ -202,10 +202,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
super.applyTheme(t);
final LayerState state = mLayerState;
if (state == null) {
return;
}
final int density = Drawable.resolveDensity(t.getResources(), 0);
state.setDensity(density);
@@ -403,7 +399,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public boolean canApplyTheme() {
return (mLayerState != null && mLayerState.canApplyTheme()) || super.canApplyTheme();
return mLayerState.canApplyTheme() || super.canApplyTheme();
}
/**
@@ -986,6 +982,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
if (mSuspendChildInvalidation) {
mChildRequestedInvalidation = true;
} else {
// This may have been called as the result of a tint changing, in
// which case we may need to refresh the cached statefulness or
// opacity.
mLayerState.invalidateCache();
invalidateSelf();
}
}
@@ -1836,15 +1837,24 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
final ConstantState cs = dr.getConstantState();
if (cs == null) {
clone = dr;
if (dr.getCallback() != null) {
// This drawable already has an owner.
Log.w(LOG_TAG, "Invalid drawable added to LayerDrawable! Drawable already "
+ "belongs to another owner but does not expose a constant state.",
new RuntimeException());
}
} else if (res != null) {
clone = cs.newDrawable(res);
} else {
clone = cs.newDrawable();
}
clone.setCallback(owner);
clone.setLayoutDirection(dr.getLayoutDirection());
clone.setBounds(dr.getBounds());
clone.setLevel(dr.getLevel());
// Set the callback last to prevent invalidation from
// propagating before the constant state has been set.
clone.setCallback(owner);
} else {
clone = null;
}
@@ -2121,7 +2131,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
return true;
}
public void invalidateCache() {
/**
* Invalidates the cached opacity and statefulness.
*/
void invalidateCache() {
mCheckedOpacity = false;
mCheckedStateful = false;
}