blob: 521fd311732978d83f40546466993916c2f749eb [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.graphics.Rect;
Jeff Brownfbf09772011-01-16 14:06:57 -080020import android.graphics.Region;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021
Chet Haase6e0ecb42010-11-03 19:41:18 -070022import java.util.ArrayList;
Chet Haase0f8ffd82012-06-07 07:48:48 -070023import java.util.concurrent.CopyOnWriteArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
25/**
26 * A view tree observer is used to register listeners that can be notified of global
27 * changes in the view tree. Such global events include, but are not limited to,
28 * layout of the whole tree, beginning of the drawing pass, touch mode change....
29 *
30 * A ViewTreeObserver should never be instantiated by applications as it is provided
31 * by the views hierarchy. Refer to {@link android.view.View#getViewTreeObserver()}
32 * for more information.
33 */
34public final class ViewTreeObserver {
Romain Guyc39ed4a2012-06-12 12:06:46 -070035 // Recursive listeners use CopyOnWriteArrayList
Dianne Hackborn961cae92013-03-20 14:59:43 -070036 private CopyOnWriteArrayList<OnWindowFocusChangeListener> mOnWindowFocusListeners;
37 private CopyOnWriteArrayList<OnWindowAttachListener> mOnWindowAttachListeners;
Chet Haase0f8ffd82012-06-07 07:48:48 -070038 private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
Chet Haase0f8ffd82012-06-07 07:48:48 -070039 private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
Filip Gruszczynski6eafa902014-11-14 14:24:37 -080040 private CopyOnWriteArrayList<OnEnterAnimationCompleteListener>
41 mOnEnterAnimationCompleteListeners;
Romain Guyc39ed4a2012-06-12 12:06:46 -070042
43 // Non-recursive listeners use CopyOnWriteArray
44 // Any listener invoked from ViewRootImpl.performTraversals() should not be recursive
45 private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
46 private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
47 private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
48 private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
Craig Mautner9c795042014-10-28 19:59:59 -070049 private CopyOnWriteArray<OnWindowShownListener> mOnWindowShownListeners;
Romain Guyc39ed4a2012-06-12 12:06:46 -070050
51 // These listeners cannot be mutated during dispatch
Romain Guy25eba5c2012-04-04 17:29:03 -070052 private ArrayList<OnDrawListener> mOnDrawListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
Craig Mautner9c795042014-10-28 19:59:59 -070054 /** Remains false until #dispatchOnWindowShown() is called. If a listener registers after
55 * that the listener will be immediately called. */
56 private boolean mWindowShown;
57
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 private boolean mAlive = true;
59
60 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -070061 * Interface definition for a callback to be invoked when the view hierarchy is
62 * attached to and detached from its window.
63 */
64 public interface OnWindowAttachListener {
65 /**
66 * Callback method to be invoked when the view hierarchy is attached to a window
67 */
68 public void onWindowAttached();
69
70 /**
71 * Callback method to be invoked when the view hierarchy is detached from a window
72 */
73 public void onWindowDetached();
74 }
75
76 /**
77 * Interface definition for a callback to be invoked when the view hierarchy's window
78 * focus state changes.
79 */
80 public interface OnWindowFocusChangeListener {
81 /**
82 * Callback method to be invoked when the window focus changes in the view tree.
83 *
84 * @param hasFocus Set to true if the window is gaining focus, false if it is
85 * losing focus.
86 */
87 public void onWindowFocusChanged(boolean hasFocus);
88 }
89
90 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 * Interface definition for a callback to be invoked when the focus state within
92 * the view tree changes.
93 */
94 public interface OnGlobalFocusChangeListener {
95 /**
96 * Callback method to be invoked when the focus changes in the view tree. When
97 * the view tree transitions from touch mode to non-touch mode, oldFocus is null.
98 * When the view tree transitions from non-touch mode to touch mode, newFocus is
99 * null. When focus changes in non-touch mode (without transition from or to
100 * touch mode) either oldFocus or newFocus can be null.
101 *
102 * @param oldFocus The previously focused view, if any.
103 * @param newFocus The newly focused View, if any.
104 */
105 public void onGlobalFocusChanged(View oldFocus, View newFocus);
106 }
107
108 /**
109 * Interface definition for a callback to be invoked when the global layout state
110 * or the visibility of views within the view tree changes.
111 */
112 public interface OnGlobalLayoutListener {
113 /**
114 * Callback method to be invoked when the global layout state or the visibility of views
115 * within the view tree changes
116 */
117 public void onGlobalLayout();
118 }
119
120 /**
121 * Interface definition for a callback to be invoked when the view tree is about to be drawn.
122 */
123 public interface OnPreDrawListener {
124 /**
125 * Callback method to be invoked when the view tree is about to be drawn. At this point, all
126 * views in the tree have been measured and given a frame. Clients can use this to adjust
127 * their scroll bounds or even to request a new layout before drawing occurs.
128 *
129 * @return Return true to proceed with the current drawing pass, or false to cancel.
130 *
131 * @see android.view.View#onMeasure
132 * @see android.view.View#onLayout
133 * @see android.view.View#onDraw
134 */
135 public boolean onPreDraw();
136 }
137
138 /**
Romain Guy25eba5c2012-04-04 17:29:03 -0700139 * Interface definition for a callback to be invoked when the view tree is about to be drawn.
140 */
141 public interface OnDrawListener {
142 /**
143 * <p>Callback method to be invoked when the view tree is about to be drawn. At this point,
144 * views cannot be modified in any way.</p>
145 *
146 * <p>Unlike with {@link OnPreDrawListener}, this method cannot be used to cancel the
147 * current drawing pass.</p>
148 *
149 * <p>An {@link OnDrawListener} listener <strong>cannot be added or removed</strong>
150 * from this method.</p>
151 *
152 * @see android.view.View#onMeasure
153 * @see android.view.View#onLayout
154 * @see android.view.View#onDraw
155 */
156 public void onDraw();
157 }
158
159 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 * Interface definition for a callback to be invoked when the touch mode changes.
161 */
162 public interface OnTouchModeChangeListener {
163 /**
164 * Callback method to be invoked when the touch mode changes.
165 *
166 * @param isInTouchMode True if the view hierarchy is now in touch mode, false otherwise.
167 */
168 public void onTouchModeChanged(boolean isInTouchMode);
169 }
170
171 /**
172 * Interface definition for a callback to be invoked when
173 * something in the view tree has been scrolled.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 */
175 public interface OnScrollChangedListener {
176 /**
177 * Callback method to be invoked when something in the view tree
178 * has been scrolled.
179 */
180 public void onScrollChanged();
181 }
182
183 /**
Craig Mautner9c795042014-10-28 19:59:59 -0700184 * Interface definition for a callback noting when a system window has been displayed.
185 * This is only used for non-Activity windows. Activity windows can use
186 * Activity.onEnterAnimationComplete() to get the same signal.
187 * @hide
188 */
189 public interface OnWindowShownListener {
190 /**
191 * Callback method to be invoked when a non-activity window is fully shown.
192 */
193 void onWindowShown();
194 }
195
196 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 * Parameters used with OnComputeInternalInsetsListener.
Dianne Hackborn935ae462009-04-13 16:11:55 -0700198 *
199 * We are not yet ready to commit to this API and support it, so
200 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 */
202 public final static class InternalInsetsInfo {
203 /**
204 * Offsets from the frame of the window at which the content of
205 * windows behind it should be placed.
206 */
207 public final Rect contentInsets = new Rect();
Romain Guyc39ed4a2012-06-12 12:06:46 -0700208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 /**
Jeff Brownfbf09772011-01-16 14:06:57 -0800210 * Offsets from the frame of the window at which windows behind it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 * are visible.
212 */
213 public final Rect visibleInsets = new Rect();
Jeff Brownfbf09772011-01-16 14:06:57 -0800214
215 /**
216 * Touchable region defined relative to the origin of the frame of the window.
217 * Only used when {@link #setTouchableInsets(int)} is called with
218 * the option {@link #TOUCHABLE_INSETS_REGION}.
219 */
220 public final Region touchableRegion = new Region();
221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 /**
223 * Option for {@link #setTouchableInsets(int)}: the entire window frame
224 * can be touched.
225 */
226 public static final int TOUCHABLE_INSETS_FRAME = 0;
Romain Guyc39ed4a2012-06-12 12:06:46 -0700227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 /**
229 * Option for {@link #setTouchableInsets(int)}: the area inside of
230 * the content insets can be touched.
231 */
232 public static final int TOUCHABLE_INSETS_CONTENT = 1;
Romain Guyc39ed4a2012-06-12 12:06:46 -0700233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 /**
235 * Option for {@link #setTouchableInsets(int)}: the area inside of
236 * the visible insets can be touched.
237 */
238 public static final int TOUCHABLE_INSETS_VISIBLE = 2;
Jeff Brownfbf09772011-01-16 14:06:57 -0800239
240 /**
241 * Option for {@link #setTouchableInsets(int)}: the area inside of
242 * the provided touchable region in {@link #touchableRegion} can be touched.
243 */
244 public static final int TOUCHABLE_INSETS_REGION = 3;
245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 /**
247 * Set which parts of the window can be touched: either
248 * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
Jeff Brownfbf09772011-01-16 14:06:57 -0800249 * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 */
251 public void setTouchableInsets(int val) {
252 mTouchableInsets = val;
253 }
Romain Guy25eba5c2012-04-04 17:29:03 -0700254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 int mTouchableInsets;
Romain Guyc39ed4a2012-06-12 12:06:46 -0700256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 void reset() {
Jeff Brownfbf09772011-01-16 14:06:57 -0800258 contentInsets.setEmpty();
259 visibleInsets.setEmpty();
260 touchableRegion.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 mTouchableInsets = TOUCHABLE_INSETS_FRAME;
262 }
Romain Guy25eba5c2012-04-04 17:29:03 -0700263
Jeff Brown2e05ec32013-09-30 15:57:43 -0700264 boolean isEmpty() {
265 return contentInsets.isEmpty()
266 && visibleInsets.isEmpty()
267 && touchableRegion.isEmpty()
268 && mTouchableInsets == TOUCHABLE_INSETS_FRAME;
269 }
270
Romain Guy25eba5c2012-04-04 17:29:03 -0700271 @Override
272 public int hashCode() {
Romain Guy21f42302013-06-28 19:19:30 -0700273 int result = contentInsets.hashCode();
274 result = 31 * result + visibleInsets.hashCode();
275 result = 31 * result + touchableRegion.hashCode();
Romain Guy25eba5c2012-04-04 17:29:03 -0700276 result = 31 * result + mTouchableInsets;
277 return result;
278 }
279
Romain Guy1e878d22012-01-23 15:34:25 -0800280 @Override
281 public boolean equals(Object o) {
Romain Guy25eba5c2012-04-04 17:29:03 -0700282 if (this == o) return true;
283 if (o == null || getClass() != o.getClass()) return false;
284
285 InternalInsetsInfo other = (InternalInsetsInfo)o;
286 return mTouchableInsets == other.mTouchableInsets &&
287 contentInsets.equals(other.contentInsets) &&
288 visibleInsets.equals(other.visibleInsets) &&
289 touchableRegion.equals(other.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 }
Romain Guy25eba5c2012-04-04 17:29:03 -0700291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 void set(InternalInsetsInfo other) {
293 contentInsets.set(other.contentInsets);
294 visibleInsets.set(other.visibleInsets);
Jeff Brownfbf09772011-01-16 14:06:57 -0800295 touchableRegion.set(other.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 mTouchableInsets = other.mTouchableInsets;
297 }
298 }
Romain Guyc39ed4a2012-06-12 12:06:46 -0700299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 /**
301 * Interface definition for a callback to be invoked when layout has
302 * completed and the client can compute its interior insets.
Dianne Hackborn935ae462009-04-13 16:11:55 -0700303 *
304 * We are not yet ready to commit to this API and support it, so
305 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 */
307 public interface OnComputeInternalInsetsListener {
308 /**
309 * Callback method to be invoked when layout has completed and the
310 * client can compute its interior insets.
311 *
312 * @param inoutInfo Should be filled in by the implementation with
313 * the information about the insets of the window. This is called
314 * with whatever values the previous OnComputeInternalInsetsListener
315 * returned, if there are multiple such listeners in the window.
316 */
317 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo);
318 }
319
320 /**
Filip Gruszczynski6eafa902014-11-14 14:24:37 -0800321 * @hide
322 */
323 public interface OnEnterAnimationCompleteListener {
324 public void onEnterAnimationComplete();
325 }
326
327 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 * Creates a new ViewTreeObserver. This constructor should not be called
329 */
330 ViewTreeObserver() {
331 }
332
333 /**
334 * Merges all the listeners registered on the specified observer with the listeners
335 * registered on this object. After this method is invoked, the specified observer
336 * will return false in {@link #isAlive()} and should not be used anymore.
337 *
338 * @param observer The ViewTreeObserver whose listeners must be added to this observer
339 */
340 void merge(ViewTreeObserver observer) {
Dianne Hackborn961cae92013-03-20 14:59:43 -0700341 if (observer.mOnWindowAttachListeners != null) {
342 if (mOnWindowAttachListeners != null) {
343 mOnWindowAttachListeners.addAll(observer.mOnWindowAttachListeners);
344 } else {
345 mOnWindowAttachListeners = observer.mOnWindowAttachListeners;
346 }
347 }
348
349 if (observer.mOnWindowFocusListeners != null) {
350 if (mOnWindowFocusListeners != null) {
351 mOnWindowFocusListeners.addAll(observer.mOnWindowFocusListeners);
352 } else {
353 mOnWindowFocusListeners = observer.mOnWindowFocusListeners;
354 }
355 }
356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 if (observer.mOnGlobalFocusListeners != null) {
358 if (mOnGlobalFocusListeners != null) {
359 mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners);
360 } else {
361 mOnGlobalFocusListeners = observer.mOnGlobalFocusListeners;
362 }
363 }
364
365 if (observer.mOnGlobalLayoutListeners != null) {
366 if (mOnGlobalLayoutListeners != null) {
367 mOnGlobalLayoutListeners.addAll(observer.mOnGlobalLayoutListeners);
368 } else {
369 mOnGlobalLayoutListeners = observer.mOnGlobalLayoutListeners;
370 }
371 }
372
373 if (observer.mOnPreDrawListeners != null) {
374 if (mOnPreDrawListeners != null) {
375 mOnPreDrawListeners.addAll(observer.mOnPreDrawListeners);
376 } else {
377 mOnPreDrawListeners = observer.mOnPreDrawListeners;
378 }
379 }
380
381 if (observer.mOnTouchModeChangeListeners != null) {
382 if (mOnTouchModeChangeListeners != null) {
383 mOnTouchModeChangeListeners.addAll(observer.mOnTouchModeChangeListeners);
384 } else {
385 mOnTouchModeChangeListeners = observer.mOnTouchModeChangeListeners;
386 }
387 }
388
389 if (observer.mOnComputeInternalInsetsListeners != null) {
390 if (mOnComputeInternalInsetsListeners != null) {
391 mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners);
392 } else {
393 mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners;
394 }
395 }
396
Mark Brophy757c6972011-10-25 17:01:28 +0100397 if (observer.mOnScrollChangedListeners != null) {
398 if (mOnScrollChangedListeners != null) {
399 mOnScrollChangedListeners.addAll(observer.mOnScrollChangedListeners);
400 } else {
401 mOnScrollChangedListeners = observer.mOnScrollChangedListeners;
402 }
403 }
404
Craig Mautner9c795042014-10-28 19:59:59 -0700405 if (observer.mOnWindowShownListeners != null) {
406 if (mOnWindowShownListeners != null) {
407 mOnWindowShownListeners.addAll(observer.mOnWindowShownListeners);
408 } else {
409 mOnWindowShownListeners = observer.mOnWindowShownListeners;
410 }
411 }
412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 observer.kill();
414 }
415
416 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -0700417 * Register a callback to be invoked when the view hierarchy is attached to a window.
418 *
419 * @param listener The callback to add
420 *
421 * @throws IllegalStateException If {@link #isAlive()} returns false
422 */
423 public void addOnWindowAttachListener(OnWindowAttachListener listener) {
424 checkIsAlive();
425
426 if (mOnWindowAttachListeners == null) {
427 mOnWindowAttachListeners
428 = new CopyOnWriteArrayList<OnWindowAttachListener>();
429 }
430
431 mOnWindowAttachListeners.add(listener);
432 }
433
434 /**
435 * Remove a previously installed window attach callback.
436 *
437 * @param victim The callback to remove
438 *
439 * @throws IllegalStateException If {@link #isAlive()} returns false
440 *
441 * @see #addOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener)
442 */
443 public void removeOnWindowAttachListener(OnWindowAttachListener victim) {
444 checkIsAlive();
445 if (mOnWindowAttachListeners == null) {
446 return;
447 }
448 mOnWindowAttachListeners.remove(victim);
449 }
450
451 /**
452 * Register a callback to be invoked when the window focus state within the view tree changes.
453 *
454 * @param listener The callback to add
455 *
456 * @throws IllegalStateException If {@link #isAlive()} returns false
457 */
458 public void addOnWindowFocusChangeListener(OnWindowFocusChangeListener listener) {
459 checkIsAlive();
460
461 if (mOnWindowFocusListeners == null) {
462 mOnWindowFocusListeners
463 = new CopyOnWriteArrayList<OnWindowFocusChangeListener>();
464 }
465
466 mOnWindowFocusListeners.add(listener);
467 }
468
469 /**
470 * Remove a previously installed window focus change callback.
471 *
472 * @param victim The callback to remove
473 *
474 * @throws IllegalStateException If {@link #isAlive()} returns false
475 *
476 * @see #addOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener)
477 */
478 public void removeOnWindowFocusChangeListener(OnWindowFocusChangeListener victim) {
479 checkIsAlive();
480 if (mOnWindowFocusListeners == null) {
481 return;
482 }
483 mOnWindowFocusListeners.remove(victim);
484 }
485
486 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 * Register a callback to be invoked when the focus state within the view tree changes.
488 *
489 * @param listener The callback to add
490 *
491 * @throws IllegalStateException If {@link #isAlive()} returns false
492 */
493 public void addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener listener) {
494 checkIsAlive();
495
496 if (mOnGlobalFocusListeners == null) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700497 mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 }
499
500 mOnGlobalFocusListeners.add(listener);
501 }
502
503 /**
504 * Remove a previously installed focus change callback.
505 *
506 * @param victim The callback to remove
507 *
508 * @throws IllegalStateException If {@link #isAlive()} returns false
509 *
510 * @see #addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener)
511 */
512 public void removeOnGlobalFocusChangeListener(OnGlobalFocusChangeListener victim) {
513 checkIsAlive();
514 if (mOnGlobalFocusListeners == null) {
515 return;
516 }
517 mOnGlobalFocusListeners.remove(victim);
518 }
519
520 /**
521 * Register a callback to be invoked when the global layout state or the visibility of views
522 * within the view tree changes
523 *
524 * @param listener The callback to add
525 *
526 * @throws IllegalStateException If {@link #isAlive()} returns false
527 */
528 public void addOnGlobalLayoutListener(OnGlobalLayoutListener listener) {
529 checkIsAlive();
530
531 if (mOnGlobalLayoutListeners == null) {
Romain Guyc39ed4a2012-06-12 12:06:46 -0700532 mOnGlobalLayoutListeners = new CopyOnWriteArray<OnGlobalLayoutListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 }
534
535 mOnGlobalLayoutListeners.add(listener);
536 }
537
538 /**
539 * Remove a previously installed global layout callback
540 *
541 * @param victim The callback to remove
542 *
543 * @throws IllegalStateException If {@link #isAlive()} returns false
Romain Guy1e878d22012-01-23 15:34:25 -0800544 *
545 * @deprecated Use #removeOnGlobalLayoutListener instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 *
547 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
548 */
Romain Guy1e878d22012-01-23 15:34:25 -0800549 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 public void removeGlobalOnLayoutListener(OnGlobalLayoutListener victim) {
Romain Guy1e878d22012-01-23 15:34:25 -0800551 removeOnGlobalLayoutListener(victim);
552 }
553
554 /**
555 * Remove a previously installed global layout callback
556 *
557 * @param victim The callback to remove
558 *
559 * @throws IllegalStateException If {@link #isAlive()} returns false
560 *
561 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
562 */
563 public void removeOnGlobalLayoutListener(OnGlobalLayoutListener victim) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 checkIsAlive();
565 if (mOnGlobalLayoutListeners == null) {
566 return;
567 }
568 mOnGlobalLayoutListeners.remove(victim);
569 }
570
571 /**
572 * Register a callback to be invoked when the view tree is about to be drawn
573 *
574 * @param listener The callback to add
575 *
576 * @throws IllegalStateException If {@link #isAlive()} returns false
577 */
578 public void addOnPreDrawListener(OnPreDrawListener listener) {
579 checkIsAlive();
580
581 if (mOnPreDrawListeners == null) {
Romain Guyc39ed4a2012-06-12 12:06:46 -0700582 mOnPreDrawListeners = new CopyOnWriteArray<OnPreDrawListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 }
584
585 mOnPreDrawListeners.add(listener);
586 }
587
588 /**
589 * Remove a previously installed pre-draw callback
590 *
591 * @param victim The callback to remove
592 *
593 * @throws IllegalStateException If {@link #isAlive()} returns false
594 *
595 * @see #addOnPreDrawListener(OnPreDrawListener)
596 */
597 public void removeOnPreDrawListener(OnPreDrawListener victim) {
598 checkIsAlive();
599 if (mOnPreDrawListeners == null) {
600 return;
601 }
602 mOnPreDrawListeners.remove(victim);
603 }
604
605 /**
Craig Mautner9c795042014-10-28 19:59:59 -0700606 * Register a callback to be invoked when the view tree window has been shown
607 *
608 * @param listener The callback to add
609 *
610 * @throws IllegalStateException If {@link #isAlive()} returns false
611 * @hide
612 */
613 public void addOnWindowShownListener(OnWindowShownListener listener) {
614 checkIsAlive();
615
616 if (mOnWindowShownListeners == null) {
617 mOnWindowShownListeners = new CopyOnWriteArray<OnWindowShownListener>();
618 }
619
620 mOnWindowShownListeners.add(listener);
621 if (mWindowShown) {
622 listener.onWindowShown();
623 }
624 }
625
626 /**
627 * Remove a previously installed window shown callback
628 *
629 * @param victim The callback to remove
630 *
631 * @throws IllegalStateException If {@link #isAlive()} returns false
632 *
633 * @see #addOnWindowShownListener(OnWindowShownListener)
634 * @hide
635 */
636 public void removeOnWindowShownListener(OnWindowShownListener victim) {
637 checkIsAlive();
638 if (mOnWindowShownListeners == null) {
639 return;
640 }
641 mOnWindowShownListeners.remove(victim);
642 }
643
644 /**
Romain Guy25eba5c2012-04-04 17:29:03 -0700645 * <p>Register a callback to be invoked when the view tree is about to be drawn.</p>
646 * <p><strong>Note:</strong> this method <strong>cannot</strong> be invoked from
647 * {@link android.view.ViewTreeObserver.OnDrawListener#onDraw()}.</p>
648 *
649 * @param listener The callback to add
650 *
651 * @throws IllegalStateException If {@link #isAlive()} returns false
652 */
653 public void addOnDrawListener(OnDrawListener listener) {
654 checkIsAlive();
655
656 if (mOnDrawListeners == null) {
657 mOnDrawListeners = new ArrayList<OnDrawListener>();
658 }
659
660 mOnDrawListeners.add(listener);
661 }
662
663 /**
664 * <p>Remove a previously installed pre-draw callback.</p>
665 * <p><strong>Note:</strong> this method <strong>cannot</strong> be invoked from
666 * {@link android.view.ViewTreeObserver.OnDrawListener#onDraw()}.</p>
667 *
668 * @param victim The callback to remove
669 *
670 * @throws IllegalStateException If {@link #isAlive()} returns false
671 *
672 * @see #addOnDrawListener(OnDrawListener)
673 */
674 public void removeOnDrawListener(OnDrawListener victim) {
675 checkIsAlive();
676 if (mOnDrawListeners == null) {
677 return;
678 }
679 mOnDrawListeners.remove(victim);
680 }
681
682 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 * Register a callback to be invoked when a view has been scrolled.
684 *
685 * @param listener The callback to add
686 *
687 * @throws IllegalStateException If {@link #isAlive()} returns false
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 */
689 public void addOnScrollChangedListener(OnScrollChangedListener listener) {
690 checkIsAlive();
691
692 if (mOnScrollChangedListeners == null) {
Romain Guyc39ed4a2012-06-12 12:06:46 -0700693 mOnScrollChangedListeners = new CopyOnWriteArray<OnScrollChangedListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 }
695
696 mOnScrollChangedListeners.add(listener);
697 }
698
699 /**
700 * Remove a previously installed scroll-changed callback
701 *
702 * @param victim The callback to remove
703 *
704 * @throws IllegalStateException If {@link #isAlive()} returns false
705 *
706 * @see #addOnScrollChangedListener(OnScrollChangedListener)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 */
708 public void removeOnScrollChangedListener(OnScrollChangedListener victim) {
709 checkIsAlive();
710 if (mOnScrollChangedListeners == null) {
711 return;
712 }
713 mOnScrollChangedListeners.remove(victim);
714 }
715
716 /**
717 * Register a callback to be invoked when the invoked when the touch mode changes.
718 *
719 * @param listener The callback to add
720 *
721 * @throws IllegalStateException If {@link #isAlive()} returns false
722 */
723 public void addOnTouchModeChangeListener(OnTouchModeChangeListener listener) {
724 checkIsAlive();
725
726 if (mOnTouchModeChangeListeners == null) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700727 mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 }
729
730 mOnTouchModeChangeListeners.add(listener);
731 }
732
733 /**
734 * Remove a previously installed touch mode change callback
735 *
736 * @param victim The callback to remove
737 *
738 * @throws IllegalStateException If {@link #isAlive()} returns false
739 *
740 * @see #addOnTouchModeChangeListener(OnTouchModeChangeListener)
741 */
742 public void removeOnTouchModeChangeListener(OnTouchModeChangeListener victim) {
743 checkIsAlive();
744 if (mOnTouchModeChangeListeners == null) {
745 return;
746 }
747 mOnTouchModeChangeListeners.remove(victim);
748 }
749
750 /**
751 * Register a callback to be invoked when the invoked when it is time to
752 * compute the window's internal insets.
753 *
754 * @param listener The callback to add
755 *
756 * @throws IllegalStateException If {@link #isAlive()} returns false
Dianne Hackborn935ae462009-04-13 16:11:55 -0700757 *
758 * We are not yet ready to commit to this API and support it, so
759 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 */
761 public void addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener listener) {
762 checkIsAlive();
763
764 if (mOnComputeInternalInsetsListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700765 mOnComputeInternalInsetsListeners =
Romain Guyc39ed4a2012-06-12 12:06:46 -0700766 new CopyOnWriteArray<OnComputeInternalInsetsListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 }
768
769 mOnComputeInternalInsetsListeners.add(listener);
770 }
771
772 /**
773 * Remove a previously installed internal insets computation callback
774 *
775 * @param victim The callback to remove
776 *
777 * @throws IllegalStateException If {@link #isAlive()} returns false
778 *
779 * @see #addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener)
Dianne Hackborn935ae462009-04-13 16:11:55 -0700780 *
781 * We are not yet ready to commit to this API and support it, so
782 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 */
784 public void removeOnComputeInternalInsetsListener(OnComputeInternalInsetsListener victim) {
785 checkIsAlive();
786 if (mOnComputeInternalInsetsListeners == null) {
787 return;
788 }
789 mOnComputeInternalInsetsListeners.remove(victim);
790 }
791
Filip Gruszczynski6eafa902014-11-14 14:24:37 -0800792 /**
793 * @hide
794 */
795 public void addOnEnterAnimationCompleteListener(OnEnterAnimationCompleteListener listener) {
796 checkIsAlive();
797 if (mOnEnterAnimationCompleteListeners == null) {
798 mOnEnterAnimationCompleteListeners =
799 new CopyOnWriteArrayList<OnEnterAnimationCompleteListener>();
800 }
801 mOnEnterAnimationCompleteListeners.add(listener);
802 }
803
804 /**
805 * @hide
806 */
807 public void removeOnEnterAnimationCompleteListener(OnEnterAnimationCompleteListener listener) {
808 checkIsAlive();
809 if (mOnEnterAnimationCompleteListeners == null) {
810 return;
811 }
812 mOnEnterAnimationCompleteListeners.remove(listener);
813 }
814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 private void checkIsAlive() {
816 if (!mAlive) {
817 throw new IllegalStateException("This ViewTreeObserver is not alive, call "
818 + "getViewTreeObserver() again");
819 }
820 }
821
822 /**
823 * Indicates whether this ViewTreeObserver is alive. When an observer is not alive,
824 * any call to a method (except this one) will throw an exception.
825 *
826 * If an application keeps a long-lived reference to this ViewTreeObserver, it should
827 * always check for the result of this method before calling any other method.
828 *
829 * @return True if this object is alive and be used, false otherwise.
830 */
831 public boolean isAlive() {
832 return mAlive;
833 }
834
835 /**
836 * Marks this ViewTreeObserver as not alive. After invoking this method, invoking
837 * any other method but {@link #isAlive()} and {@link #kill()} will throw an Exception.
838 *
839 * @hide
840 */
841 private void kill() {
842 mAlive = false;
843 }
844
845 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -0700846 * Notifies registered listeners that window has been attached/detached.
847 */
848 final void dispatchOnWindowAttachedChange(boolean attached) {
849 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
850 // perform the dispatching. The iterator is a safe guard against listeners that
851 // could mutate the list by calling the various add/remove methods. This prevents
852 // the array from being modified while we iterate it.
853 final CopyOnWriteArrayList<OnWindowAttachListener> listeners
854 = mOnWindowAttachListeners;
855 if (listeners != null && listeners.size() > 0) {
856 for (OnWindowAttachListener listener : listeners) {
857 if (attached) listener.onWindowAttached();
858 else listener.onWindowDetached();
859 }
860 }
861 }
862
863 /**
864 * Notifies registered listeners that window focus has changed.
865 */
866 final void dispatchOnWindowFocusChange(boolean hasFocus) {
867 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
868 // perform the dispatching. The iterator is a safe guard against listeners that
869 // could mutate the list by calling the various add/remove methods. This prevents
870 // the array from being modified while we iterate it.
871 final CopyOnWriteArrayList<OnWindowFocusChangeListener> listeners
872 = mOnWindowFocusListeners;
873 if (listeners != null && listeners.size() > 0) {
874 for (OnWindowFocusChangeListener listener : listeners) {
875 listener.onWindowFocusChanged(hasFocus);
876 }
877 }
878 }
879
880 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 * Notifies registered listeners that focus has changed.
882 */
883 final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700884 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
885 // perform the dispatching. The iterator is a safe guard against listeners that
886 // could mutate the list by calling the various add/remove methods. This prevents
887 // the array from being modified while we iterate it.
Chet Haase0f8ffd82012-06-07 07:48:48 -0700888 final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700889 if (listeners != null && listeners.size() > 0) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700890 for (OnGlobalFocusChangeListener listener : listeners) {
891 listener.onGlobalFocusChanged(oldFocus, newFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 }
893 }
894 }
895
896 /**
897 * Notifies registered listeners that a global layout happened. This can be called
898 * manually if you are forcing a layout on a View or a hierarchy of Views that are
899 * not attached to a Window or in the GONE state.
900 */
901 public final void dispatchOnGlobalLayout() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700902 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
903 // perform the dispatching. The iterator is a safe guard against listeners that
904 // could mutate the list by calling the various add/remove methods. This prevents
905 // the array from being modified while we iterate it.
Romain Guyc39ed4a2012-06-12 12:06:46 -0700906 final CopyOnWriteArray<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700907 if (listeners != null && listeners.size() > 0) {
Romain Guyc39ed4a2012-06-12 12:06:46 -0700908 CopyOnWriteArray.Access<OnGlobalLayoutListener> access = listeners.start();
909 try {
910 int count = access.size();
911 for (int i = 0; i < count; i++) {
912 access.get(i).onGlobalLayout();
913 }
914 } finally {
915 listeners.end();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 }
917 }
918 }
919
920 /**
Romain Guy21f42302013-06-28 19:19:30 -0700921 * Returns whether there are listeners for on pre-draw events.
922 */
923 final boolean hasOnPreDrawListeners() {
924 return mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0;
925 }
926
927 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 * Notifies registered listeners that the drawing pass is about to start. If a
929 * listener returns true, then the drawing pass is canceled and rescheduled. This can
930 * be called manually if you are forcing the drawing on a View or a hierarchy of Views
931 * that are not attached to a Window or in the GONE state.
932 *
933 * @return True if the current draw should be canceled and resceduled, false otherwise.
934 */
Romain Guy25eba5c2012-04-04 17:29:03 -0700935 @SuppressWarnings("unchecked")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 public final boolean dispatchOnPreDraw() {
937 boolean cancelDraw = false;
Romain Guyc39ed4a2012-06-12 12:06:46 -0700938 final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
939 if (listeners != null && listeners.size() > 0) {
940 CopyOnWriteArray.Access<OnPreDrawListener> access = listeners.start();
941 try {
942 int count = access.size();
943 for (int i = 0; i < count; i++) {
944 cancelDraw |= !(access.get(i).onPreDraw());
945 }
946 } finally {
947 listeners.end();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 }
949 }
950 return cancelDraw;
951 }
952
953 /**
Craig Mautner9c795042014-10-28 19:59:59 -0700954 * Notifies registered listeners that the window is now shown
955 * @hide
956 */
957 @SuppressWarnings("unchecked")
958 public final void dispatchOnWindowShown() {
959 mWindowShown = true;
960 final CopyOnWriteArray<OnWindowShownListener> listeners = mOnWindowShownListeners;
961 if (listeners != null && listeners.size() > 0) {
962 CopyOnWriteArray.Access<OnWindowShownListener> access = listeners.start();
963 try {
964 int count = access.size();
965 for (int i = 0; i < count; i++) {
966 access.get(i).onWindowShown();
967 }
968 } finally {
969 listeners.end();
970 }
971 }
972 }
973
974 /**
Romain Guy25eba5c2012-04-04 17:29:03 -0700975 * Notifies registered listeners that the drawing pass is about to start.
976 */
977 public final void dispatchOnDraw() {
978 if (mOnDrawListeners != null) {
979 final ArrayList<OnDrawListener> listeners = mOnDrawListeners;
980 int numListeners = listeners.size();
981 for (int i = 0; i < numListeners; ++i) {
982 listeners.get(i).onDraw();
983 }
984 }
985 }
986
987 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 * Notifies registered listeners that the touch mode has changed.
989 *
990 * @param inTouchMode True if the touch mode is now enabled, false otherwise.
991 */
992 final void dispatchOnTouchModeChanged(boolean inTouchMode) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700993 final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
The Android Open Source Project10592532009-03-18 17:39:46 -0700994 mOnTouchModeChangeListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700995 if (listeners != null && listeners.size() > 0) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700996 for (OnTouchModeChangeListener listener : listeners) {
997 listener.onTouchModeChanged(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 }
999 }
1000 }
1001
1002 /**
1003 * Notifies registered listeners that something has scrolled.
1004 */
1005 final void dispatchOnScrollChanged() {
The Android Open Source Project10592532009-03-18 17:39:46 -07001006 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
1007 // perform the dispatching. The iterator is a safe guard against listeners that
1008 // could mutate the list by calling the various add/remove methods. This prevents
1009 // the array from being modified while we iterate it.
Romain Guyc39ed4a2012-06-12 12:06:46 -07001010 final CopyOnWriteArray<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -07001011 if (listeners != null && listeners.size() > 0) {
Romain Guyc39ed4a2012-06-12 12:06:46 -07001012 CopyOnWriteArray.Access<OnScrollChangedListener> access = listeners.start();
1013 try {
1014 int count = access.size();
1015 for (int i = 0; i < count; i++) {
1016 access.get(i).onScrollChanged();
1017 }
1018 } finally {
1019 listeners.end();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 }
1021 }
1022 }
1023
1024 /**
1025 * Returns whether there are listeners for computing internal insets.
1026 */
1027 final boolean hasComputeInternalInsetsListeners() {
Romain Guyc39ed4a2012-06-12 12:06:46 -07001028 final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
The Android Open Source Project10592532009-03-18 17:39:46 -07001029 mOnComputeInternalInsetsListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 return (listeners != null && listeners.size() > 0);
1031 }
Romain Guyc39ed4a2012-06-12 12:06:46 -07001032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 /**
1034 * Calls all listeners to compute the current insets.
1035 */
1036 final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001037 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
1038 // perform the dispatching. The iterator is a safe guard against listeners that
1039 // could mutate the list by calling the various add/remove methods. This prevents
1040 // the array from being modified while we iterate it.
Romain Guyc39ed4a2012-06-12 12:06:46 -07001041 final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
The Android Open Source Project10592532009-03-18 17:39:46 -07001042 mOnComputeInternalInsetsListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -07001043 if (listeners != null && listeners.size() > 0) {
Romain Guyc39ed4a2012-06-12 12:06:46 -07001044 CopyOnWriteArray.Access<OnComputeInternalInsetsListener> access = listeners.start();
1045 try {
1046 int count = access.size();
1047 for (int i = 0; i < count; i++) {
1048 access.get(i).onComputeInternalInsets(inoutInfo);
1049 }
1050 } finally {
1051 listeners.end();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 }
1053 }
1054 }
Romain Guyc39ed4a2012-06-12 12:06:46 -07001055
1056 /**
Filip Gruszczynski6eafa902014-11-14 14:24:37 -08001057 * @hide
1058 */
1059 public final void dispatchOnEnterAnimationComplete() {
1060 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
1061 // perform the dispatching. The iterator is a safe guard against listeners that
1062 // could mutate the list by calling the various add/remove methods. This prevents
1063 // the array from being modified while we iterate it.
1064 final CopyOnWriteArrayList<OnEnterAnimationCompleteListener> listeners =
1065 mOnEnterAnimationCompleteListeners;
1066 if (listeners != null && !listeners.isEmpty()) {
1067 for (OnEnterAnimationCompleteListener listener : listeners) {
1068 listener.onEnterAnimationComplete();
1069 }
1070 }
1071 }
1072
1073 /**
Romain Guyc39ed4a2012-06-12 12:06:46 -07001074 * Copy on write array. This array is not thread safe, and only one loop can
1075 * iterate over this array at any given time. This class avoids allocations
1076 * until a concurrent modification happens.
1077 *
1078 * Usage:
1079 *
1080 * CopyOnWriteArray.Access<MyData> access = array.start();
1081 * try {
1082 * for (int i = 0; i < access.size(); i++) {
1083 * MyData d = access.get(i);
1084 * }
1085 * } finally {
1086 * access.end();
1087 * }
1088 */
1089 static class CopyOnWriteArray<T> {
1090 private ArrayList<T> mData = new ArrayList<T>();
1091 private ArrayList<T> mDataCopy;
1092
1093 private final Access<T> mAccess = new Access<T>();
1094
1095 private boolean mStart;
1096
1097 static class Access<T> {
1098 private ArrayList<T> mData;
1099 private int mSize;
1100
1101 T get(int index) {
1102 return mData.get(index);
1103 }
1104
1105 int size() {
1106 return mSize;
1107 }
1108 }
1109
1110 CopyOnWriteArray() {
1111 }
1112
1113 private ArrayList<T> getArray() {
1114 if (mStart) {
1115 if (mDataCopy == null) mDataCopy = new ArrayList<T>(mData);
1116 return mDataCopy;
1117 }
1118 return mData;
1119 }
1120
1121 Access<T> start() {
1122 if (mStart) throw new IllegalStateException("Iteration already started");
1123 mStart = true;
1124 mDataCopy = null;
1125 mAccess.mData = mData;
1126 mAccess.mSize = mData.size();
1127 return mAccess;
1128 }
1129
1130 void end() {
1131 if (!mStart) throw new IllegalStateException("Iteration not started");
1132 mStart = false;
1133 if (mDataCopy != null) {
1134 mData = mDataCopy;
Chet Haasefc343962013-09-18 08:44:33 -07001135 mAccess.mData.clear();
1136 mAccess.mSize = 0;
Romain Guyc39ed4a2012-06-12 12:06:46 -07001137 }
1138 mDataCopy = null;
1139 }
1140
1141 int size() {
1142 return getArray().size();
1143 }
1144
1145 void add(T item) {
1146 getArray().add(item);
1147 }
1148
1149 void addAll(CopyOnWriteArray<T> array) {
1150 getArray().addAll(array.mData);
1151 }
1152
1153 void remove(T item) {
1154 getArray().remove(item);
1155 }
1156
1157 void clear() {
1158 getArray().clear();
1159 }
1160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161}