blob: 1c5d436422dfb62881a16c30562049782a5c6eff [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.graphics.Rect;
Jeff Brownfbf09772011-01-16 14:06:57 -080020import android.graphics.Region;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021
Chet Haase6e0ecb42010-11-03 19:41:18 -070022import java.util.ArrayList;
Chet Haase0f8ffd82012-06-07 07:48:48 -070023import java.util.concurrent.CopyOnWriteArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
25/**
26 * A view tree observer is used to register listeners that can be notified of global
27 * changes in the view tree. Such global events include, but are not limited to,
28 * layout of the whole tree, beginning of the drawing pass, touch mode change....
29 *
30 * A ViewTreeObserver should never be instantiated by applications as it is provided
31 * by the views hierarchy. Refer to {@link android.view.View#getViewTreeObserver()}
32 * for more information.
33 */
34public final class ViewTreeObserver {
Chet Haase0f8ffd82012-06-07 07:48:48 -070035 private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
36 private CopyOnWriteArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
37 private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
38 private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
39 private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
40 private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
Romain Guy25eba5c2012-04-04 17:29:03 -070041 private ArrayList<OnDrawListener> mOnDrawListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
43 private boolean mAlive = true;
44
45 /**
46 * Interface definition for a callback to be invoked when the focus state within
47 * the view tree changes.
48 */
49 public interface OnGlobalFocusChangeListener {
50 /**
51 * Callback method to be invoked when the focus changes in the view tree. When
52 * the view tree transitions from touch mode to non-touch mode, oldFocus is null.
53 * When the view tree transitions from non-touch mode to touch mode, newFocus is
54 * null. When focus changes in non-touch mode (without transition from or to
55 * touch mode) either oldFocus or newFocus can be null.
56 *
57 * @param oldFocus The previously focused view, if any.
58 * @param newFocus The newly focused View, if any.
59 */
60 public void onGlobalFocusChanged(View oldFocus, View newFocus);
61 }
62
63 /**
64 * Interface definition for a callback to be invoked when the global layout state
65 * or the visibility of views within the view tree changes.
66 */
67 public interface OnGlobalLayoutListener {
68 /**
69 * Callback method to be invoked when the global layout state or the visibility of views
70 * within the view tree changes
71 */
72 public void onGlobalLayout();
73 }
74
75 /**
76 * Interface definition for a callback to be invoked when the view tree is about to be drawn.
77 */
78 public interface OnPreDrawListener {
79 /**
80 * Callback method to be invoked when the view tree is about to be drawn. At this point, all
81 * views in the tree have been measured and given a frame. Clients can use this to adjust
82 * their scroll bounds or even to request a new layout before drawing occurs.
83 *
84 * @return Return true to proceed with the current drawing pass, or false to cancel.
85 *
86 * @see android.view.View#onMeasure
87 * @see android.view.View#onLayout
88 * @see android.view.View#onDraw
89 */
90 public boolean onPreDraw();
91 }
92
93 /**
Romain Guy25eba5c2012-04-04 17:29:03 -070094 * Interface definition for a callback to be invoked when the view tree is about to be drawn.
95 */
96 public interface OnDrawListener {
97 /**
98 * <p>Callback method to be invoked when the view tree is about to be drawn. At this point,
99 * views cannot be modified in any way.</p>
100 *
101 * <p>Unlike with {@link OnPreDrawListener}, this method cannot be used to cancel the
102 * current drawing pass.</p>
103 *
104 * <p>An {@link OnDrawListener} listener <strong>cannot be added or removed</strong>
105 * from this method.</p>
106 *
107 * @see android.view.View#onMeasure
108 * @see android.view.View#onLayout
109 * @see android.view.View#onDraw
110 */
111 public void onDraw();
112 }
113
114 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 * Interface definition for a callback to be invoked when the touch mode changes.
116 */
117 public interface OnTouchModeChangeListener {
118 /**
119 * Callback method to be invoked when the touch mode changes.
120 *
121 * @param isInTouchMode True if the view hierarchy is now in touch mode, false otherwise.
122 */
123 public void onTouchModeChanged(boolean isInTouchMode);
124 }
125
126 /**
127 * Interface definition for a callback to be invoked when
128 * something in the view tree has been scrolled.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 */
130 public interface OnScrollChangedListener {
131 /**
132 * Callback method to be invoked when something in the view tree
133 * has been scrolled.
134 */
135 public void onScrollChanged();
136 }
137
138 /**
139 * Parameters used with OnComputeInternalInsetsListener.
Dianne Hackborn935ae462009-04-13 16:11:55 -0700140 *
141 * We are not yet ready to commit to this API and support it, so
142 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 */
144 public final static class InternalInsetsInfo {
145 /**
146 * Offsets from the frame of the window at which the content of
147 * windows behind it should be placed.
148 */
149 public final Rect contentInsets = new Rect();
Chet Haase0f8ffd82012-06-07 07:48:48 -0700150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 /**
Jeff Brownfbf09772011-01-16 14:06:57 -0800152 * Offsets from the frame of the window at which windows behind it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 * are visible.
154 */
155 public final Rect visibleInsets = new Rect();
Jeff Brownfbf09772011-01-16 14:06:57 -0800156
157 /**
158 * Touchable region defined relative to the origin of the frame of the window.
159 * Only used when {@link #setTouchableInsets(int)} is called with
160 * the option {@link #TOUCHABLE_INSETS_REGION}.
161 */
162 public final Region touchableRegion = new Region();
163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 /**
165 * Option for {@link #setTouchableInsets(int)}: the entire window frame
166 * can be touched.
167 */
168 public static final int TOUCHABLE_INSETS_FRAME = 0;
Chet Haase0f8ffd82012-06-07 07:48:48 -0700169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 /**
171 * Option for {@link #setTouchableInsets(int)}: the area inside of
172 * the content insets can be touched.
173 */
174 public static final int TOUCHABLE_INSETS_CONTENT = 1;
Chet Haase0f8ffd82012-06-07 07:48:48 -0700175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 /**
177 * Option for {@link #setTouchableInsets(int)}: the area inside of
178 * the visible insets can be touched.
179 */
180 public static final int TOUCHABLE_INSETS_VISIBLE = 2;
Jeff Brownfbf09772011-01-16 14:06:57 -0800181
182 /**
183 * Option for {@link #setTouchableInsets(int)}: the area inside of
184 * the provided touchable region in {@link #touchableRegion} can be touched.
185 */
186 public static final int TOUCHABLE_INSETS_REGION = 3;
187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 /**
189 * Set which parts of the window can be touched: either
190 * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
Jeff Brownfbf09772011-01-16 14:06:57 -0800191 * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 */
193 public void setTouchableInsets(int val) {
194 mTouchableInsets = val;
195 }
Romain Guy25eba5c2012-04-04 17:29:03 -0700196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 int mTouchableInsets;
Chet Haase0f8ffd82012-06-07 07:48:48 -0700198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 void reset() {
Jeff Brownfbf09772011-01-16 14:06:57 -0800200 contentInsets.setEmpty();
201 visibleInsets.setEmpty();
202 touchableRegion.setEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 mTouchableInsets = TOUCHABLE_INSETS_FRAME;
204 }
Romain Guy25eba5c2012-04-04 17:29:03 -0700205
206 @Override
207 public int hashCode() {
208 int result = contentInsets != null ? contentInsets.hashCode() : 0;
209 result = 31 * result + (visibleInsets != null ? visibleInsets.hashCode() : 0);
210 result = 31 * result + (touchableRegion != null ? touchableRegion.hashCode() : 0);
211 result = 31 * result + mTouchableInsets;
212 return result;
213 }
214
Romain Guy1e878d22012-01-23 15:34:25 -0800215 @Override
216 public boolean equals(Object o) {
Romain Guy25eba5c2012-04-04 17:29:03 -0700217 if (this == o) return true;
218 if (o == null || getClass() != o.getClass()) return false;
219
220 InternalInsetsInfo other = (InternalInsetsInfo)o;
221 return mTouchableInsets == other.mTouchableInsets &&
222 contentInsets.equals(other.contentInsets) &&
223 visibleInsets.equals(other.visibleInsets) &&
224 touchableRegion.equals(other.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 }
Romain Guy25eba5c2012-04-04 17:29:03 -0700226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 void set(InternalInsetsInfo other) {
228 contentInsets.set(other.contentInsets);
229 visibleInsets.set(other.visibleInsets);
Jeff Brownfbf09772011-01-16 14:06:57 -0800230 touchableRegion.set(other.touchableRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 mTouchableInsets = other.mTouchableInsets;
232 }
233 }
Chet Haase0f8ffd82012-06-07 07:48:48 -0700234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 /**
236 * Interface definition for a callback to be invoked when layout has
237 * completed and the client can compute its interior insets.
Dianne Hackborn935ae462009-04-13 16:11:55 -0700238 *
239 * We are not yet ready to commit to this API and support it, so
240 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 */
242 public interface OnComputeInternalInsetsListener {
243 /**
244 * Callback method to be invoked when layout has completed and the
245 * client can compute its interior insets.
246 *
247 * @param inoutInfo Should be filled in by the implementation with
248 * the information about the insets of the window. This is called
249 * with whatever values the previous OnComputeInternalInsetsListener
250 * returned, if there are multiple such listeners in the window.
251 */
252 public void onComputeInternalInsets(InternalInsetsInfo inoutInfo);
253 }
254
255 /**
256 * Creates a new ViewTreeObserver. This constructor should not be called
257 */
258 ViewTreeObserver() {
259 }
260
261 /**
262 * Merges all the listeners registered on the specified observer with the listeners
263 * registered on this object. After this method is invoked, the specified observer
264 * will return false in {@link #isAlive()} and should not be used anymore.
265 *
266 * @param observer The ViewTreeObserver whose listeners must be added to this observer
267 */
268 void merge(ViewTreeObserver observer) {
269 if (observer.mOnGlobalFocusListeners != null) {
270 if (mOnGlobalFocusListeners != null) {
271 mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners);
272 } else {
273 mOnGlobalFocusListeners = observer.mOnGlobalFocusListeners;
274 }
275 }
276
277 if (observer.mOnGlobalLayoutListeners != null) {
278 if (mOnGlobalLayoutListeners != null) {
279 mOnGlobalLayoutListeners.addAll(observer.mOnGlobalLayoutListeners);
280 } else {
281 mOnGlobalLayoutListeners = observer.mOnGlobalLayoutListeners;
282 }
283 }
284
285 if (observer.mOnPreDrawListeners != null) {
286 if (mOnPreDrawListeners != null) {
287 mOnPreDrawListeners.addAll(observer.mOnPreDrawListeners);
288 } else {
289 mOnPreDrawListeners = observer.mOnPreDrawListeners;
290 }
291 }
292
293 if (observer.mOnTouchModeChangeListeners != null) {
294 if (mOnTouchModeChangeListeners != null) {
295 mOnTouchModeChangeListeners.addAll(observer.mOnTouchModeChangeListeners);
296 } else {
297 mOnTouchModeChangeListeners = observer.mOnTouchModeChangeListeners;
298 }
299 }
300
301 if (observer.mOnComputeInternalInsetsListeners != null) {
302 if (mOnComputeInternalInsetsListeners != null) {
303 mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners);
304 } else {
305 mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners;
306 }
307 }
308
Mark Brophy757c6972011-10-25 17:01:28 +0100309 if (observer.mOnScrollChangedListeners != null) {
310 if (mOnScrollChangedListeners != null) {
311 mOnScrollChangedListeners.addAll(observer.mOnScrollChangedListeners);
312 } else {
313 mOnScrollChangedListeners = observer.mOnScrollChangedListeners;
314 }
315 }
316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 observer.kill();
318 }
319
320 /**
321 * Register a callback to be invoked when the focus state within the view tree changes.
322 *
323 * @param listener The callback to add
324 *
325 * @throws IllegalStateException If {@link #isAlive()} returns false
326 */
327 public void addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener listener) {
328 checkIsAlive();
329
330 if (mOnGlobalFocusListeners == null) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700331 mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 }
333
334 mOnGlobalFocusListeners.add(listener);
335 }
336
337 /**
338 * Remove a previously installed focus change callback.
339 *
340 * @param victim The callback to remove
341 *
342 * @throws IllegalStateException If {@link #isAlive()} returns false
343 *
344 * @see #addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener)
345 */
346 public void removeOnGlobalFocusChangeListener(OnGlobalFocusChangeListener victim) {
347 checkIsAlive();
348 if (mOnGlobalFocusListeners == null) {
349 return;
350 }
351 mOnGlobalFocusListeners.remove(victim);
352 }
353
354 /**
355 * Register a callback to be invoked when the global layout state or the visibility of views
356 * within the view tree changes
357 *
358 * @param listener The callback to add
359 *
360 * @throws IllegalStateException If {@link #isAlive()} returns false
361 */
362 public void addOnGlobalLayoutListener(OnGlobalLayoutListener listener) {
363 checkIsAlive();
364
365 if (mOnGlobalLayoutListeners == null) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700366 mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 }
368
369 mOnGlobalLayoutListeners.add(listener);
370 }
371
372 /**
373 * Remove a previously installed global layout callback
374 *
375 * @param victim The callback to remove
376 *
377 * @throws IllegalStateException If {@link #isAlive()} returns false
Romain Guy1e878d22012-01-23 15:34:25 -0800378 *
379 * @deprecated Use #removeOnGlobalLayoutListener instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 *
381 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
382 */
Romain Guy1e878d22012-01-23 15:34:25 -0800383 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 public void removeGlobalOnLayoutListener(OnGlobalLayoutListener victim) {
Romain Guy1e878d22012-01-23 15:34:25 -0800385 removeOnGlobalLayoutListener(victim);
386 }
387
388 /**
389 * Remove a previously installed global layout callback
390 *
391 * @param victim The callback to remove
392 *
393 * @throws IllegalStateException If {@link #isAlive()} returns false
394 *
395 * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
396 */
397 public void removeOnGlobalLayoutListener(OnGlobalLayoutListener victim) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 checkIsAlive();
399 if (mOnGlobalLayoutListeners == null) {
400 return;
401 }
402 mOnGlobalLayoutListeners.remove(victim);
403 }
404
405 /**
406 * Register a callback to be invoked when the view tree is about to be drawn
407 *
408 * @param listener The callback to add
409 *
410 * @throws IllegalStateException If {@link #isAlive()} returns false
411 */
412 public void addOnPreDrawListener(OnPreDrawListener listener) {
413 checkIsAlive();
414
415 if (mOnPreDrawListeners == null) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700416 mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 }
418
419 mOnPreDrawListeners.add(listener);
420 }
421
422 /**
423 * Remove a previously installed pre-draw callback
424 *
425 * @param victim The callback to remove
426 *
427 * @throws IllegalStateException If {@link #isAlive()} returns false
428 *
429 * @see #addOnPreDrawListener(OnPreDrawListener)
430 */
431 public void removeOnPreDrawListener(OnPreDrawListener victim) {
432 checkIsAlive();
433 if (mOnPreDrawListeners == null) {
434 return;
435 }
436 mOnPreDrawListeners.remove(victim);
437 }
438
439 /**
Romain Guy25eba5c2012-04-04 17:29:03 -0700440 * <p>Register a callback to be invoked when the view tree is about to be drawn.</p>
441 * <p><strong>Note:</strong> this method <strong>cannot</strong> be invoked from
442 * {@link android.view.ViewTreeObserver.OnDrawListener#onDraw()}.</p>
443 *
444 * @param listener The callback to add
445 *
446 * @throws IllegalStateException If {@link #isAlive()} returns false
447 */
448 public void addOnDrawListener(OnDrawListener listener) {
449 checkIsAlive();
450
451 if (mOnDrawListeners == null) {
452 mOnDrawListeners = new ArrayList<OnDrawListener>();
453 }
454
455 mOnDrawListeners.add(listener);
456 }
457
458 /**
459 * <p>Remove a previously installed pre-draw callback.</p>
460 * <p><strong>Note:</strong> this method <strong>cannot</strong> be invoked from
461 * {@link android.view.ViewTreeObserver.OnDrawListener#onDraw()}.</p>
462 *
463 * @param victim The callback to remove
464 *
465 * @throws IllegalStateException If {@link #isAlive()} returns false
466 *
467 * @see #addOnDrawListener(OnDrawListener)
468 */
469 public void removeOnDrawListener(OnDrawListener victim) {
470 checkIsAlive();
471 if (mOnDrawListeners == null) {
472 return;
473 }
474 mOnDrawListeners.remove(victim);
475 }
476
477 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 * Register a callback to be invoked when a view has been scrolled.
479 *
480 * @param listener The callback to add
481 *
482 * @throws IllegalStateException If {@link #isAlive()} returns false
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 */
484 public void addOnScrollChangedListener(OnScrollChangedListener listener) {
485 checkIsAlive();
486
487 if (mOnScrollChangedListeners == null) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700488 mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490
491 mOnScrollChangedListeners.add(listener);
492 }
493
494 /**
495 * Remove a previously installed scroll-changed callback
496 *
497 * @param victim The callback to remove
498 *
499 * @throws IllegalStateException If {@link #isAlive()} returns false
500 *
501 * @see #addOnScrollChangedListener(OnScrollChangedListener)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 */
503 public void removeOnScrollChangedListener(OnScrollChangedListener victim) {
504 checkIsAlive();
505 if (mOnScrollChangedListeners == null) {
506 return;
507 }
508 mOnScrollChangedListeners.remove(victim);
509 }
510
511 /**
512 * Register a callback to be invoked when the invoked when the touch mode changes.
513 *
514 * @param listener The callback to add
515 *
516 * @throws IllegalStateException If {@link #isAlive()} returns false
517 */
518 public void addOnTouchModeChangeListener(OnTouchModeChangeListener listener) {
519 checkIsAlive();
520
521 if (mOnTouchModeChangeListeners == null) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700522 mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 }
524
525 mOnTouchModeChangeListeners.add(listener);
526 }
527
528 /**
529 * Remove a previously installed touch mode change callback
530 *
531 * @param victim The callback to remove
532 *
533 * @throws IllegalStateException If {@link #isAlive()} returns false
534 *
535 * @see #addOnTouchModeChangeListener(OnTouchModeChangeListener)
536 */
537 public void removeOnTouchModeChangeListener(OnTouchModeChangeListener victim) {
538 checkIsAlive();
539 if (mOnTouchModeChangeListeners == null) {
540 return;
541 }
542 mOnTouchModeChangeListeners.remove(victim);
543 }
544
545 /**
546 * Register a callback to be invoked when the invoked when it is time to
547 * compute the window's internal insets.
548 *
549 * @param listener The callback to add
550 *
551 * @throws IllegalStateException If {@link #isAlive()} returns false
Dianne Hackborn935ae462009-04-13 16:11:55 -0700552 *
553 * We are not yet ready to commit to this API and support it, so
554 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 */
556 public void addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener listener) {
557 checkIsAlive();
558
559 if (mOnComputeInternalInsetsListeners == null) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700560 mOnComputeInternalInsetsListeners =
Chet Haase0f8ffd82012-06-07 07:48:48 -0700561 new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
563
564 mOnComputeInternalInsetsListeners.add(listener);
565 }
566
567 /**
568 * Remove a previously installed internal insets computation callback
569 *
570 * @param victim The callback to remove
571 *
572 * @throws IllegalStateException If {@link #isAlive()} returns false
573 *
574 * @see #addOnComputeInternalInsetsListener(OnComputeInternalInsetsListener)
Dianne Hackborn935ae462009-04-13 16:11:55 -0700575 *
576 * We are not yet ready to commit to this API and support it, so
577 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 */
579 public void removeOnComputeInternalInsetsListener(OnComputeInternalInsetsListener victim) {
580 checkIsAlive();
581 if (mOnComputeInternalInsetsListeners == null) {
582 return;
583 }
584 mOnComputeInternalInsetsListeners.remove(victim);
585 }
586
587 private void checkIsAlive() {
588 if (!mAlive) {
589 throw new IllegalStateException("This ViewTreeObserver is not alive, call "
590 + "getViewTreeObserver() again");
591 }
592 }
593
594 /**
595 * Indicates whether this ViewTreeObserver is alive. When an observer is not alive,
596 * any call to a method (except this one) will throw an exception.
597 *
598 * If an application keeps a long-lived reference to this ViewTreeObserver, it should
599 * always check for the result of this method before calling any other method.
600 *
601 * @return True if this object is alive and be used, false otherwise.
602 */
603 public boolean isAlive() {
604 return mAlive;
605 }
606
607 /**
608 * Marks this ViewTreeObserver as not alive. After invoking this method, invoking
609 * any other method but {@link #isAlive()} and {@link #kill()} will throw an Exception.
610 *
611 * @hide
612 */
613 private void kill() {
614 mAlive = false;
615 }
616
617 /**
618 * Notifies registered listeners that focus has changed.
619 */
620 final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700621 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
622 // perform the dispatching. The iterator is a safe guard against listeners that
623 // could mutate the list by calling the various add/remove methods. This prevents
624 // the array from being modified while we iterate it.
Chet Haase0f8ffd82012-06-07 07:48:48 -0700625 final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700626 if (listeners != null && listeners.size() > 0) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700627 for (OnGlobalFocusChangeListener listener : listeners) {
628 listener.onGlobalFocusChanged(oldFocus, newFocus);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 }
630 }
631 }
632
633 /**
634 * Notifies registered listeners that a global layout happened. This can be called
635 * manually if you are forcing a layout on a View or a hierarchy of Views that are
636 * not attached to a Window or in the GONE state.
637 */
638 public final void dispatchOnGlobalLayout() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700639 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
640 // perform the dispatching. The iterator is a safe guard against listeners that
641 // could mutate the list by calling the various add/remove methods. This prevents
642 // the array from being modified while we iterate it.
Chet Haase0f8ffd82012-06-07 07:48:48 -0700643 final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700644 if (listeners != null && listeners.size() > 0) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700645 for (OnGlobalLayoutListener listener : listeners) {
646 listener.onGlobalLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 }
648 }
649 }
650
651 /**
652 * Notifies registered listeners that the drawing pass is about to start. If a
653 * listener returns true, then the drawing pass is canceled and rescheduled. This can
654 * be called manually if you are forcing the drawing on a View or a hierarchy of Views
655 * that are not attached to a Window or in the GONE state.
656 *
657 * @return True if the current draw should be canceled and resceduled, false otherwise.
658 */
Romain Guy25eba5c2012-04-04 17:29:03 -0700659 @SuppressWarnings("unchecked")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 public final boolean dispatchOnPreDraw() {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700661 // NOTE: we *must* clone the listener list to perform the dispatching.
662 // The clone is a safe guard against listeners that
663 // could mutate the list by calling the various add/remove methods. This prevents
664 // the array from being modified while we process it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 boolean cancelDraw = false;
Chet Haase0f8ffd82012-06-07 07:48:48 -0700666 if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
667 final ArrayList<OnPreDrawListener> listeners =
668 (ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
669 int numListeners = listeners.size();
670 for (int i = 0; i < numListeners; ++i) {
671 cancelDraw |= !(listeners.get(i).onPreDraw());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 }
673 }
674 return cancelDraw;
675 }
676
677 /**
Romain Guy25eba5c2012-04-04 17:29:03 -0700678 * Notifies registered listeners that the drawing pass is about to start.
679 */
680 public final void dispatchOnDraw() {
681 if (mOnDrawListeners != null) {
682 final ArrayList<OnDrawListener> listeners = mOnDrawListeners;
683 int numListeners = listeners.size();
684 for (int i = 0; i < numListeners; ++i) {
685 listeners.get(i).onDraw();
686 }
687 }
688 }
689
690 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 * Notifies registered listeners that the touch mode has changed.
692 *
693 * @param inTouchMode True if the touch mode is now enabled, false otherwise.
694 */
695 final void dispatchOnTouchModeChanged(boolean inTouchMode) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700696 final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
The Android Open Source Project10592532009-03-18 17:39:46 -0700697 mOnTouchModeChangeListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700698 if (listeners != null && listeners.size() > 0) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700699 for (OnTouchModeChangeListener listener : listeners) {
700 listener.onTouchModeChanged(inTouchMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 }
702 }
703 }
704
705 /**
706 * Notifies registered listeners that something has scrolled.
707 */
708 final void dispatchOnScrollChanged() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700709 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
710 // perform the dispatching. The iterator is a safe guard against listeners that
711 // could mutate the list by calling the various add/remove methods. This prevents
712 // the array from being modified while we iterate it.
Chet Haase0f8ffd82012-06-07 07:48:48 -0700713 final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700714 if (listeners != null && listeners.size() > 0) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700715 for (OnScrollChangedListener listener : listeners) {
716 listener.onScrollChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 }
718 }
719 }
720
721 /**
722 * Returns whether there are listeners for computing internal insets.
723 */
724 final boolean hasComputeInternalInsetsListeners() {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700725 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
The Android Open Source Project10592532009-03-18 17:39:46 -0700726 mOnComputeInternalInsetsListeners;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 return (listeners != null && listeners.size() > 0);
728 }
Chet Haase0f8ffd82012-06-07 07:48:48 -0700729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 /**
731 * Calls all listeners to compute the current insets.
732 */
733 final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700734 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
735 // perform the dispatching. The iterator is a safe guard against listeners that
736 // could mutate the list by calling the various add/remove methods. This prevents
737 // the array from being modified while we iterate it.
Chet Haase0f8ffd82012-06-07 07:48:48 -0700738 final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
The Android Open Source Project10592532009-03-18 17:39:46 -0700739 mOnComputeInternalInsetsListeners;
Chet Haase6e0ecb42010-11-03 19:41:18 -0700740 if (listeners != null && listeners.size() > 0) {
Chet Haase0f8ffd82012-06-07 07:48:48 -0700741 for (OnComputeInternalInsetsListener listener : listeners) {
742 listener.onComputeInternalInsets(inoutInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 }
744 }
745 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746}