blob: 06a0fa6eb8eefb583c459303fd1818ae7cb4a4b1 [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;
20
Chet Haase6e0ecb42010-11-03 19:41:18 -070021import java.util.ArrayList;
The Android Open Source Project10592532009-03-18 17:39:46 -070022import java.util.concurrent.CopyOnWriteArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
24/**
25 * A view tree observer is used to register listeners that can be notified of global
26 * changes in the view tree. Such global events include, but are not limited to,
27 * layout of the whole tree, beginning of the drawing pass, touch mode change....
28 *
29 * A ViewTreeObserver should never be instantiated by applications as it is provided
30 * by the views hierarchy. Refer to {@link android.view.View#getViewTreeObserver()}
31 * for more information.
32 */
33public final class ViewTreeObserver {
The Android Open Source Project10592532009-03-18 17:39:46 -070034 private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
35 private CopyOnWriteArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
The Android Open Source Project10592532009-03-18 17:39:46 -070036 private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
37 private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
38 private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -070039 private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
41 private boolean mAlive = true;
42
43 /**
44 * Interface definition for a callback to be invoked when the focus state within
45 * the view tree changes.
46 */
47 public interface OnGlobalFocusChangeListener {
48 /**
49 * Callback method to be invoked when the focus changes in the view tree. When
50 * the view tree transitions from touch mode to non-touch mode, oldFocus is null.
51 * When the view tree transitions from non-touch mode to touch mode, newFocus is
52 * null. When focus changes in non-touch mode (without transition from or to
53 * touch mode) either oldFocus or newFocus can be null.
54 *
55 * @param oldFocus The previously focused view, if any.
56 * @param newFocus The newly focused View, if any.
57 */
58 public void onGlobalFocusChanged(View oldFocus, View newFocus);
59 }
60
61 /**
62 * Interface definition for a callback to be invoked when the global layout state
63 * or the visibility of views within the view tree changes.
64 */
65 public interface OnGlobalLayoutListener {
66 /**
67 * Callback method to be invoked when the global layout state or the visibility of views
68 * within the view tree changes
69 */
70 public void onGlobalLayout();
71 }
72
73 /**
74 * Interface definition for a callback to be invoked when the view tree is about to be drawn.
75 */
76 public interface OnPreDrawListener {
77 /**
78 * Callback method to be invoked when the view tree is about to be drawn. At this point, all
79 * views in the tree have been measured and given a frame. Clients can use this to adjust
80 * their scroll bounds or even to request a new layout before drawing occurs.
81 *
82 * @return Return true to proceed with the current drawing pass, or false to cancel.
83 *
84 * @see android.view.View#onMeasure
85 * @see android.view.View#onLayout
86 * @see android.view.View#onDraw
87 */
88 public boolean onPreDraw();
89 }
90
91 /**
92 * Interface definition for a callback to be invoked when the touch mode changes.
93 */
94 public interface OnTouchModeChangeListener {
95 /**
96 * Callback method to be invoked when the touch mode changes.
97 *
98 * @param isInTouchMode True if the view hierarchy is now in touch mode, false otherwise.
99 */
100 public void onTouchModeChanged(boolean isInTouchMode);
101 }
102
103 /**
104 * Interface definition for a callback to be invoked when
105 * something in the view tree has been scrolled.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 */
107 public interface OnScrollChangedListener {
108 /**
109 * Callback method to be invoked when something in the view tree
110 * has been scrolled.
111 */
112 public void onScrollChanged();
113 }
114
115 /**
116 * Parameters used with OnComputeInternalInsetsListener.
Dianne Hackborn935ae462009-04-13 16:11:55 -0700117 *
118 * We are not yet ready to commit to this API and support it, so
119 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 */
121 public final static class InternalInsetsInfo {
122 /**
123 * Offsets from the frame of the window at which the content of
124 * windows behind it should be placed.
125 */
126 public final Rect contentInsets = new Rect();
127
128 /**
129 * Offsets from the fram of the window at which windows behind it
130 * are visible.
131 */
132 public final Rect visibleInsets = new Rect();
133
134 /**
135 * Option for {@link #setTouchableInsets(int)}: the entire window frame
136 * can be touched.
137 */
138 public static final int TOUCHABLE_INSETS_FRAME = 0;
139
140 /**
141 * Option for {@link #setTouchableInsets(int)}: the area inside of
142 * the content insets can be touched.
143 */
144 public static final int TOUCHABLE_INSETS_CONTENT = 1;
145
146 /**
147 * Option for {@link #setTouchableInsets(int)}: the area inside of
148 * the visible insets can be touched.
149 */
150 public static final int TOUCHABLE_INSETS_VISIBLE = 2;
151
152 /**
153 * Set which parts of the window can be touched: either
154 * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
155 * or {@link #TOUCHABLE_INSETS_VISIBLE}.
156 */
157 public void setTouchableInsets(int val) {
158 mTouchableInsets = val;
159 }
160
161 public int getTouchableInsets() {
162 return mTouchableInsets;
163 }
164
165 int mTouchableInsets;
166
167 void reset() {
168 final Rect givenContent = contentInsets;
169 final Rect givenVisible = visibleInsets;
170 givenContent.left = givenContent.top = givenContent.right
171 = givenContent.bottom = givenVisible.left = givenVisible.top
172 = givenVisible.right = givenVisible.bottom = 0;
173 mTouchableInsets = TOUCHABLE_INSETS_FRAME;
174 }
175
176 @Override public boolean equals(Object o) {
177 try {
178 if (o == null) {
179 return false;
180 }
181 InternalInsetsInfo other = (InternalInsetsInfo)o;
182 if (!contentInsets.equals(other.contentInsets)) {
183 return false;
184 }
185 if (!visibleInsets.equals(other.visibleInsets)) {
186 return false;
187 }
188 return mTouchableInsets == other.mTouchableInsets;
189 } catch (ClassCastException e) {
190 return false;
191 }
192 }
193
194 void set(InternalInsetsInfo other) {
195 contentInsets.set(other.contentInsets);
196 visibleInsets.set(other.visibleInsets);
197 mTouchableInsets = other.mTouchableInsets;
198 }
199 }
200
201 /**
202 * Interface definition for a callback to be invoked when layout has
203 * completed and the client can compute its interior insets.
Dianne Hackborn935ae462009-04-13 16:11:55 -0700204 *
205 * We are not yet ready to commit to this API and support it, so
206 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 */
208 public interface OnComputeInternalInsetsListener {
209 /**
210 * Callback method to be invoked when layout has completed and the
211 * client can compute its interior insets.
212 *
213 * @param inoutInfo Should be filled in by the implementation with
214 * the information about the insets of the window. This is called
215 * with whatever values the previous OnComputeInternalInsetsListener
216 * returned, if there are multiple such listeners in the window.
217 */
218 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo);
219 }
220
221 /**
222 * Creates a new ViewTreeObserver. This constructor should not be called
223 */
224 ViewTreeObserver() {
225 }
226
227 /**
228 * Merges all the listeners registered on the specified observer with the listeners
229 * registered on this object. After this method is invoked, the specified observer
230 * will return false in {@link #isAlive()} and should not be used anymore.
231 *
232 * @param observer The ViewTreeObserver whose listeners must be added to this observer
233 */
234 void merge(ViewTreeObserver observer) {
235 if (observer.mOnGlobalFocusListeners != null) {
236 if (mOnGlobalFocusListeners != null) {
237 mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners);
238 } else {
239 mOnGlobalFocusListeners = observer.mOnGlobalFocusListeners;
240 }
241 }
242
243 if (observer.mOnGlobalLayoutListeners != null) {
244 if (mOnGlobalLayoutListeners != null) {
245 mOnGlobalLayoutListeners.addAll(observer.mOnGlobalLayoutListeners);
246 } else {
247 mOnGlobalLayoutListeners = observer.mOnGlobalLayoutListeners;
248 }
249 }
250
251 if (observer.mOnPreDrawListeners != null) {
252 if (mOnPreDrawListeners != null) {
253 mOnPreDrawListeners.addAll(observer.mOnPreDrawListeners);
254 } else {
255 mOnPreDrawListeners = observer.mOnPreDrawListeners;
256 }
257 }
258
259 if (observer.mOnTouchModeChangeListeners != null) {
260 if (mOnTouchModeChangeListeners != null) {
261 mOnTouchModeChangeListeners.addAll(observer.mOnTouchModeChangeListeners);
262 } else {
263 mOnTouchModeChangeListeners = observer.mOnTouchModeChangeListeners;
264 }
265 }
266
267 if (observer.mOnComputeInternalInsetsListeners != null) {
268 if (mOnComputeInternalInsetsListeners != null) {
269 mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners);
270 } else {
271 mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners;
272 }
273 }
274
275 observer.kill();
276 }
277
278 /**
279 * Register a callback to be invoked when the focus state within the view tree changes.
280 *
281 * @param listener The callback to add
282 *
283 * @throws IllegalStateException If {@link #isAlive()} returns false
284 */
285 public void addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener listener) {
286 checkIsAlive();
287
288 if (mOnGlobalFocusListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700289 mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 }
291
292 mOnGlobalFocusListeners.add(listener);
293 }
294
295 /**
296 * Remove a previously installed focus change callback.
297 *
298 * @param victim The callback to remove
299 *
300 * @throws IllegalStateException If {@link #isAlive()} returns false
301 *
302 * @see #addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener)
303 */
304 public void removeOnGlobalFocusChangeListener(OnGlobalFocusChangeListener victim) {
305 checkIsAlive();
306 if (mOnGlobalFocusListeners == null) {
307 return;
308 }
309 mOnGlobalFocusListeners.remove(victim);
310 }
311
312 /**
313 * Register a callback to be invoked when the global layout state or the visibility of views
314 * within the view tree changes
315 *
316 * @param listener The callback to add
317 *
318 * @throws IllegalStateException If {@link #isAlive()} returns false
319 */
320 public void addOnGlobalLayoutListener(OnGlobalLayoutListener listener) {
321 checkIsAlive();
322
323 if (mOnGlobalLayoutListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700324 mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 }
326
327 mOnGlobalLayoutListeners.add(listener);
328 }
329
330 /**
331 * Remove a previously installed global layout callback
332 *
333 * @param victim The callback to remove
334 *
335 * @throws IllegalStateException If {@link #isAlive()} returns false
336 *
337 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
338 */
339 public void removeGlobalOnLayoutListener(OnGlobalLayoutListener victim) {
340 checkIsAlive();
341 if (mOnGlobalLayoutListeners == null) {
342 return;
343 }
344 mOnGlobalLayoutListeners.remove(victim);
345 }
346
347 /**
348 * Register a callback to be invoked when the view tree is about to be drawn
349 *
350 * @param listener The callback to add
351 *
352 * @throws IllegalStateException If {@link #isAlive()} returns false
353 */
354 public void addOnPreDrawListener(OnPreDrawListener listener) {
355 checkIsAlive();
356
357 if (mOnPreDrawListeners == null) {
Chet Haase6e0ecb42010-11-03 19:41:18 -0700358 mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 }
360
361 mOnPreDrawListeners.add(listener);
362 }
363
364 /**
365 * Remove a previously installed pre-draw callback
366 *
367 * @param victim The callback to remove
368 *
369 * @throws IllegalStateException If {@link #isAlive()} returns false
370 *
371 * @see #addOnPreDrawListener(OnPreDrawListener)
372 */
373 public void removeOnPreDrawListener(OnPreDrawListener victim) {
374 checkIsAlive();
375 if (mOnPreDrawListeners == null) {
376 return;
377 }
378 mOnPreDrawListeners.remove(victim);
379 }
380
381 /**
382 * Register a callback to be invoked when a view has been scrolled.
383 *
384 * @param listener The callback to add
385 *
386 * @throws IllegalStateException If {@link #isAlive()} returns false
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 */
388 public void addOnScrollChangedListener(OnScrollChangedListener listener) {
389 checkIsAlive();
390
391 if (mOnScrollChangedListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700392 mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 }
394
395 mOnScrollChangedListeners.add(listener);
396 }
397
398 /**
399 * Remove a previously installed scroll-changed callback
400 *
401 * @param victim The callback to remove
402 *
403 * @throws IllegalStateException If {@link #isAlive()} returns false
404 *
405 * @see #addOnScrollChangedListener(OnScrollChangedListener)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 */
407 public void removeOnScrollChangedListener(OnScrollChangedListener victim) {
408 checkIsAlive();
409 if (mOnScrollChangedListeners == null) {
410 return;
411 }
412 mOnScrollChangedListeners.remove(victim);
413 }
414
415 /**
416 * Register a callback to be invoked when the invoked when the touch mode changes.
417 *
418 * @param listener The callback to add
419 *
420 * @throws IllegalStateException If {@link #isAlive()} returns false
421 */
422 public void addOnTouchModeChangeListener(OnTouchModeChangeListener listener) {
423 checkIsAlive();
424
425 if (mOnTouchModeChangeListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700426 mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 }
428
429 mOnTouchModeChangeListeners.add(listener);
430 }
431
432 /**
433 * Remove a previously installed touch mode change callback
434 *
435 * @param victim The callback to remove
436 *
437 * @throws IllegalStateException If {@link #isAlive()} returns false
438 *
439 * @see #addOnTouchModeChangeListener(OnTouchModeChangeListener)
440 */
441 public void removeOnTouchModeChangeListener(OnTouchModeChangeListener victim) {
442 checkIsAlive();
443 if (mOnTouchModeChangeListeners == null) {
444 return;
445 }
446 mOnTouchModeChangeListeners.remove(victim);
447 }
448
449 /**
450 * Register a callback to be invoked when the invoked when it is time to
451 * compute the window's internal insets.
452 *
453 * @param listener The callback to add
454 *
455 * @throws IllegalStateException If {@link #isAlive()} returns false
Dianne Hackborn935ae462009-04-13 16:11:55 -0700456 *
457 * We are not yet ready to commit to this API and support it, so
458 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 */
460 public void addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener listener) {
461 checkIsAlive();
462
463 if (mOnComputeInternalInsetsListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700464 mOnComputeInternalInsetsListeners =
465 new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 }
467
468 mOnComputeInternalInsetsListeners.add(listener);
469 }
470
471 /**
472 * Remove a previously installed internal insets computation callback
473 *
474 * @param victim The callback to remove
475 *
476 * @throws IllegalStateException If {@link #isAlive()} returns false
477 *
478 * @see #addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener)
Dianne Hackborn935ae462009-04-13 16:11:55 -0700479 *
480 * We are not yet ready to commit to this API and support it, so
481 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 */
483 public void removeOnComputeInternalInsetsListener(OnComputeInternalInsetsListener victim) {
484 checkIsAlive();
485 if (mOnComputeInternalInsetsListeners == null) {
486 return;
487 }
488 mOnComputeInternalInsetsListeners.remove(victim);
489 }
490
491 private void checkIsAlive() {
492 if (!mAlive) {
493 throw new IllegalStateException("This ViewTreeObserver is not alive, call "
494 + "getViewTreeObserver() again");
495 }
496 }
497
498 /**
499 * Indicates whether this ViewTreeObserver is alive. When an observer is not alive,
500 * any call to a method (except this one) will throw an exception.
501 *
502 * If an application keeps a long-lived reference to this ViewTreeObserver, it should
503 * always check for the result of this method before calling any other method.
504 *
505 * @return True if this object is alive and be used, false otherwise.
506 */
507 public boolean isAlive() {
508 return mAlive;
509 }
510
511 /**
512 * Marks this ViewTreeObserver as not alive. After invoking this method, invoking
513 * any other method but {@link #isAlive()} and {@link #kill()} will throw an Exception.
514 *
515 * @hide
516 */
517 private void kill() {
518 mAlive = false;
519 }
520
521 /**
522 * Notifies registered listeners that focus has changed.
523 */
524 final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700525 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
526 // perform the dispatching. The iterator is a safe guard against listeners that
527 // could mutate the list by calling the various add/remove methods. This prevents
528 // the array from being modified while we iterate it.
529 final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700530 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700531 for (OnGlobalFocusChangeListener listener : listeners) {
532 listener.onGlobalFocusChanged(oldFocus, newFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 }
534 }
535 }
536
537 /**
538 * Notifies registered listeners that a global layout happened. This can be called
539 * manually if you are forcing a layout on a View or a hierarchy of Views that are
540 * not attached to a Window or in the GONE state.
541 */
542 public final void dispatchOnGlobalLayout() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700543 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
544 // perform the dispatching. The iterator is a safe guard against listeners that
545 // could mutate the list by calling the various add/remove methods. This prevents
546 // the array from being modified while we iterate it.
547 final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700548 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700549 for (OnGlobalLayoutListener listener : listeners) {
550 listener.onGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 }
552 }
553 }
554
555 /**
556 * Notifies registered listeners that the drawing pass is about to start. If a
557 * listener returns true, then the drawing pass is canceled and rescheduled. This can
558 * be called manually if you are forcing the drawing on a View or a hierarchy of Views
559 * that are not attached to a Window or in the GONE state.
560 *
561 * @return True if the current draw should be canceled and resceduled, false otherwise.
562 */
563 public final boolean dispatchOnPreDraw() {
Chet Haase6e0ecb42010-11-03 19:41:18 -0700564 // NOTE: we *must* clone the listener list to perform the dispatching.
565 // The clone is a safe guard against listeners that
The Android Open Source Project10592532009-03-18 17:39:46 -0700566 // could mutate the list by calling the various add/remove methods. This prevents
Chet Haase6e0ecb42010-11-03 19:41:18 -0700567 // the array from being modified while we process it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 boolean cancelDraw = false;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700569 if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
570 final ArrayList<OnPreDrawListener> listeners =
571 (ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
572 int numListeners = listeners.size();
573 for (int i = 0; i < numListeners; ++i) {
574 cancelDraw |= !(listeners.get(i).onPreDraw());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 }
576 }
577 return cancelDraw;
578 }
579
580 /**
581 * Notifies registered listeners that the touch mode has changed.
582 *
583 * @param inTouchMode True if the touch mode is now enabled, false otherwise.
584 */
585 final void dispatchOnTouchModeChanged(boolean inTouchMode) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700586 final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
587 mOnTouchModeChangeListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700588 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700589 for (OnTouchModeChangeListener listener : listeners) {
590 listener.onTouchModeChanged(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 }
592 }
593 }
594
595 /**
596 * Notifies registered listeners that something has scrolled.
597 */
598 final void dispatchOnScrollChanged() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700599 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
600 // perform the dispatching. The iterator is a safe guard against listeners that
601 // could mutate the list by calling the various add/remove methods. This prevents
602 // the array from being modified while we iterate it.
603 final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
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 (OnScrollChangedListener listener : listeners) {
606 listener.onScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 }
608 }
609 }
610
611 /**
612 * Returns whether there are listeners for computing internal insets.
613 */
614 final boolean hasComputeInternalInsetsListeners() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700615 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
616 mOnComputeInternalInsetsListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 return (listeners != null && listeners.size() > 0);
618 }
619
620 /**
621 * Calls all listeners to compute the current insets.
622 */
623 final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700624 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
625 // perform the dispatching. The iterator is a safe guard against listeners that
626 // could mutate the list by calling the various add/remove methods. This prevents
627 // the array from being modified while we iterate it.
628 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
629 mOnComputeInternalInsetsListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700630 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700631 for (OnComputeInternalInsetsListener listener : listeners) {
632 listener.onComputeInternalInsets(inoutInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 }
634 }
635 }
636}