blob: 7fd33894973d4c0a9ca2f3a8580bb55205357570 [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
Romain Guy1e878d22012-01-23 15:34:25 -0800188 @Override
189 public boolean equals(Object o) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 try {
191 if (o == null) {
192 return false;
193 }
194 InternalInsetsInfo other = (InternalInsetsInfo)o;
Jeff Brownfbf09772011-01-16 14:06:57 -0800195 if (mTouchableInsets != other.mTouchableInsets) {
196 return false;
197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 if (!contentInsets.equals(other.contentInsets)) {
199 return false;
200 }
201 if (!visibleInsets.equals(other.visibleInsets)) {
202 return false;
203 }
Jeff Brownfbf09772011-01-16 14:06:57 -0800204 return touchableRegion.equals(other.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 } catch (ClassCastException e) {
206 return false;
207 }
208 }
209
210 void set(InternalInsetsInfo other) {
211 contentInsets.set(other.contentInsets);
212 visibleInsets.set(other.visibleInsets);
Jeff Brownfbf09772011-01-16 14:06:57 -0800213 touchableRegion.set(other.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 mTouchableInsets = other.mTouchableInsets;
215 }
216 }
217
218 /**
219 * Interface definition for a callback to be invoked when layout has
220 * completed and the client can compute its interior insets.
Dianne Hackborn935ae462009-04-13 16:11:55 -0700221 *
222 * We are not yet ready to commit to this API and support it, so
223 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 */
225 public interface OnComputeInternalInsetsListener {
226 /**
227 * Callback method to be invoked when layout has completed and the
228 * client can compute its interior insets.
229 *
230 * @param inoutInfo Should be filled in by the implementation with
231 * the information about the insets of the window. This is called
232 * with whatever values the previous OnComputeInternalInsetsListener
233 * returned, if there are multiple such listeners in the window.
234 */
235 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo);
236 }
237
238 /**
239 * Creates a new ViewTreeObserver. This constructor should not be called
240 */
241 ViewTreeObserver() {
242 }
243
244 /**
245 * Merges all the listeners registered on the specified observer with the listeners
246 * registered on this object. After this method is invoked, the specified observer
247 * will return false in {@link #isAlive()} and should not be used anymore.
248 *
249 * @param observer The ViewTreeObserver whose listeners must be added to this observer
250 */
251 void merge(ViewTreeObserver observer) {
252 if (observer.mOnGlobalFocusListeners != null) {
253 if (mOnGlobalFocusListeners != null) {
254 mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners);
255 } else {
256 mOnGlobalFocusListeners = observer.mOnGlobalFocusListeners;
257 }
258 }
259
260 if (observer.mOnGlobalLayoutListeners != null) {
261 if (mOnGlobalLayoutListeners != null) {
262 mOnGlobalLayoutListeners.addAll(observer.mOnGlobalLayoutListeners);
263 } else {
264 mOnGlobalLayoutListeners = observer.mOnGlobalLayoutListeners;
265 }
266 }
267
268 if (observer.mOnPreDrawListeners != null) {
269 if (mOnPreDrawListeners != null) {
270 mOnPreDrawListeners.addAll(observer.mOnPreDrawListeners);
271 } else {
272 mOnPreDrawListeners = observer.mOnPreDrawListeners;
273 }
274 }
275
276 if (observer.mOnTouchModeChangeListeners != null) {
277 if (mOnTouchModeChangeListeners != null) {
278 mOnTouchModeChangeListeners.addAll(observer.mOnTouchModeChangeListeners);
279 } else {
280 mOnTouchModeChangeListeners = observer.mOnTouchModeChangeListeners;
281 }
282 }
283
284 if (observer.mOnComputeInternalInsetsListeners != null) {
285 if (mOnComputeInternalInsetsListeners != null) {
286 mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners);
287 } else {
288 mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners;
289 }
290 }
291
Mark Brophy757c6972011-10-25 17:01:28 +0100292 if (observer.mOnScrollChangedListeners != null) {
293 if (mOnScrollChangedListeners != null) {
294 mOnScrollChangedListeners.addAll(observer.mOnScrollChangedListeners);
295 } else {
296 mOnScrollChangedListeners = observer.mOnScrollChangedListeners;
297 }
298 }
299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 observer.kill();
301 }
302
303 /**
304 * Register a callback to be invoked when the focus state within the view tree changes.
305 *
306 * @param listener The callback to add
307 *
308 * @throws IllegalStateException If {@link #isAlive()} returns false
309 */
310 public void addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener listener) {
311 checkIsAlive();
312
313 if (mOnGlobalFocusListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700314 mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316
317 mOnGlobalFocusListeners.add(listener);
318 }
319
320 /**
321 * Remove a previously installed focus change callback.
322 *
323 * @param victim The callback to remove
324 *
325 * @throws IllegalStateException If {@link #isAlive()} returns false
326 *
327 * @see #addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener)
328 */
329 public void removeOnGlobalFocusChangeListener(OnGlobalFocusChangeListener victim) {
330 checkIsAlive();
331 if (mOnGlobalFocusListeners == null) {
332 return;
333 }
334 mOnGlobalFocusListeners.remove(victim);
335 }
336
337 /**
338 * Register a callback to be invoked when the global layout state or the visibility of views
339 * within the view tree changes
340 *
341 * @param listener The callback to add
342 *
343 * @throws IllegalStateException If {@link #isAlive()} returns false
344 */
345 public void addOnGlobalLayoutListener(OnGlobalLayoutListener listener) {
346 checkIsAlive();
347
348 if (mOnGlobalLayoutListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700349 mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 }
351
352 mOnGlobalLayoutListeners.add(listener);
353 }
354
355 /**
356 * Remove a previously installed global layout callback
357 *
358 * @param victim The callback to remove
359 *
360 * @throws IllegalStateException If {@link #isAlive()} returns false
Romain Guy1e878d22012-01-23 15:34:25 -0800361 *
362 * @deprecated Use #removeOnGlobalLayoutListener instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 *
364 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
365 */
Romain Guy1e878d22012-01-23 15:34:25 -0800366 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 public void removeGlobalOnLayoutListener(OnGlobalLayoutListener victim) {
Romain Guy1e878d22012-01-23 15:34:25 -0800368 removeOnGlobalLayoutListener(victim);
369 }
370
371 /**
372 * Remove a previously installed global layout callback
373 *
374 * @param victim The callback to remove
375 *
376 * @throws IllegalStateException If {@link #isAlive()} returns false
377 *
378 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
379 */
380 public void removeOnGlobalLayoutListener(OnGlobalLayoutListener victim) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 checkIsAlive();
382 if (mOnGlobalLayoutListeners == null) {
383 return;
384 }
385 mOnGlobalLayoutListeners.remove(victim);
386 }
387
388 /**
389 * Register a callback to be invoked when the view tree is about to be drawn
390 *
391 * @param listener The callback to add
392 *
393 * @throws IllegalStateException If {@link #isAlive()} returns false
394 */
395 public void addOnPreDrawListener(OnPreDrawListener listener) {
396 checkIsAlive();
397
398 if (mOnPreDrawListeners == null) {
Chet Haase6e0ecb42010-11-03 19:41:18 -0700399 mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 }
401
402 mOnPreDrawListeners.add(listener);
403 }
404
405 /**
406 * Remove a previously installed pre-draw callback
407 *
408 * @param victim The callback to remove
409 *
410 * @throws IllegalStateException If {@link #isAlive()} returns false
411 *
412 * @see #addOnPreDrawListener(OnPreDrawListener)
413 */
414 public void removeOnPreDrawListener(OnPreDrawListener victim) {
415 checkIsAlive();
416 if (mOnPreDrawListeners == null) {
417 return;
418 }
419 mOnPreDrawListeners.remove(victim);
420 }
421
422 /**
423 * Register a callback to be invoked when a view has been scrolled.
424 *
425 * @param listener The callback to add
426 *
427 * @throws IllegalStateException If {@link #isAlive()} returns false
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 */
429 public void addOnScrollChangedListener(OnScrollChangedListener listener) {
430 checkIsAlive();
431
432 if (mOnScrollChangedListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700433 mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 }
435
436 mOnScrollChangedListeners.add(listener);
437 }
438
439 /**
440 * Remove a previously installed scroll-changed callback
441 *
442 * @param victim The callback to remove
443 *
444 * @throws IllegalStateException If {@link #isAlive()} returns false
445 *
446 * @see #addOnScrollChangedListener(OnScrollChangedListener)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 */
448 public void removeOnScrollChangedListener(OnScrollChangedListener victim) {
449 checkIsAlive();
450 if (mOnScrollChangedListeners == null) {
451 return;
452 }
453 mOnScrollChangedListeners.remove(victim);
454 }
455
456 /**
457 * Register a callback to be invoked when the invoked when the touch mode changes.
458 *
459 * @param listener The callback to add
460 *
461 * @throws IllegalStateException If {@link #isAlive()} returns false
462 */
463 public void addOnTouchModeChangeListener(OnTouchModeChangeListener listener) {
464 checkIsAlive();
465
466 if (mOnTouchModeChangeListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700467 mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 }
469
470 mOnTouchModeChangeListeners.add(listener);
471 }
472
473 /**
474 * Remove a previously installed touch mode change callback
475 *
476 * @param victim The callback to remove
477 *
478 * @throws IllegalStateException If {@link #isAlive()} returns false
479 *
480 * @see #addOnTouchModeChangeListener(OnTouchModeChangeListener)
481 */
482 public void removeOnTouchModeChangeListener(OnTouchModeChangeListener victim) {
483 checkIsAlive();
484 if (mOnTouchModeChangeListeners == null) {
485 return;
486 }
487 mOnTouchModeChangeListeners.remove(victim);
488 }
489
490 /**
491 * Register a callback to be invoked when the invoked when it is time to
492 * compute the window's internal insets.
493 *
494 * @param listener The callback to add
495 *
496 * @throws IllegalStateException If {@link #isAlive()} returns false
Dianne Hackborn935ae462009-04-13 16:11:55 -0700497 *
498 * We are not yet ready to commit to this API and support it, so
499 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 */
501 public void addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener listener) {
502 checkIsAlive();
503
504 if (mOnComputeInternalInsetsListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700505 mOnComputeInternalInsetsListeners =
506 new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 }
508
509 mOnComputeInternalInsetsListeners.add(listener);
510 }
511
512 /**
513 * Remove a previously installed internal insets computation callback
514 *
515 * @param victim The callback to remove
516 *
517 * @throws IllegalStateException If {@link #isAlive()} returns false
518 *
519 * @see #addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener)
Dianne Hackborn935ae462009-04-13 16:11:55 -0700520 *
521 * We are not yet ready to commit to this API and support it, so
522 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 */
524 public void removeOnComputeInternalInsetsListener(OnComputeInternalInsetsListener victim) {
525 checkIsAlive();
526 if (mOnComputeInternalInsetsListeners == null) {
527 return;
528 }
529 mOnComputeInternalInsetsListeners.remove(victim);
530 }
531
532 private void checkIsAlive() {
533 if (!mAlive) {
534 throw new IllegalStateException("This ViewTreeObserver is not alive, call "
535 + "getViewTreeObserver() again");
536 }
537 }
538
539 /**
540 * Indicates whether this ViewTreeObserver is alive. When an observer is not alive,
541 * any call to a method (except this one) will throw an exception.
542 *
543 * If an application keeps a long-lived reference to this ViewTreeObserver, it should
544 * always check for the result of this method before calling any other method.
545 *
546 * @return True if this object is alive and be used, false otherwise.
547 */
548 public boolean isAlive() {
549 return mAlive;
550 }
551
552 /**
553 * Marks this ViewTreeObserver as not alive. After invoking this method, invoking
554 * any other method but {@link #isAlive()} and {@link #kill()} will throw an Exception.
555 *
556 * @hide
557 */
558 private void kill() {
559 mAlive = false;
560 }
561
562 /**
563 * Notifies registered listeners that focus has changed.
564 */
565 final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700566 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
567 // perform the dispatching. The iterator is a safe guard against listeners that
568 // could mutate the list by calling the various add/remove methods. This prevents
569 // the array from being modified while we iterate it.
570 final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700571 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700572 for (OnGlobalFocusChangeListener listener : listeners) {
573 listener.onGlobalFocusChanged(oldFocus, newFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 }
575 }
576 }
577
578 /**
579 * Notifies registered listeners that a global layout happened. This can be called
580 * manually if you are forcing a layout on a View or a hierarchy of Views that are
581 * not attached to a Window or in the GONE state.
582 */
583 public final void dispatchOnGlobalLayout() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700584 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
585 // perform the dispatching. The iterator is a safe guard against listeners that
586 // could mutate the list by calling the various add/remove methods. This prevents
587 // the array from being modified while we iterate it.
588 final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700589 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700590 for (OnGlobalLayoutListener listener : listeners) {
591 listener.onGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 }
593 }
594 }
595
596 /**
597 * Notifies registered listeners that the drawing pass is about to start. If a
598 * listener returns true, then the drawing pass is canceled and rescheduled. This can
599 * be called manually if you are forcing the drawing on a View or a hierarchy of Views
600 * that are not attached to a Window or in the GONE state.
601 *
602 * @return True if the current draw should be canceled and resceduled, false otherwise.
603 */
604 public final boolean dispatchOnPreDraw() {
Chet Haase6e0ecb42010-11-03 19:41:18 -0700605 // NOTE: we *must* clone the listener list to perform the dispatching.
606 // The clone is a safe guard against listeners that
The Android Open Source Project10592532009-03-18 17:39:46 -0700607 // could mutate the list by calling the various add/remove methods. This prevents
Chet Haase6e0ecb42010-11-03 19:41:18 -0700608 // the array from being modified while we process it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 boolean cancelDraw = false;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700610 if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
611 final ArrayList<OnPreDrawListener> listeners =
612 (ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
613 int numListeners = listeners.size();
614 for (int i = 0; i < numListeners; ++i) {
615 cancelDraw |= !(listeners.get(i).onPreDraw());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 }
617 }
618 return cancelDraw;
619 }
620
621 /**
622 * Notifies registered listeners that the touch mode has changed.
623 *
624 * @param inTouchMode True if the touch mode is now enabled, false otherwise.
625 */
626 final void dispatchOnTouchModeChanged(boolean inTouchMode) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700627 final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
628 mOnTouchModeChangeListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700629 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700630 for (OnTouchModeChangeListener listener : listeners) {
631 listener.onTouchModeChanged(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 }
633 }
634 }
635
636 /**
637 * Notifies registered listeners that something has scrolled.
638 */
639 final void dispatchOnScrollChanged() {
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<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700645 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700646 for (OnScrollChangedListener listener : listeners) {
647 listener.onScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 }
649 }
650 }
651
652 /**
653 * Returns whether there are listeners for computing internal insets.
654 */
655 final boolean hasComputeInternalInsetsListeners() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700656 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
657 mOnComputeInternalInsetsListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 return (listeners != null && listeners.size() > 0);
659 }
660
661 /**
662 * Calls all listeners to compute the current insets.
663 */
664 final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700665 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
666 // perform the dispatching. The iterator is a safe guard against listeners that
667 // could mutate the list by calling the various add/remove methods. This prevents
668 // the array from being modified while we iterate it.
669 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
670 mOnComputeInternalInsetsListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700671 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700672 for (OnComputeInternalInsetsListener listener : listeners) {
673 listener.onComputeInternalInsets(inoutInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 }
675 }
676 }
677}