blob: db8717517e4896ecf938ab9c3ca49b4656988029 [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;
The Android Open Source Project10592532009-03-18 17:39:46 -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 {
The Android Open Source Project10592532009-03-18 17:39:46 -070035 private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
36 private CopyOnWriteArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
The Android Open Source Project10592532009-03-18 17:39:46 -070037 private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
38 private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
39 private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -070040 private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
42 private boolean mAlive = true;
43
44 /**
45 * Interface definition for a callback to be invoked when the focus state within
46 * the view tree changes.
47 */
48 public interface OnGlobalFocusChangeListener {
49 /**
50 * Callback method to be invoked when the focus changes in the view tree. When
51 * the view tree transitions from touch mode to non-touch mode, oldFocus is null.
52 * When the view tree transitions from non-touch mode to touch mode, newFocus is
53 * null. When focus changes in non-touch mode (without transition from or to
54 * touch mode) either oldFocus or newFocus can be null.
55 *
56 * @param oldFocus The previously focused view, if any.
57 * @param newFocus The newly focused View, if any.
58 */
59 public void onGlobalFocusChanged(View oldFocus, View newFocus);
60 }
61
62 /**
63 * Interface definition for a callback to be invoked when the global layout state
64 * or the visibility of views within the view tree changes.
65 */
66 public interface OnGlobalLayoutListener {
67 /**
68 * Callback method to be invoked when the global layout state or the visibility of views
69 * within the view tree changes
70 */
71 public void onGlobalLayout();
72 }
73
74 /**
75 * Interface definition for a callback to be invoked when the view tree is about to be drawn.
76 */
77 public interface OnPreDrawListener {
78 /**
79 * Callback method to be invoked when the view tree is about to be drawn. At this point, all
80 * views in the tree have been measured and given a frame. Clients can use this to adjust
81 * their scroll bounds or even to request a new layout before drawing occurs.
82 *
83 * @return Return true to proceed with the current drawing pass, or false to cancel.
84 *
85 * @see android.view.View#onMeasure
86 * @see android.view.View#onLayout
87 * @see android.view.View#onDraw
88 */
89 public boolean onPreDraw();
90 }
91
92 /**
93 * Interface definition for a callback to be invoked when the touch mode changes.
94 */
95 public interface OnTouchModeChangeListener {
96 /**
97 * Callback method to be invoked when the touch mode changes.
98 *
99 * @param isInTouchMode True if the view hierarchy is now in touch mode, false otherwise.
100 */
101 public void onTouchModeChanged(boolean isInTouchMode);
102 }
103
104 /**
105 * Interface definition for a callback to be invoked when
106 * something in the view tree has been scrolled.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 */
108 public interface OnScrollChangedListener {
109 /**
110 * Callback method to be invoked when something in the view tree
111 * has been scrolled.
112 */
113 public void onScrollChanged();
114 }
115
116 /**
117 * Parameters used with OnComputeInternalInsetsListener.
Dianne Hackborn935ae462009-04-13 16:11:55 -0700118 *
119 * We are not yet ready to commit to this API and support it, so
120 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 */
122 public final static class InternalInsetsInfo {
123 /**
124 * Offsets from the frame of the window at which the content of
125 * windows behind it should be placed.
126 */
127 public final Rect contentInsets = new Rect();
128
129 /**
Jeff Brownfbf09772011-01-16 14:06:57 -0800130 * Offsets from the frame of the window at which windows behind it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 * are visible.
132 */
133 public final Rect visibleInsets = new Rect();
Jeff Brownfbf09772011-01-16 14:06:57 -0800134
135 /**
136 * Touchable region defined relative to the origin of the frame of the window.
137 * Only used when {@link #setTouchableInsets(int)} is called with
138 * the option {@link #TOUCHABLE_INSETS_REGION}.
139 */
140 public final Region touchableRegion = new Region();
141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 /**
143 * Option for {@link #setTouchableInsets(int)}: the entire window frame
144 * can be touched.
145 */
146 public static final int TOUCHABLE_INSETS_FRAME = 0;
147
148 /**
149 * Option for {@link #setTouchableInsets(int)}: the area inside of
150 * the content insets can be touched.
151 */
152 public static final int TOUCHABLE_INSETS_CONTENT = 1;
153
154 /**
155 * Option for {@link #setTouchableInsets(int)}: the area inside of
156 * the visible insets can be touched.
157 */
158 public static final int TOUCHABLE_INSETS_VISIBLE = 2;
Jeff Brownfbf09772011-01-16 14:06:57 -0800159
160 /**
161 * Option for {@link #setTouchableInsets(int)}: the area inside of
162 * the provided touchable region in {@link #touchableRegion} can be touched.
163 */
164 public static final int TOUCHABLE_INSETS_REGION = 3;
165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 /**
167 * Set which parts of the window can be touched: either
168 * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
Jeff Brownfbf09772011-01-16 14:06:57 -0800169 * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 */
171 public void setTouchableInsets(int val) {
172 mTouchableInsets = val;
173 }
174
175 public int getTouchableInsets() {
176 return mTouchableInsets;
177 }
178
179 int mTouchableInsets;
180
181 void reset() {
Jeff Brownfbf09772011-01-16 14:06:57 -0800182 contentInsets.setEmpty();
183 visibleInsets.setEmpty();
184 touchableRegion.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 mTouchableInsets = TOUCHABLE_INSETS_FRAME;
186 }
187
188 @Override public boolean equals(Object o) {
189 try {
190 if (o == null) {
191 return false;
192 }
193 InternalInsetsInfo other = (InternalInsetsInfo)o;
Jeff Brownfbf09772011-01-16 14:06:57 -0800194 if (mTouchableInsets != other.mTouchableInsets) {
195 return false;
196 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 if (!contentInsets.equals(other.contentInsets)) {
198 return false;
199 }
200 if (!visibleInsets.equals(other.visibleInsets)) {
201 return false;
202 }
Jeff Brownfbf09772011-01-16 14:06:57 -0800203 return touchableRegion.equals(other.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 } catch (ClassCastException e) {
205 return false;
206 }
207 }
208
209 void set(InternalInsetsInfo other) {
210 contentInsets.set(other.contentInsets);
211 visibleInsets.set(other.visibleInsets);
Jeff Brownfbf09772011-01-16 14:06:57 -0800212 touchableRegion.set(other.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 mTouchableInsets = other.mTouchableInsets;
214 }
215 }
216
217 /**
218 * Interface definition for a callback to be invoked when layout has
219 * completed and the client can compute its interior insets.
Dianne Hackborn935ae462009-04-13 16:11:55 -0700220 *
221 * We are not yet ready to commit to this API and support it, so
222 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 */
224 public interface OnComputeInternalInsetsListener {
225 /**
226 * Callback method to be invoked when layout has completed and the
227 * client can compute its interior insets.
228 *
229 * @param inoutInfo Should be filled in by the implementation with
230 * the information about the insets of the window. This is called
231 * with whatever values the previous OnComputeInternalInsetsListener
232 * returned, if there are multiple such listeners in the window.
233 */
234 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo);
235 }
236
237 /**
238 * Creates a new ViewTreeObserver. This constructor should not be called
239 */
240 ViewTreeObserver() {
241 }
242
243 /**
244 * Merges all the listeners registered on the specified observer with the listeners
245 * registered on this object. After this method is invoked, the specified observer
246 * will return false in {@link #isAlive()} and should not be used anymore.
247 *
248 * @param observer The ViewTreeObserver whose listeners must be added to this observer
249 */
250 void merge(ViewTreeObserver observer) {
251 if (observer.mOnGlobalFocusListeners != null) {
252 if (mOnGlobalFocusListeners != null) {
253 mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners);
254 } else {
255 mOnGlobalFocusListeners = observer.mOnGlobalFocusListeners;
256 }
257 }
258
259 if (observer.mOnGlobalLayoutListeners != null) {
260 if (mOnGlobalLayoutListeners != null) {
261 mOnGlobalLayoutListeners.addAll(observer.mOnGlobalLayoutListeners);
262 } else {
263 mOnGlobalLayoutListeners = observer.mOnGlobalLayoutListeners;
264 }
265 }
266
267 if (observer.mOnPreDrawListeners != null) {
268 if (mOnPreDrawListeners != null) {
269 mOnPreDrawListeners.addAll(observer.mOnPreDrawListeners);
270 } else {
271 mOnPreDrawListeners = observer.mOnPreDrawListeners;
272 }
273 }
274
275 if (observer.mOnTouchModeChangeListeners != null) {
276 if (mOnTouchModeChangeListeners != null) {
277 mOnTouchModeChangeListeners.addAll(observer.mOnTouchModeChangeListeners);
278 } else {
279 mOnTouchModeChangeListeners = observer.mOnTouchModeChangeListeners;
280 }
281 }
282
283 if (observer.mOnComputeInternalInsetsListeners != null) {
284 if (mOnComputeInternalInsetsListeners != null) {
285 mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners);
286 } else {
287 mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners;
288 }
289 }
290
291 observer.kill();
292 }
293
294 /**
295 * Register a callback to be invoked when the focus state within the view tree changes.
296 *
297 * @param listener The callback to add
298 *
299 * @throws IllegalStateException If {@link #isAlive()} returns false
300 */
301 public void addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener listener) {
302 checkIsAlive();
303
304 if (mOnGlobalFocusListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700305 mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 }
307
308 mOnGlobalFocusListeners.add(listener);
309 }
310
311 /**
312 * Remove a previously installed focus change callback.
313 *
314 * @param victim The callback to remove
315 *
316 * @throws IllegalStateException If {@link #isAlive()} returns false
317 *
318 * @see #addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener)
319 */
320 public void removeOnGlobalFocusChangeListener(OnGlobalFocusChangeListener victim) {
321 checkIsAlive();
322 if (mOnGlobalFocusListeners == null) {
323 return;
324 }
325 mOnGlobalFocusListeners.remove(victim);
326 }
327
328 /**
329 * Register a callback to be invoked when the global layout state or the visibility of views
330 * within the view tree changes
331 *
332 * @param listener The callback to add
333 *
334 * @throws IllegalStateException If {@link #isAlive()} returns false
335 */
336 public void addOnGlobalLayoutListener(OnGlobalLayoutListener listener) {
337 checkIsAlive();
338
339 if (mOnGlobalLayoutListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700340 mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 }
342
343 mOnGlobalLayoutListeners.add(listener);
344 }
345
346 /**
347 * Remove a previously installed global layout callback
348 *
349 * @param victim The callback to remove
350 *
351 * @throws IllegalStateException If {@link #isAlive()} returns false
352 *
353 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
354 */
355 public void removeGlobalOnLayoutListener(OnGlobalLayoutListener victim) {
356 checkIsAlive();
357 if (mOnGlobalLayoutListeners == null) {
358 return;
359 }
360 mOnGlobalLayoutListeners.remove(victim);
361 }
362
363 /**
364 * Register a callback to be invoked when the view tree is about to be drawn
365 *
366 * @param listener The callback to add
367 *
368 * @throws IllegalStateException If {@link #isAlive()} returns false
369 */
370 public void addOnPreDrawListener(OnPreDrawListener listener) {
371 checkIsAlive();
372
373 if (mOnPreDrawListeners == null) {
Chet Haase6e0ecb42010-11-03 19:41:18 -0700374 mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
376
377 mOnPreDrawListeners.add(listener);
378 }
379
380 /**
381 * Remove a previously installed pre-draw callback
382 *
383 * @param victim The callback to remove
384 *
385 * @throws IllegalStateException If {@link #isAlive()} returns false
386 *
387 * @see #addOnPreDrawListener(OnPreDrawListener)
388 */
389 public void removeOnPreDrawListener(OnPreDrawListener victim) {
390 checkIsAlive();
391 if (mOnPreDrawListeners == null) {
392 return;
393 }
394 mOnPreDrawListeners.remove(victim);
395 }
396
397 /**
398 * Register a callback to be invoked when a view has been scrolled.
399 *
400 * @param listener The callback to add
401 *
402 * @throws IllegalStateException If {@link #isAlive()} returns false
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 */
404 public void addOnScrollChangedListener(OnScrollChangedListener listener) {
405 checkIsAlive();
406
407 if (mOnScrollChangedListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700408 mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 }
410
411 mOnScrollChangedListeners.add(listener);
412 }
413
414 /**
415 * Remove a previously installed scroll-changed callback
416 *
417 * @param victim The callback to remove
418 *
419 * @throws IllegalStateException If {@link #isAlive()} returns false
420 *
421 * @see #addOnScrollChangedListener(OnScrollChangedListener)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 */
423 public void removeOnScrollChangedListener(OnScrollChangedListener victim) {
424 checkIsAlive();
425 if (mOnScrollChangedListeners == null) {
426 return;
427 }
428 mOnScrollChangedListeners.remove(victim);
429 }
430
431 /**
432 * Register a callback to be invoked when the invoked when the touch mode changes.
433 *
434 * @param listener The callback to add
435 *
436 * @throws IllegalStateException If {@link #isAlive()} returns false
437 */
438 public void addOnTouchModeChangeListener(OnTouchModeChangeListener listener) {
439 checkIsAlive();
440
441 if (mOnTouchModeChangeListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700442 mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 }
444
445 mOnTouchModeChangeListeners.add(listener);
446 }
447
448 /**
449 * Remove a previously installed touch mode change callback
450 *
451 * @param victim The callback to remove
452 *
453 * @throws IllegalStateException If {@link #isAlive()} returns false
454 *
455 * @see #addOnTouchModeChangeListener(OnTouchModeChangeListener)
456 */
457 public void removeOnTouchModeChangeListener(OnTouchModeChangeListener victim) {
458 checkIsAlive();
459 if (mOnTouchModeChangeListeners == null) {
460 return;
461 }
462 mOnTouchModeChangeListeners.remove(victim);
463 }
464
465 /**
466 * Register a callback to be invoked when the invoked when it is time to
467 * compute the window's internal insets.
468 *
469 * @param listener The callback to add
470 *
471 * @throws IllegalStateException If {@link #isAlive()} returns false
Dianne Hackborn935ae462009-04-13 16:11:55 -0700472 *
473 * We are not yet ready to commit to this API and support it, so
474 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 */
476 public void addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener listener) {
477 checkIsAlive();
478
479 if (mOnComputeInternalInsetsListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700480 mOnComputeInternalInsetsListeners =
481 new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 }
483
484 mOnComputeInternalInsetsListeners.add(listener);
485 }
486
487 /**
488 * Remove a previously installed internal insets computation callback
489 *
490 * @param victim The callback to remove
491 *
492 * @throws IllegalStateException If {@link #isAlive()} returns false
493 *
494 * @see #addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener)
Dianne Hackborn935ae462009-04-13 16:11:55 -0700495 *
496 * We are not yet ready to commit to this API and support it, so
497 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 */
499 public void removeOnComputeInternalInsetsListener(OnComputeInternalInsetsListener victim) {
500 checkIsAlive();
501 if (mOnComputeInternalInsetsListeners == null) {
502 return;
503 }
504 mOnComputeInternalInsetsListeners.remove(victim);
505 }
506
507 private void checkIsAlive() {
508 if (!mAlive) {
509 throw new IllegalStateException("This ViewTreeObserver is not alive, call "
510 + "getViewTreeObserver() again");
511 }
512 }
513
514 /**
515 * Indicates whether this ViewTreeObserver is alive. When an observer is not alive,
516 * any call to a method (except this one) will throw an exception.
517 *
518 * If an application keeps a long-lived reference to this ViewTreeObserver, it should
519 * always check for the result of this method before calling any other method.
520 *
521 * @return True if this object is alive and be used, false otherwise.
522 */
523 public boolean isAlive() {
524 return mAlive;
525 }
526
527 /**
528 * Marks this ViewTreeObserver as not alive. After invoking this method, invoking
529 * any other method but {@link #isAlive()} and {@link #kill()} will throw an Exception.
530 *
531 * @hide
532 */
533 private void kill() {
534 mAlive = false;
535 }
536
537 /**
538 * Notifies registered listeners that focus has changed.
539 */
540 final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700541 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
542 // perform the dispatching. The iterator is a safe guard against listeners that
543 // could mutate the list by calling the various add/remove methods. This prevents
544 // the array from being modified while we iterate it.
545 final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700546 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700547 for (OnGlobalFocusChangeListener listener : listeners) {
548 listener.onGlobalFocusChanged(oldFocus, newFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 }
550 }
551 }
552
553 /**
554 * Notifies registered listeners that a global layout happened. This can be called
555 * manually if you are forcing a layout on a View or a hierarchy of Views that are
556 * not attached to a Window or in the GONE state.
557 */
558 public final void dispatchOnGlobalLayout() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700559 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
560 // perform the dispatching. The iterator is a safe guard against listeners that
561 // could mutate the list by calling the various add/remove methods. This prevents
562 // the array from being modified while we iterate it.
563 final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700564 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700565 for (OnGlobalLayoutListener listener : listeners) {
566 listener.onGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568 }
569 }
570
571 /**
572 * Notifies registered listeners that the drawing pass is about to start. If a
573 * listener returns true, then the drawing pass is canceled and rescheduled. This can
574 * be called manually if you are forcing the drawing on a View or a hierarchy of Views
575 * that are not attached to a Window or in the GONE state.
576 *
577 * @return True if the current draw should be canceled and resceduled, false otherwise.
578 */
579 public final boolean dispatchOnPreDraw() {
Chet Haase6e0ecb42010-11-03 19:41:18 -0700580 // NOTE: we *must* clone the listener list to perform the dispatching.
581 // The clone is a safe guard against listeners that
The Android Open Source Project10592532009-03-18 17:39:46 -0700582 // could mutate the list by calling the various add/remove methods. This prevents
Chet Haase6e0ecb42010-11-03 19:41:18 -0700583 // the array from being modified while we process it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 boolean cancelDraw = false;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700585 if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
586 final ArrayList<OnPreDrawListener> listeners =
587 (ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
588 int numListeners = listeners.size();
589 for (int i = 0; i < numListeners; ++i) {
590 cancelDraw |= !(listeners.get(i).onPreDraw());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 }
592 }
593 return cancelDraw;
594 }
595
596 /**
597 * Notifies registered listeners that the touch mode has changed.
598 *
599 * @param inTouchMode True if the touch mode is now enabled, false otherwise.
600 */
601 final void dispatchOnTouchModeChanged(boolean inTouchMode) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700602 final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
603 mOnTouchModeChangeListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700604 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700605 for (OnTouchModeChangeListener listener : listeners) {
606 listener.onTouchModeChanged(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 }
608 }
609 }
610
611 /**
612 * Notifies registered listeners that something has scrolled.
613 */
614 final void dispatchOnScrollChanged() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700615 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
616 // perform the dispatching. The iterator is a safe guard against listeners that
617 // could mutate the list by calling the various add/remove methods. This prevents
618 // the array from being modified while we iterate it.
619 final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700620 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700621 for (OnScrollChangedListener listener : listeners) {
622 listener.onScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 }
624 }
625 }
626
627 /**
628 * Returns whether there are listeners for computing internal insets.
629 */
630 final boolean hasComputeInternalInsetsListeners() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700631 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
632 mOnComputeInternalInsetsListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 return (listeners != null && listeners.size() > 0);
634 }
635
636 /**
637 * Calls all listeners to compute the current insets.
638 */
639 final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700640 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
641 // perform the dispatching. The iterator is a safe guard against listeners that
642 // could mutate the list by calling the various add/remove methods. This prevents
643 // the array from being modified while we iterate it.
644 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
645 mOnComputeInternalInsetsListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700646 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700647 for (OnComputeInternalInsetsListener listener : listeners) {
648 listener.onComputeInternalInsets(inoutInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 }
650 }
651 }
652}