Merge "Ensure calling mutate() on DrawableContainer creates a new state" into lmp-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
10e2700d50
@@ -527,14 +527,18 @@ public class AnimatedStateListDrawable extends StateListDrawable {
|
|||||||
@Override
|
@Override
|
||||||
public Drawable mutate() {
|
public Drawable mutate() {
|
||||||
if (!mMutated && super.mutate() == this) {
|
if (!mMutated && super.mutate() == this) {
|
||||||
final AnimatedStateListState newState = new AnimatedStateListState(mState, this, null);
|
mState.mutate();
|
||||||
setConstantState(newState);
|
|
||||||
mMutated = true;
|
mMutated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
AnimatedStateListState cloneConstantState() {
|
||||||
|
return new AnimatedStateListState(mState, this, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -553,23 +557,29 @@ public class AnimatedStateListDrawable extends StateListDrawable {
|
|||||||
|
|
||||||
int[] mAnimThemeAttrs;
|
int[] mAnimThemeAttrs;
|
||||||
|
|
||||||
final LongSparseLongArray mTransitions;
|
LongSparseLongArray mTransitions;
|
||||||
final SparseIntArray mStateIds;
|
SparseIntArray mStateIds;
|
||||||
|
|
||||||
AnimatedStateListState(@Nullable AnimatedStateListState orig,
|
AnimatedStateListState(@Nullable AnimatedStateListState orig,
|
||||||
@NonNull AnimatedStateListDrawable owner, @Nullable Resources res) {
|
@NonNull AnimatedStateListDrawable owner, @Nullable Resources res) {
|
||||||
super(orig, owner, res);
|
super(orig, owner, res);
|
||||||
|
|
||||||
if (orig != null) {
|
if (orig != null) {
|
||||||
|
// Perform a shallow copy and rely on mutate() to deep-copy.
|
||||||
mAnimThemeAttrs = orig.mAnimThemeAttrs;
|
mAnimThemeAttrs = orig.mAnimThemeAttrs;
|
||||||
mTransitions = orig.mTransitions.clone();
|
mTransitions = orig.mTransitions;
|
||||||
mStateIds = orig.mStateIds.clone();
|
mStateIds = orig.mStateIds;
|
||||||
} else {
|
} else {
|
||||||
mTransitions = new LongSparseLongArray();
|
mTransitions = new LongSparseLongArray();
|
||||||
mStateIds = new SparseIntArray();
|
mStateIds = new SparseIntArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mutate() {
|
||||||
|
mTransitions = mTransitions.clone();
|
||||||
|
mStateIds = mStateIds.clone();
|
||||||
|
}
|
||||||
|
|
||||||
int addTransition(int fromId, int toId, @NonNull Drawable anim, boolean reversible) {
|
int addTransition(int fromId, int toId, @NonNull Drawable anim, boolean reversible) {
|
||||||
final int pos = super.addChild(anim);
|
final int pos = super.addChild(anim);
|
||||||
final long keyFromTo = generateTransitionKey(fromId, toId);
|
final long keyFromTo = generateTransitionKey(fromId, toId);
|
||||||
@@ -641,15 +651,18 @@ public class AnimatedStateListDrawable extends StateListDrawable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setConstantState(@NonNull AnimatedStateListState state) {
|
protected void setConstantState(@NonNull DrawableContainerState state) {
|
||||||
super.setConstantState(state);
|
super.setConstantState(state);
|
||||||
|
|
||||||
mState = state;
|
if (state instanceof AnimatedStateListState) {
|
||||||
|
mState = (AnimatedStateListState) state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AnimatedStateListDrawable(@Nullable AnimatedStateListState state, @Nullable Resources res) {
|
private AnimatedStateListDrawable(@Nullable AnimatedStateListState state, @Nullable Resources res) {
|
||||||
super(null);
|
super(null);
|
||||||
|
|
||||||
|
// Every animated state list drawable has its own constant state.
|
||||||
final AnimatedStateListState newState = new AnimatedStateListState(state, this, res);
|
final AnimatedStateListState newState = new AnimatedStateListState(state, this, res);
|
||||||
setConstantState(newState);
|
setConstantState(newState);
|
||||||
onStateChange(getState());
|
onStateChange(getState());
|
||||||
|
|||||||
@@ -342,12 +342,17 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
|
|||||||
@Override
|
@Override
|
||||||
public Drawable mutate() {
|
public Drawable mutate() {
|
||||||
if (!mMutated && super.mutate() == this) {
|
if (!mMutated && super.mutate() == this) {
|
||||||
mAnimationState.mDurations = mAnimationState.mDurations.clone();
|
mAnimationState.mutate();
|
||||||
mMutated = true;
|
mMutated = true;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
AnimationState cloneConstantState() {
|
||||||
|
return new AnimationState(mAnimationState, this, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -373,6 +378,10 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mutate() {
|
||||||
|
mDurations = mDurations.clone();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Drawable newDrawable() {
|
public Drawable newDrawable() {
|
||||||
return new AnimationDrawable(this, null);
|
return new AnimationDrawable(this, null);
|
||||||
|
|||||||
@@ -536,7 +536,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (schedule && animating) {
|
if (schedule && animating) {
|
||||||
scheduleSelf(mAnimationRunnable, now + 1000/60);
|
scheduleSelf(mAnimationRunnable, now + 1000 / 60);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,12 +567,23 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
|
|||||||
@Override
|
@Override
|
||||||
public Drawable mutate() {
|
public Drawable mutate() {
|
||||||
if (!mMutated && super.mutate() == this) {
|
if (!mMutated && super.mutate() == this) {
|
||||||
|
mDrawableContainerState = cloneConstantState();
|
||||||
mDrawableContainerState.mutate();
|
mDrawableContainerState.mutate();
|
||||||
mMutated = true;
|
mMutated = true;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a shallow copy of the container's constant state to be used as
|
||||||
|
* the base state for {@link #mutate()}.
|
||||||
|
*
|
||||||
|
* @return a shallow copy of the constant state
|
||||||
|
*/
|
||||||
|
DrawableContainerState cloneConstantState() {
|
||||||
|
return mDrawableContainerState;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -833,7 +844,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final void mutate() {
|
private void mutate() {
|
||||||
// No need to call createAllFutures, since future drawables will
|
// No need to call createAllFutures, since future drawables will
|
||||||
// mutate when they are prepared.
|
// mutate when they are prepared.
|
||||||
final int N = mNumChildren;
|
final int N = mNumChildren;
|
||||||
|
|||||||
@@ -146,13 +146,17 @@ public class LevelListDrawable extends DrawableContainer {
|
|||||||
@Override
|
@Override
|
||||||
public Drawable mutate() {
|
public Drawable mutate() {
|
||||||
if (!mMutated && super.mutate() == this) {
|
if (!mMutated && super.mutate() == this) {
|
||||||
mLevelListState.mLows = mLevelListState.mLows.clone();
|
mLevelListState.mutate();
|
||||||
mLevelListState.mHighs = mLevelListState.mHighs.clone();
|
|
||||||
mMutated = true;
|
mMutated = true;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
LevelListState cloneConstantState() {
|
||||||
|
return new LevelListState(mLevelListState, this, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -169,6 +173,7 @@ public class LevelListDrawable extends DrawableContainer {
|
|||||||
super(orig, owner, res);
|
super(orig, owner, res);
|
||||||
|
|
||||||
if (orig != null) {
|
if (orig != null) {
|
||||||
|
// Perform a shallow copy and rely on mutate() to deep-copy.
|
||||||
mLows = orig.mLows;
|
mLows = orig.mLows;
|
||||||
mHighs = orig.mHighs;
|
mHighs = orig.mHighs;
|
||||||
} else {
|
} else {
|
||||||
@@ -177,6 +182,11 @@ public class LevelListDrawable extends DrawableContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mutate() {
|
||||||
|
mLows = mLows.clone();
|
||||||
|
mHighs = mHighs.clone();
|
||||||
|
}
|
||||||
|
|
||||||
public void addLevel(int low, int high, Drawable drawable) {
|
public void addLevel(int low, int high, Drawable drawable) {
|
||||||
int pos = addChild(drawable);
|
int pos = addChild(drawable);
|
||||||
mLows[pos] = low;
|
mLows[pos] = low;
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import org.xmlpull.v1.XmlPullParserException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.content.res.Resources.Theme;
|
import android.content.res.Resources.Theme;
|
||||||
@@ -288,20 +290,17 @@ public class StateListDrawable extends DrawableContainer {
|
|||||||
@Override
|
@Override
|
||||||
public Drawable mutate() {
|
public Drawable mutate() {
|
||||||
if (!mMutated && super.mutate() == this) {
|
if (!mMutated && super.mutate() == this) {
|
||||||
final int[][] sets = mStateListState.mStateSets;
|
mStateListState.mutate();
|
||||||
final int count = sets.length;
|
|
||||||
mStateListState.mStateSets = new int[count][];
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
final int[] set = sets[i];
|
|
||||||
if (set != null) {
|
|
||||||
mStateListState.mStateSets[i] = set.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mMutated = true;
|
mMutated = true;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
StateListState cloneConstantState() {
|
||||||
|
return new StateListState(mStateListState, this, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -328,25 +327,24 @@ public class StateListDrawable extends DrawableContainer {
|
|||||||
super(orig, owner, res);
|
super(orig, owner, res);
|
||||||
|
|
||||||
if (orig != null) {
|
if (orig != null) {
|
||||||
// Perform a deep copy.
|
// Perform a shallow copy and rely on mutate() to deep-copy.
|
||||||
final int[][] sets = orig.mStateSets;
|
|
||||||
final int count = sets.length;
|
|
||||||
mStateSets = new int[count][];
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
final int[] set = sets[i];
|
|
||||||
if (set != null) {
|
|
||||||
mStateSets[i] = set.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mThemeAttrs = orig.mThemeAttrs;
|
mThemeAttrs = orig.mThemeAttrs;
|
||||||
mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length);
|
mStateSets = orig.mStateSets;
|
||||||
} else {
|
} else {
|
||||||
mThemeAttrs = null;
|
mThemeAttrs = null;
|
||||||
mStateSets = new int[getCapacity()][];
|
mStateSets = new int[getCapacity()][];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mutate() {
|
||||||
|
mThemeAttrs = mThemeAttrs != null ? mThemeAttrs.clone() : null;
|
||||||
|
|
||||||
|
final int[][] stateSets = new int[mStateSets.length][];
|
||||||
|
for (int i = mStateSets.length - 1; i >= 0; i--) {
|
||||||
|
stateSets[i] = mStateSets[i] != null ? mStateSets[i].clone() : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int addStateSet(int[] stateSet, Drawable drawable) {
|
int addStateSet(int[] stateSet, Drawable drawable) {
|
||||||
final int pos = addChild(drawable);
|
final int pos = addChild(drawable);
|
||||||
mStateSets[pos] = stateSet;
|
mStateSets[pos] = stateSet;
|
||||||
@@ -395,13 +393,16 @@ public class StateListDrawable extends DrawableContainer {
|
|||||||
onStateChange(getState());
|
onStateChange(getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
void setConstantState(StateListState state) {
|
protected void setConstantState(@NonNull DrawableContainerState state) {
|
||||||
super.setConstantState(state);
|
super.setConstantState(state);
|
||||||
|
|
||||||
mStateListState = state;
|
if (state instanceof StateListState) {
|
||||||
|
mStateListState = (StateListState) state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StateListDrawable(StateListState state, Resources res) {
|
private StateListDrawable(StateListState state, Resources res) {
|
||||||
|
// Every state list drawable has its own constant state.
|
||||||
final StateListState newState = new StateListState(state, this, res);
|
final StateListState newState = new StateListState(state, this, res);
|
||||||
setConstantState(newState);
|
setConstantState(newState);
|
||||||
onStateChange(getState());
|
onStateChange(getState());
|
||||||
@@ -411,7 +412,7 @@ public class StateListDrawable extends DrawableContainer {
|
|||||||
* This constructor exists so subclasses can avoid calling the default
|
* This constructor exists so subclasses can avoid calling the default
|
||||||
* constructor and setting up a StateListDrawable-specific constant state.
|
* constructor and setting up a StateListDrawable-specific constant state.
|
||||||
*/
|
*/
|
||||||
StateListDrawable(StateListState state) {
|
StateListDrawable(@Nullable StateListState state) {
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
setConstantState(state);
|
setConstantState(state);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user