blob: c53fc6b4010aeb41b608c5894a34e993ca7dbc4a [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
Mark Brophy757c6972011-10-25 17:01:28 +0100291 if (observer.mOnScrollChangedListeners != null) {
292 if (mOnScrollChangedListeners != null) {
293 mOnScrollChangedListeners.addAll(observer.mOnScrollChangedListeners);
294 } else {
295 mOnScrollChangedListeners = observer.mOnScrollChangedListeners;
296 }
297 }
298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 observer.kill();
300 }
301
302 /**
303 * Register a callback to be invoked when the focus state within the view tree changes.
304 *
305 * @param listener The callback to add
306 *
307 * @throws IllegalStateException If {@link #isAlive()} returns false
308 */
309 public void addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener listener) {
310 checkIsAlive();
311
312 if (mOnGlobalFocusListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700313 mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 }
315
316 mOnGlobalFocusListeners.add(listener);
317 }
318
319 /**
320 * Remove a previously installed focus change callback.
321 *
322 * @param victim The callback to remove
323 *
324 * @throws IllegalStateException If {@link #isAlive()} returns false
325 *
326 * @see #addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener)
327 */
328 public void removeOnGlobalFocusChangeListener(OnGlobalFocusChangeListener victim) {
329 checkIsAlive();
330 if (mOnGlobalFocusListeners == null) {
331 return;
332 }
333 mOnGlobalFocusListeners.remove(victim);
334 }
335
336 /**
337 * Register a callback to be invoked when the global layout state or the visibility of views
338 * within the view tree changes
339 *
340 * @param listener The callback to add
341 *
342 * @throws IllegalStateException If {@link #isAlive()} returns false
343 */
344 public void addOnGlobalLayoutListener(OnGlobalLayoutListener listener) {
345 checkIsAlive();
346
347 if (mOnGlobalLayoutListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700348 mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 }
350
351 mOnGlobalLayoutListeners.add(listener);
352 }
353
354 /**
355 * Remove a previously installed global layout callback
356 *
357 * @param victim The callback to remove
358 *
359 * @throws IllegalStateException If {@link #isAlive()} returns false
360 *
361 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
362 */
363 public void removeGlobalOnLayoutListener(OnGlobalLayoutListener victim) {
364 checkIsAlive();
365 if (mOnGlobalLayoutListeners == null) {
366 return;
367 }
368 mOnGlobalLayoutListeners.remove(victim);
369 }
370
371 /**
372 * Register a callback to be invoked when the view tree is about to be drawn
373 *
374 * @param listener The callback to add
375 *
376 * @throws IllegalStateException If {@link #isAlive()} returns false
377 */
378 public void addOnPreDrawListener(OnPreDrawListener listener) {
379 checkIsAlive();
380
381 if (mOnPreDrawListeners == null) {
Chet Haase6e0ecb42010-11-03 19:41:18 -0700382 mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 }
384
385 mOnPreDrawListeners.add(listener);
386 }
387
388 /**
389 * Remove a previously installed pre-draw callback
390 *
391 * @param victim The callback to remove
392 *
393 * @throws IllegalStateException If {@link #isAlive()} returns false
394 *
395 * @see #addOnPreDrawListener(OnPreDrawListener)
396 */
397 public void removeOnPreDrawListener(OnPreDrawListener victim) {
398 checkIsAlive();
399 if (mOnPreDrawListeners == null) {
400 return;
401 }
402 mOnPreDrawListeners.remove(victim);
403 }
404
405 /**
406 * Register a callback to be invoked when a view has been scrolled.
407 *
408 * @param listener The callback to add
409 *
410 * @throws IllegalStateException If {@link #isAlive()} returns false
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 */
412 public void addOnScrollChangedListener(OnScrollChangedListener listener) {
413 checkIsAlive();
414
415 if (mOnScrollChangedListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700416 mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 }
418
419 mOnScrollChangedListeners.add(listener);
420 }
421
422 /**
423 * Remove a previously installed scroll-changed callback
424 *
425 * @param victim The callback to remove
426 *
427 * @throws IllegalStateException If {@link #isAlive()} returns false
428 *
429 * @see #addOnScrollChangedListener(OnScrollChangedListener)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 */
431 public void removeOnScrollChangedListener(OnScrollChangedListener victim) {
432 checkIsAlive();
433 if (mOnScrollChangedListeners == null) {
434 return;
435 }
436 mOnScrollChangedListeners.remove(victim);
437 }
438
439 /**
440 * Register a callback to be invoked when the invoked when the touch mode changes.
441 *
442 * @param listener The callback to add
443 *
444 * @throws IllegalStateException If {@link #isAlive()} returns false
445 */
446 public void addOnTouchModeChangeListener(OnTouchModeChangeListener listener) {
447 checkIsAlive();
448
449 if (mOnTouchModeChangeListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700450 mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 }
452
453 mOnTouchModeChangeListeners.add(listener);
454 }
455
456 /**
457 * Remove a previously installed touch mode change callback
458 *
459 * @param victim The callback to remove
460 *
461 * @throws IllegalStateException If {@link #isAlive()} returns false
462 *
463 * @see #addOnTouchModeChangeListener(OnTouchModeChangeListener)
464 */
465 public void removeOnTouchModeChangeListener(OnTouchModeChangeListener victim) {
466 checkIsAlive();
467 if (mOnTouchModeChangeListeners == null) {
468 return;
469 }
470 mOnTouchModeChangeListeners.remove(victim);
471 }
472
473 /**
474 * Register a callback to be invoked when the invoked when it is time to
475 * compute the window's internal insets.
476 *
477 * @param listener The callback to add
478 *
479 * @throws IllegalStateException If {@link #isAlive()} returns false
Dianne Hackborn935ae462009-04-13 16:11:55 -0700480 *
481 * We are not yet ready to commit to this API and support it, so
482 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 */
484 public void addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener listener) {
485 checkIsAlive();
486
487 if (mOnComputeInternalInsetsListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700488 mOnComputeInternalInsetsListeners =
489 new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 }
491
492 mOnComputeInternalInsetsListeners.add(listener);
493 }
494
495 /**
496 * Remove a previously installed internal insets computation callback
497 *
498 * @param victim The callback to remove
499 *
500 * @throws IllegalStateException If {@link #isAlive()} returns false
501 *
502 * @see #addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener)
Dianne Hackborn935ae462009-04-13 16:11:55 -0700503 *
504 * We are not yet ready to commit to this API and support it, so
505 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 */
507 public void removeOnComputeInternalInsetsListener(OnComputeInternalInsetsListener victim) {
508 checkIsAlive();
509 if (mOnComputeInternalInsetsListeners == null) {
510 return;
511 }
512 mOnComputeInternalInsetsListeners.remove(victim);
513 }
514
515 private void checkIsAlive() {
516 if (!mAlive) {
517 throw new IllegalStateException("This ViewTreeObserver is not alive, call "
518 + "getViewTreeObserver() again");
519 }
520 }
521
522 /**
523 * Indicates whether this ViewTreeObserver is alive. When an observer is not alive,
524 * any call to a method (except this one) will throw an exception.
525 *
526 * If an application keeps a long-lived reference to this ViewTreeObserver, it should
527 * always check for the result of this method before calling any other method.
528 *
529 * @return True if this object is alive and be used, false otherwise.
530 */
531 public boolean isAlive() {
532 return mAlive;
533 }
534
535 /**
536 * Marks this ViewTreeObserver as not alive. After invoking this method, invoking
537 * any other method but {@link #isAlive()} and {@link #kill()} will throw an Exception.
538 *
539 * @hide
540 */
541 private void kill() {
542 mAlive = false;
543 }
544
545 /**
546 * Notifies registered listeners that focus has changed.
547 */
548 final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700549 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
550 // perform the dispatching. The iterator is a safe guard against listeners that
551 // could mutate the list by calling the various add/remove methods. This prevents
552 // the array from being modified while we iterate it.
553 final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700554 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700555 for (OnGlobalFocusChangeListener listener : listeners) {
556 listener.onGlobalFocusChanged(oldFocus, newFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 }
558 }
559 }
560
561 /**
562 * Notifies registered listeners that a global layout happened. This can be called
563 * manually if you are forcing a layout on a View or a hierarchy of Views that are
564 * not attached to a Window or in the GONE state.
565 */
566 public final void dispatchOnGlobalLayout() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700567 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
568 // perform the dispatching. The iterator is a safe guard against listeners that
569 // could mutate the list by calling the various add/remove methods. This prevents
570 // the array from being modified while we iterate it.
571 final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700572 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700573 for (OnGlobalLayoutListener listener : listeners) {
574 listener.onGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 }
576 }
577 }
578
579 /**
580 * Notifies registered listeners that the drawing pass is about to start. If a
581 * listener returns true, then the drawing pass is canceled and rescheduled. This can
582 * be called manually if you are forcing the drawing on a View or a hierarchy of Views
583 * that are not attached to a Window or in the GONE state.
584 *
585 * @return True if the current draw should be canceled and resceduled, false otherwise.
586 */
587 public final boolean dispatchOnPreDraw() {
Chet Haase6e0ecb42010-11-03 19:41:18 -0700588 // NOTE: we *must* clone the listener list to perform the dispatching.
589 // The clone is a safe guard against listeners that
The Android Open Source Project10592532009-03-18 17:39:46 -0700590 // could mutate the list by calling the various add/remove methods. This prevents
Chet Haase6e0ecb42010-11-03 19:41:18 -0700591 // the array from being modified while we process it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 boolean cancelDraw = false;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700593 if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
594 final ArrayList<OnPreDrawListener> listeners =
595 (ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
596 int numListeners = listeners.size();
597 for (int i = 0; i < numListeners; ++i) {
598 cancelDraw |= !(listeners.get(i).onPreDraw());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 }
600 }
601 return cancelDraw;
602 }
603
604 /**
605 * Notifies registered listeners that the touch mode has changed.
606 *
607 * @param inTouchMode True if the touch mode is now enabled, false otherwise.
608 */
609 final void dispatchOnTouchModeChanged(boolean inTouchMode) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700610 final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
611 mOnTouchModeChangeListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700612 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700613 for (OnTouchModeChangeListener listener : listeners) {
614 listener.onTouchModeChanged(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 }
616 }
617 }
618
619 /**
620 * Notifies registered listeners that something has scrolled.
621 */
622 final void dispatchOnScrollChanged() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700623 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
624 // perform the dispatching. The iterator is a safe guard against listeners that
625 // could mutate the list by calling the various add/remove methods. This prevents
626 // the array from being modified while we iterate it.
627 final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700628 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700629 for (OnScrollChangedListener listener : listeners) {
630 listener.onScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 }
632 }
633 }
634
635 /**
636 * Returns whether there are listeners for computing internal insets.
637 */
638 final boolean hasComputeInternalInsetsListeners() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700639 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
640 mOnComputeInternalInsetsListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 return (listeners != null && listeners.size() > 0);
642 }
643
644 /**
645 * Calls all listeners to compute the current insets.
646 */
647 final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700648 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
649 // perform the dispatching. The iterator is a safe guard against listeners that
650 // could mutate the list by calling the various add/remove methods. This prevents
651 // the array from being modified while we iterate it.
652 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
653 mOnComputeInternalInsetsListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700654 if (listeners != null && listeners.size() > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700655 for (OnComputeInternalInsetsListener listener : listeners) {
656 listener.onComputeInternalInsets(inoutInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 }
658 }
659 }
660}