Skip to content

Commit 393a52c

Browse files
author
Romain Guy
committed
Make it harder for apps to mess up ViewGroup's internal state
Bug #6421288 Change-Id: I8c2c597f45391d3c1ae40c8341a68bb25d8ad4d9
1 parent 956f28e commit 393a52c

File tree

3 files changed

+118
-15
lines changed

3 files changed

+118
-15
lines changed

core/java/android/view/View.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12725,6 +12725,7 @@ private boolean drawAnimation(ViewGroup parent, long drawingTime,
1272512725
if (!initialized) {
1272612726
a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
1272712727
a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
12728+
if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
1272812729
onAnimationStart();
1272912730
}
1273012731

@@ -12738,6 +12739,7 @@ private boolean drawAnimation(ViewGroup parent, long drawingTime,
1273812739
} else {
1273912740
invalidationTransform = parent.mChildTransformation;
1274012741
}
12742+
1274112743
if (more) {
1274212744
if (!a.willChangeBounds()) {
1274312745
if ((flags & (parent.FLAG_OPTIMIZE_INVALIDATE | parent.FLAG_ANIMATION_DONE)) ==

core/java/android/view/ViewGroup.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3154,8 +3154,12 @@ protected View findViewByPredicateTraversal(Predicate<View> predicate, View chil
31543154
}
31553155

31563156
/**
3157-
* Adds a child view. If no layout parameters are already set on the child, the
3158-
* default parameters for this ViewGroup are set on the child.
3157+
* <p>Adds a child view. If no layout parameters are already set on the child, the
3158+
* default parameters for this ViewGroup are set on the child.</p>
3159+
*
3160+
* <p><strong>Note:</strong> do not invoke this method from
3161+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3162+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
31593163
*
31603164
* @param child the child view to add
31613165
*
@@ -3168,6 +3172,10 @@ public void addView(View child) {
31683172
/**
31693173
* Adds a child view. If no layout parameters are already set on the child, the
31703174
* default parameters for this ViewGroup are set on the child.
3175+
*
3176+
* <p><strong>Note:</strong> do not invoke this method from
3177+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3178+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
31713179
*
31723180
* @param child the child view to add
31733181
* @param index the position at which to add the child
@@ -3189,6 +3197,10 @@ public void addView(View child, int index) {
31893197
* Adds a child view with this ViewGroup's default layout parameters and the
31903198
* specified width and height.
31913199
*
3200+
* <p><strong>Note:</strong> do not invoke this method from
3201+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3202+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3203+
*
31923204
* @param child the child view to add
31933205
*/
31943206
public void addView(View child, int width, int height) {
@@ -3201,6 +3213,10 @@ public void addView(View child, int width, int height) {
32013213
/**
32023214
* Adds a child view with the specified layout parameters.
32033215
*
3216+
* <p><strong>Note:</strong> do not invoke this method from
3217+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3218+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3219+
*
32043220
* @param child the child view to add
32053221
* @param params the layout parameters to set on the child
32063222
*/
@@ -3211,6 +3227,10 @@ public void addView(View child, LayoutParams params) {
32113227
/**
32123228
* Adds a child view with the specified layout parameters.
32133229
*
3230+
* <p><strong>Note:</strong> do not invoke this method from
3231+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3232+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3233+
*
32143234
* @param child the child view to add
32153235
* @param index the position at which to add the child
32163236
* @param params the layout parameters to set on the child
@@ -3528,6 +3548,10 @@ protected void attachLayoutAnimationParameters(View child,
35283548

35293549
/**
35303550
* {@inheritDoc}
3551+
*
3552+
* <p><strong>Note:</strong> do not invoke this method from
3553+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3554+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
35313555
*/
35323556
public void removeView(View view) {
35333557
removeViewInternal(view);
@@ -3539,6 +3563,10 @@ public void removeView(View view) {
35393563
* Removes a view during layout. This is useful if in your onLayout() method,
35403564
* you need to remove more views.
35413565
*
3566+
* <p><strong>Note:</strong> do not invoke this method from
3567+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3568+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3569+
*
35423570
* @param view the view to remove from the group
35433571
*/
35443572
public void removeViewInLayout(View view) {
@@ -3549,6 +3577,10 @@ public void removeViewInLayout(View view) {
35493577
* Removes a range of views during layout. This is useful if in your onLayout() method,
35503578
* you need to remove more views.
35513579
*
3580+
* <p><strong>Note:</strong> do not invoke this method from
3581+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3582+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3583+
*
35523584
* @param start the index of the first view to remove from the group
35533585
* @param count the number of views to remove from the group
35543586
*/
@@ -3559,6 +3591,10 @@ public void removeViewsInLayout(int start, int count) {
35593591
/**
35603592
* Removes the view at the specified position in the group.
35613593
*
3594+
* <p><strong>Note:</strong> do not invoke this method from
3595+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3596+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3597+
*
35623598
* @param index the position in the group of the view to remove
35633599
*/
35643600
public void removeViewAt(int index) {
@@ -3570,6 +3606,10 @@ public void removeViewAt(int index) {
35703606
/**
35713607
* Removes the specified range of views from the group.
35723608
*
3609+
* <p><strong>Note:</strong> do not invoke this method from
3610+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3611+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3612+
*
35733613
* @param start the first position in the group of the range of views to remove
35743614
* @param count the number of views to remove
35753615
*/
@@ -3715,6 +3755,10 @@ private void removeViewsInternal(int start, int count) {
37153755
/**
37163756
* Call this method to remove all child views from the
37173757
* ViewGroup.
3758+
*
3759+
* <p><strong>Note:</strong> do not invoke this method from
3760+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3761+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
37183762
*/
37193763
public void removeAllViews() {
37203764
removeAllViewsInLayout();
@@ -3730,6 +3774,10 @@ public void removeAllViews() {
37303774
* that can currently fit inside the object on screen. Do not call
37313775
* this method unless you are extending ViewGroup and understand the
37323776
* view measuring and layout pipeline.
3777+
*
3778+
* <p><strong>Note:</strong> do not invoke this method from
3779+
* {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3780+
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
37333781
*/
37343782
public void removeAllViewsInLayout() {
37353783
final int count = mChildrenCount;

core/java/android/view/animation/Animation.java

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import android.content.Context;
2020
import android.content.res.TypedArray;
2121
import android.graphics.RectF;
22+
import android.os.Handler;
2223
import android.os.SystemProperties;
2324
import android.util.AttributeSet;
2425
import android.util.TypedValue;
@@ -207,6 +208,11 @@ public abstract class Animation implements Cloneable {
207208

208209
private final CloseGuard guard = CloseGuard.get();
209210

211+
private Handler mListenerHandler;
212+
private Runnable mOnStart;
213+
private Runnable mOnRepeat;
214+
private Runnable mOnEnd;
215+
210216
/**
211217
* Creates a new animation with a duration of 0ms, the default interpolator, with
212218
* fillBefore set to true and fillAfter set to false
@@ -275,6 +281,7 @@ public void reset() {
275281
mRepeated = 0;
276282
mMore = true;
277283
mOneMoreTime = true;
284+
mListenerHandler = null;
278285
}
279286

280287
/**
@@ -290,7 +297,7 @@ public void reset() {
290297
*/
291298
public void cancel() {
292299
if (mStarted && !mEnded) {
293-
if (mListener != null) mListener.onAnimationEnd(this);
300+
fireAnimationEnd();
294301
mEnded = true;
295302
guard.close();
296303
}
@@ -306,7 +313,7 @@ public void detach() {
306313
if (mStarted && !mEnded) {
307314
mEnded = true;
308315
guard.close();
309-
if (mListener != null) mListener.onAnimationEnd(this);
316+
fireAnimationEnd();
310317
}
311318
}
312319

@@ -340,6 +347,38 @@ public void initialize(int width, int height, int parentWidth, int parentHeight)
340347
mInitialized = true;
341348
}
342349

350+
/**
351+
* Sets the handler used to invoke listeners.
352+
*
353+
* @hide
354+
*/
355+
public void setListenerHandler(Handler handler) {
356+
if (mListenerHandler == null) {
357+
mOnStart = new Runnable() {
358+
public void run() {
359+
if (mListener != null) {
360+
mListener.onAnimationStart(Animation.this);
361+
}
362+
}
363+
};
364+
mOnRepeat = new Runnable() {
365+
public void run() {
366+
if (mListener != null) {
367+
mListener.onAnimationRepeat(Animation.this);
368+
}
369+
}
370+
};
371+
mOnEnd = new Runnable() {
372+
public void run() {
373+
if (mListener != null) {
374+
mListener.onAnimationEnd(Animation.this);
375+
}
376+
}
377+
};
378+
}
379+
mListenerHandler = handler;
380+
}
381+
343382
/**
344383
* Sets the acceleration curve for this animation. The interpolator is loaded as
345384
* a resource from the specified context.
@@ -792,7 +831,6 @@ public long computeDurationHint() {
792831
* @return True if the animation is still running
793832
*/
794833
public boolean getTransformation(long currentTime, Transformation outTransformation) {
795-
796834
if (mStartTime == -1) {
797835
mStartTime = currentTime;
798836
}
@@ -815,9 +853,7 @@ public boolean getTransformation(long currentTime, Transformation outTransformat
815853

816854
if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
817855
if (!mStarted) {
818-
if (mListener != null) {
819-
mListener.onAnimationStart(this);
820-
}
856+
fireAnimationStart();
821857
mStarted = true;
822858
if (USE_CLOSEGUARD) {
823859
guard.open("cancel or detach or getTransformation");
@@ -839,9 +875,7 @@ public boolean getTransformation(long currentTime, Transformation outTransformat
839875
if (!mEnded) {
840876
mEnded = true;
841877
guard.close();
842-
if (mListener != null) {
843-
mListener.onAnimationEnd(this);
844-
}
878+
fireAnimationEnd();
845879
}
846880
} else {
847881
if (mRepeatCount > 0) {
@@ -855,9 +889,7 @@ public boolean getTransformation(long currentTime, Transformation outTransformat
855889
mStartTime = -1;
856890
mMore = true;
857891

858-
if (mListener != null) {
859-
mListener.onAnimationRepeat(this);
860-
}
892+
fireAnimationRepeat();
861893
}
862894
}
863895

@@ -868,7 +900,28 @@ public boolean getTransformation(long currentTime, Transformation outTransformat
868900

869901
return mMore;
870902
}
871-
903+
904+
private void fireAnimationStart() {
905+
if (mListener != null) {
906+
if (mListenerHandler == null) mListener.onAnimationStart(this);
907+
else mListenerHandler.postAtFrontOfQueue(mOnStart);
908+
}
909+
}
910+
911+
private void fireAnimationRepeat() {
912+
if (mListener != null) {
913+
if (mListenerHandler == null) mListener.onAnimationRepeat(this);
914+
else mListenerHandler.postAtFrontOfQueue(mOnRepeat);
915+
}
916+
}
917+
918+
private void fireAnimationEnd() {
919+
if (mListener != null) {
920+
if (mListenerHandler == null) mListener.onAnimationEnd(this);
921+
else mListenerHandler.postAtFrontOfQueue(mOnEnd);
922+
}
923+
}
924+
872925
/**
873926
* Gets the transformation to apply at a specified point in time. Implementations of this
874927
* method should always replace the specified Transformation or document they are doing

0 commit comments

Comments
 (0)