ViewGroup.java revision 4846032ac7be7c28c7cfeb3096b8cb656312a382
1/* 2 * Copyright (C) 2006 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 com.android.internal.R; 20 21import android.content.Context; 22import android.content.res.Configuration; 23import android.content.res.TypedArray; 24import android.graphics.Bitmap; 25import android.graphics.Canvas; 26import android.graphics.Paint; 27import android.graphics.Rect; 28import android.graphics.RectF; 29import android.graphics.Region; 30import android.os.Parcelable; 31import android.os.SystemClock; 32import android.util.AttributeSet; 33import android.util.Config; 34import android.util.EventLog; 35import android.util.Log; 36import android.util.SparseArray; 37import android.view.accessibility.AccessibilityEvent; 38import android.view.animation.Animation; 39import android.view.animation.AnimationUtils; 40import android.view.animation.LayoutAnimationController; 41import android.view.animation.Transformation; 42 43import java.util.ArrayList; 44 45/** 46 * <p> 47 * A <code>ViewGroup</code> is a special view that can contain other views 48 * (called children.) The view group is the base class for layouts and views 49 * containers. This class also defines the 50 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base 51 * class for layouts parameters. 52 * </p> 53 * 54 * <p> 55 * Also see {@link LayoutParams} for layout attributes. 56 * </p> 57 * 58 * @attr ref android.R.styleable#ViewGroup_clipChildren 59 * @attr ref android.R.styleable#ViewGroup_clipToPadding 60 * @attr ref android.R.styleable#ViewGroup_layoutAnimation 61 * @attr ref android.R.styleable#ViewGroup_animationCache 62 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache 63 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache 64 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren 65 * @attr ref android.R.styleable#ViewGroup_descendantFocusability 66 */ 67public abstract class ViewGroup extends View implements ViewParent, ViewManager { 68 private static final boolean DBG = false; 69 70 /** 71 * Views which have been hidden or removed which need to be animated on 72 * their way out. 73 * This field should be made private, so it is hidden from the SDK. 74 * {@hide} 75 */ 76 protected ArrayList<View> mDisappearingChildren; 77 78 /** 79 * Listener used to propagate events indicating when children are added 80 * and/or removed from a view group. 81 * This field should be made private, so it is hidden from the SDK. 82 * {@hide} 83 */ 84 protected OnHierarchyChangeListener mOnHierarchyChangeListener; 85 86 // The view contained within this ViewGroup that has or contains focus. 87 private View mFocused; 88 89 /** 90 * A Transformation used when drawing children, to 91 * apply on the child being drawn. 92 */ 93 private final Transformation mChildTransformation = new Transformation(); 94 95 /** 96 * Used to track the current invalidation region. 97 */ 98 private RectF mInvalidateRegion; 99 100 /** 101 * A Transformation used to calculate a correct 102 * invalidation area when the application is autoscaled. 103 */ 104 private Transformation mInvalidationTransformation; 105 106 // Target of Motion events 107 private View mMotionTarget; 108 private final Rect mTempRect = new Rect(); 109 110 // Layout animation 111 private LayoutAnimationController mLayoutAnimationController; 112 private Animation.AnimationListener mAnimationListener; 113 114 /** 115 * Internal flags. 116 * 117 * This field should be made private, so it is hidden from the SDK. 118 * {@hide} 119 */ 120 protected int mGroupFlags; 121 122 // When set, ViewGroup invalidates only the child's rectangle 123 // Set by default 124 private static final int FLAG_CLIP_CHILDREN = 0x1; 125 126 // When set, ViewGroup excludes the padding area from the invalidate rectangle 127 // Set by default 128 private static final int FLAG_CLIP_TO_PADDING = 0x2; 129 130 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when 131 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set 132 private static final int FLAG_INVALIDATE_REQUIRED = 0x4; 133 134 // When set, dispatchDraw() will run the layout animation and unset the flag 135 private static final int FLAG_RUN_ANIMATION = 0x8; 136 137 // When set, there is either no layout animation on the ViewGroup or the layout 138 // animation is over 139 // Set by default 140 private static final int FLAG_ANIMATION_DONE = 0x10; 141 142 // If set, this ViewGroup has padding; if unset there is no padding and we don't need 143 // to clip it, even if FLAG_CLIP_TO_PADDING is set 144 private static final int FLAG_PADDING_NOT_NULL = 0x20; 145 146 // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation 147 // Set by default 148 private static final int FLAG_ANIMATION_CACHE = 0x40; 149 150 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a 151 // layout animation; this avoid clobbering the hierarchy 152 // Automatically set when the layout animation starts, depending on the animation's 153 // characteristics 154 private static final int FLAG_OPTIMIZE_INVALIDATE = 0x80; 155 156 // When set, the next call to drawChild() will clear mChildTransformation's matrix 157 private static final int FLAG_CLEAR_TRANSFORMATION = 0x100; 158 159 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes 160 // the children's Bitmap caches if necessary 161 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set) 162 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200; 163 164 /** 165 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)} 166 * to get the index of the child to draw for that iteration. 167 * 168 * @hide 169 */ 170 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400; 171 172 /** 173 * When set, this ViewGroup supports static transformations on children; this causes 174 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be 175 * invoked when a child is drawn. 176 * 177 * Any subclass overriding 178 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should 179 * set this flags in {@link #mGroupFlags}. 180 * 181 * {@hide} 182 */ 183 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800; 184 185 // When the previous drawChild() invocation used an alpha value that was lower than 186 // 1.0 and set it in mCachePaint 187 private static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000; 188 189 /** 190 * When set, this ViewGroup's drawable states also include those 191 * of its children. 192 */ 193 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000; 194 195 /** 196 * When set, this ViewGroup tries to always draw its children using their drawing cache. 197 */ 198 private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000; 199 200 /** 201 * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to 202 * draw its children with their drawing cache. 203 */ 204 private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000; 205 206 /** 207 * When set, this group will go through its list of children to notify them of 208 * any drawable state change. 209 */ 210 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000; 211 212 private static final int FLAG_MASK_FOCUSABILITY = 0x60000; 213 214 /** 215 * This view will get focus before any of its descendants. 216 */ 217 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000; 218 219 /** 220 * This view will get focus only if none of its descendants want it. 221 */ 222 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000; 223 224 /** 225 * This view will block any of its descendants from getting focus, even 226 * if they are focusable. 227 */ 228 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000; 229 230 /** 231 * Used to map between enum in attrubutes and flag values. 232 */ 233 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS = 234 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, 235 FOCUS_BLOCK_DESCENDANTS}; 236 237 /** 238 * When set, this ViewGroup should not intercept touch events. 239 */ 240 private static final int FLAG_DISALLOW_INTERCEPT = 0x80000; 241 242 /** 243 * Indicates which types of drawing caches are to be kept in memory. 244 * This field should be made private, so it is hidden from the SDK. 245 * {@hide} 246 */ 247 protected int mPersistentDrawingCache; 248 249 /** 250 * Used to indicate that no drawing cache should be kept in memory. 251 */ 252 public static final int PERSISTENT_NO_CACHE = 0x0; 253 254 /** 255 * Used to indicate that the animation drawing cache should be kept in memory. 256 */ 257 public static final int PERSISTENT_ANIMATION_CACHE = 0x1; 258 259 /** 260 * Used to indicate that the scrolling drawing cache should be kept in memory. 261 */ 262 public static final int PERSISTENT_SCROLLING_CACHE = 0x2; 263 264 /** 265 * Used to indicate that all drawing caches should be kept in memory. 266 */ 267 public static final int PERSISTENT_ALL_CACHES = 0x3; 268 269 /** 270 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL 271 * are set at the same time. 272 */ 273 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL; 274 275 // Index of the child's left position in the mLocation array 276 private static final int CHILD_LEFT_INDEX = 0; 277 // Index of the child's top position in the mLocation array 278 private static final int CHILD_TOP_INDEX = 1; 279 280 // Child views of this ViewGroup 281 private View[] mChildren; 282 // Number of valid children in the mChildren array, the rest should be null or not 283 // considered as children 284 private int mChildrenCount; 285 286 private static final int ARRAY_INITIAL_CAPACITY = 12; 287 private static final int ARRAY_CAPACITY_INCREMENT = 12; 288 289 // Used to draw cached views 290 private final Paint mCachePaint = new Paint(); 291 292 public ViewGroup(Context context) { 293 super(context); 294 initViewGroup(); 295 } 296 297 public ViewGroup(Context context, AttributeSet attrs) { 298 super(context, attrs); 299 initViewGroup(); 300 initFromAttributes(context, attrs); 301 } 302 303 public ViewGroup(Context context, AttributeSet attrs, int defStyle) { 304 super(context, attrs, defStyle); 305 initViewGroup(); 306 initFromAttributes(context, attrs); 307 } 308 309 private void initViewGroup() { 310 // ViewGroup doesn't draw by default 311 setFlags(WILL_NOT_DRAW, DRAW_MASK); 312 mGroupFlags |= FLAG_CLIP_CHILDREN; 313 mGroupFlags |= FLAG_CLIP_TO_PADDING; 314 mGroupFlags |= FLAG_ANIMATION_DONE; 315 mGroupFlags |= FLAG_ANIMATION_CACHE; 316 mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE; 317 318 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS); 319 320 mChildren = new View[ARRAY_INITIAL_CAPACITY]; 321 mChildrenCount = 0; 322 323 mCachePaint.setDither(false); 324 325 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE; 326 } 327 328 private void initFromAttributes(Context context, AttributeSet attrs) { 329 TypedArray a = context.obtainStyledAttributes(attrs, 330 R.styleable.ViewGroup); 331 332 final int N = a.getIndexCount(); 333 for (int i = 0; i < N; i++) { 334 int attr = a.getIndex(i); 335 switch (attr) { 336 case R.styleable.ViewGroup_clipChildren: 337 setClipChildren(a.getBoolean(attr, true)); 338 break; 339 case R.styleable.ViewGroup_clipToPadding: 340 setClipToPadding(a.getBoolean(attr, true)); 341 break; 342 case R.styleable.ViewGroup_animationCache: 343 setAnimationCacheEnabled(a.getBoolean(attr, true)); 344 break; 345 case R.styleable.ViewGroup_persistentDrawingCache: 346 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE)); 347 break; 348 case R.styleable.ViewGroup_addStatesFromChildren: 349 setAddStatesFromChildren(a.getBoolean(attr, false)); 350 break; 351 case R.styleable.ViewGroup_alwaysDrawnWithCache: 352 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true)); 353 break; 354 case R.styleable.ViewGroup_layoutAnimation: 355 int id = a.getResourceId(attr, -1); 356 if (id > 0) { 357 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id)); 358 } 359 break; 360 case R.styleable.ViewGroup_descendantFocusability: 361 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]); 362 break; 363 } 364 } 365 366 a.recycle(); 367 } 368 369 /** 370 * Gets the descendant focusability of this view group. The descendant 371 * focusability defines the relationship between this view group and its 372 * descendants when looking for a view to take focus in 373 * {@link #requestFocus(int, android.graphics.Rect)}. 374 * 375 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS}, 376 * {@link #FOCUS_BLOCK_DESCENDANTS}. 377 */ 378 @ViewDebug.ExportedProperty(mapping = { 379 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"), 380 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"), 381 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS") 382 }) 383 public int getDescendantFocusability() { 384 return mGroupFlags & FLAG_MASK_FOCUSABILITY; 385 } 386 387 /** 388 * Set the descendant focusability of this view group. This defines the relationship 389 * between this view group and its descendants when looking for a view to 390 * take focus in {@link #requestFocus(int, android.graphics.Rect)}. 391 * 392 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS}, 393 * {@link #FOCUS_BLOCK_DESCENDANTS}. 394 */ 395 public void setDescendantFocusability(int focusability) { 396 switch (focusability) { 397 case FOCUS_BEFORE_DESCENDANTS: 398 case FOCUS_AFTER_DESCENDANTS: 399 case FOCUS_BLOCK_DESCENDANTS: 400 break; 401 default: 402 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, " 403 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS"); 404 } 405 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY; 406 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY); 407 } 408 409 /** 410 * {@inheritDoc} 411 */ 412 @Override 413 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) { 414 if (mFocused != null) { 415 mFocused.unFocus(); 416 mFocused = null; 417 } 418 super.handleFocusGainInternal(direction, previouslyFocusedRect); 419 } 420 421 /** 422 * {@inheritDoc} 423 */ 424 public void requestChildFocus(View child, View focused) { 425 if (DBG) { 426 System.out.println(this + " requestChildFocus()"); 427 } 428 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) { 429 return; 430 } 431 432 // Unfocus us, if necessary 433 super.unFocus(); 434 435 // We had a previous notion of who had focus. Clear it. 436 if (mFocused != child) { 437 if (mFocused != null) { 438 mFocused.unFocus(); 439 } 440 441 mFocused = child; 442 } 443 if (mParent != null) { 444 mParent.requestChildFocus(this, focused); 445 } 446 } 447 448 /** 449 * {@inheritDoc} 450 */ 451 public void focusableViewAvailable(View v) { 452 if (mParent != null 453 // shortcut: don't report a new focusable view if we block our descendants from 454 // getting focus 455 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS) 456 // shortcut: don't report a new focusable view if we already are focused 457 // (and we don't prefer our descendants) 458 // 459 // note: knowing that mFocused is non-null is not a good enough reason 460 // to break the traversal since in that case we'd actually have to find 461 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and 462 // an ancestor of v; this will get checked for at ViewRoot 463 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) { 464 mParent.focusableViewAvailable(v); 465 } 466 } 467 468 /** 469 * {@inheritDoc} 470 */ 471 public boolean showContextMenuForChild(View originalView) { 472 return mParent != null && mParent.showContextMenuForChild(originalView); 473 } 474 475 /** 476 * Find the nearest view in the specified direction that wants to take 477 * focus. 478 * 479 * @param focused The view that currently has focus 480 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and 481 * FOCUS_RIGHT, or 0 for not applicable. 482 */ 483 public View focusSearch(View focused, int direction) { 484 if (isRootNamespace()) { 485 // root namespace means we should consider ourselves the top of the 486 // tree for focus searching; otherwise we could be focus searching 487 // into other tabs. see LocalActivityManager and TabHost for more info 488 return FocusFinder.getInstance().findNextFocus(this, focused, direction); 489 } else if (mParent != null) { 490 return mParent.focusSearch(focused, direction); 491 } 492 return null; 493 } 494 495 /** 496 * {@inheritDoc} 497 */ 498 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { 499 return false; 500 } 501 502 /** 503 * {@inheritDoc} 504 */ 505 @Override 506 public boolean dispatchUnhandledMove(View focused, int direction) { 507 return mFocused != null && 508 mFocused.dispatchUnhandledMove(focused, direction); 509 } 510 511 /** 512 * {@inheritDoc} 513 */ 514 public void clearChildFocus(View child) { 515 if (DBG) { 516 System.out.println(this + " clearChildFocus()"); 517 } 518 519 mFocused = null; 520 if (mParent != null) { 521 mParent.clearChildFocus(this); 522 } 523 } 524 525 /** 526 * {@inheritDoc} 527 */ 528 @Override 529 public void clearFocus() { 530 super.clearFocus(); 531 532 // clear any child focus if it exists 533 if (mFocused != null) { 534 mFocused.clearFocus(); 535 } 536 } 537 538 /** 539 * {@inheritDoc} 540 */ 541 @Override 542 void unFocus() { 543 if (DBG) { 544 System.out.println(this + " unFocus()"); 545 } 546 547 super.unFocus(); 548 if (mFocused != null) { 549 mFocused.unFocus(); 550 } 551 mFocused = null; 552 } 553 554 /** 555 * Returns the focused child of this view, if any. The child may have focus 556 * or contain focus. 557 * 558 * @return the focused child or null. 559 */ 560 public View getFocusedChild() { 561 return mFocused; 562 } 563 564 /** 565 * Returns true if this view has or contains focus 566 * 567 * @return true if this view has or contains focus 568 */ 569 @Override 570 public boolean hasFocus() { 571 return (mPrivateFlags & FOCUSED) != 0 || mFocused != null; 572 } 573 574 /* 575 * (non-Javadoc) 576 * 577 * @see android.view.View#findFocus() 578 */ 579 @Override 580 public View findFocus() { 581 if (DBG) { 582 System.out.println("Find focus in " + this + ": flags=" 583 + isFocused() + ", child=" + mFocused); 584 } 585 586 if (isFocused()) { 587 return this; 588 } 589 590 if (mFocused != null) { 591 return mFocused.findFocus(); 592 } 593 return null; 594 } 595 596 /** 597 * {@inheritDoc} 598 */ 599 @Override 600 public boolean hasFocusable() { 601 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 602 return false; 603 } 604 605 if (isFocusable()) { 606 return true; 607 } 608 609 final int descendantFocusability = getDescendantFocusability(); 610 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 611 final int count = mChildrenCount; 612 final View[] children = mChildren; 613 614 for (int i = 0; i < count; i++) { 615 final View child = children[i]; 616 if (child.hasFocusable()) { 617 return true; 618 } 619 } 620 } 621 622 return false; 623 } 624 625 /** 626 * {@inheritDoc} 627 */ 628 @Override 629 public void addFocusables(ArrayList<View> views, int direction) { 630 addFocusables(views, direction, FOCUSABLES_TOUCH_MODE); 631 } 632 633 /** 634 * {@inheritDoc} 635 */ 636 @Override 637 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 638 final int focusableCount = views.size(); 639 640 final int descendantFocusability = getDescendantFocusability(); 641 642 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { 643 final int count = mChildrenCount; 644 final View[] children = mChildren; 645 646 for (int i = 0; i < count; i++) { 647 final View child = children[i]; 648 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 649 child.addFocusables(views, direction, focusableMode); 650 } 651 } 652 } 653 654 // we add ourselves (if focusable) in all cases except for when we are 655 // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is 656 // to avoid the focus search finding layouts when a more precise search 657 // among the focusable children would be more interesting. 658 if ( 659 descendantFocusability != FOCUS_AFTER_DESCENDANTS || 660 // No focusable descendants 661 (focusableCount == views.size())) { 662 super.addFocusables(views, direction, focusableMode); 663 } 664 } 665 666 /** 667 * {@inheritDoc} 668 */ 669 @Override 670 public void dispatchWindowFocusChanged(boolean hasFocus) { 671 super.dispatchWindowFocusChanged(hasFocus); 672 final int count = mChildrenCount; 673 final View[] children = mChildren; 674 for (int i = 0; i < count; i++) { 675 children[i].dispatchWindowFocusChanged(hasFocus); 676 } 677 } 678 679 /** 680 * {@inheritDoc} 681 */ 682 @Override 683 public void addTouchables(ArrayList<View> views) { 684 super.addTouchables(views); 685 686 final int count = mChildrenCount; 687 final View[] children = mChildren; 688 689 for (int i = 0; i < count; i++) { 690 final View child = children[i]; 691 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 692 child.addTouchables(views); 693 } 694 } 695 } 696 697 /** 698 * {@inheritDoc} 699 */ 700 @Override 701 public void dispatchDisplayHint(int hint) { 702 super.dispatchDisplayHint(hint); 703 final int count = mChildrenCount; 704 final View[] children = mChildren; 705 for (int i = 0; i < count; i++) { 706 children[i].dispatchDisplayHint(hint); 707 } 708 } 709 710 /** 711 * {@inheritDoc} 712 */ 713 @Override 714 protected void dispatchVisibilityChanged(View changedView, int visibility) { 715 super.dispatchVisibilityChanged(changedView, visibility); 716 final int count = mChildrenCount; 717 final View[] children = mChildren; 718 for (int i = 0; i < count; i++) { 719 children[i].dispatchVisibilityChanged(changedView, visibility); 720 } 721 } 722 723 /** 724 * {@inheritDoc} 725 */ 726 @Override 727 public void dispatchWindowVisibilityChanged(int visibility) { 728 super.dispatchWindowVisibilityChanged(visibility); 729 final int count = mChildrenCount; 730 final View[] children = mChildren; 731 for (int i = 0; i < count; i++) { 732 children[i].dispatchWindowVisibilityChanged(visibility); 733 } 734 } 735 736 /** 737 * {@inheritDoc} 738 */ 739 @Override 740 public void dispatchConfigurationChanged(Configuration newConfig) { 741 super.dispatchConfigurationChanged(newConfig); 742 final int count = mChildrenCount; 743 final View[] children = mChildren; 744 for (int i = 0; i < count; i++) { 745 children[i].dispatchConfigurationChanged(newConfig); 746 } 747 } 748 749 /** 750 * {@inheritDoc} 751 */ 752 public void recomputeViewAttributes(View child) { 753 ViewParent parent = mParent; 754 if (parent != null) parent.recomputeViewAttributes(this); 755 } 756 757 @Override 758 void dispatchCollectViewAttributes(int visibility) { 759 visibility |= mViewFlags&VISIBILITY_MASK; 760 super.dispatchCollectViewAttributes(visibility); 761 final int count = mChildrenCount; 762 final View[] children = mChildren; 763 for (int i = 0; i < count; i++) { 764 children[i].dispatchCollectViewAttributes(visibility); 765 } 766 } 767 768 /** 769 * {@inheritDoc} 770 */ 771 public void bringChildToFront(View child) { 772 int index = indexOfChild(child); 773 if (index >= 0) { 774 removeFromArray(index); 775 addInArray(child, mChildrenCount); 776 child.mParent = this; 777 } 778 } 779 780 /** 781 * {@inheritDoc} 782 */ 783 @Override 784 public boolean dispatchKeyEventPreIme(KeyEvent event) { 785 if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { 786 return super.dispatchKeyEventPreIme(event); 787 } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { 788 return mFocused.dispatchKeyEventPreIme(event); 789 } 790 return false; 791 } 792 793 /** 794 * {@inheritDoc} 795 */ 796 @Override 797 public boolean dispatchKeyEvent(KeyEvent event) { 798 if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { 799 return super.dispatchKeyEvent(event); 800 } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { 801 return mFocused.dispatchKeyEvent(event); 802 } 803 return false; 804 } 805 806 /** 807 * {@inheritDoc} 808 */ 809 @Override 810 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 811 if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { 812 return super.dispatchKeyShortcutEvent(event); 813 } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { 814 return mFocused.dispatchKeyShortcutEvent(event); 815 } 816 return false; 817 } 818 819 /** 820 * {@inheritDoc} 821 */ 822 @Override 823 public boolean dispatchTrackballEvent(MotionEvent event) { 824 if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) { 825 return super.dispatchTrackballEvent(event); 826 } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) { 827 return mFocused.dispatchTrackballEvent(event); 828 } 829 return false; 830 } 831 832 /** 833 * {@inheritDoc} 834 */ 835 @Override 836 public boolean dispatchTouchEvent(MotionEvent ev) { 837 final int action = ev.getAction(); 838 final float xf = ev.getX(); 839 final float yf = ev.getY(); 840 final float scrolledXFloat = xf + mScrollX; 841 final float scrolledYFloat = yf + mScrollY; 842 final Rect frame = mTempRect; 843 844 boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; 845 846 if (action == MotionEvent.ACTION_DOWN) { 847 if (mMotionTarget != null) { 848 // this is weird, we got a pen down, but we thought it was 849 // already down! 850 // XXX: We should probably send an ACTION_UP to the current 851 // target. 852 mMotionTarget = null; 853 } 854 // If we're disallowing intercept or if we're allowing and we didn't 855 // intercept 856 if (disallowIntercept || !onInterceptTouchEvent(ev)) { 857 // reset this event's action (just to protect ourselves) 858 ev.setAction(MotionEvent.ACTION_DOWN); 859 // We know we want to dispatch the event down, find a child 860 // who can handle it, start with the front-most child. 861 final int scrolledXInt = (int) scrolledXFloat; 862 final int scrolledYInt = (int) scrolledYFloat; 863 final View[] children = mChildren; 864 final int count = mChildrenCount; 865 for (int i = count - 1; i >= 0; i--) { 866 final View child = children[i]; 867 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE 868 || child.getAnimation() != null) { 869 child.getHitRect(frame); 870 if (frame.contains(scrolledXInt, scrolledYInt)) { 871 // offset the event to the view's coordinate system 872 final float xc = scrolledXFloat - child.mLeft; 873 final float yc = scrolledYFloat - child.mTop; 874 ev.setLocation(xc, yc); 875 child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; 876 if (child.dispatchTouchEvent(ev)) { 877 // Event handled, we have a target now. 878 mMotionTarget = child; 879 return true; 880 } 881 // The event didn't get handled, try the next view. 882 // Don't reset the event's location, it's not 883 // necessary here. 884 } 885 } 886 } 887 } 888 } 889 890 boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) || 891 (action == MotionEvent.ACTION_CANCEL); 892 893 if (isUpOrCancel) { 894 // Note, we've already copied the previous state to our local 895 // variable, so this takes effect on the next event 896 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; 897 } 898 899 // The event wasn't an ACTION_DOWN, dispatch it to our target if 900 // we have one. 901 final View target = mMotionTarget; 902 if (target == null) { 903 // We don't have a target, this means we're handling the 904 // event as a regular view. 905 ev.setLocation(xf, yf); 906 if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) { 907 ev.setAction(MotionEvent.ACTION_CANCEL); 908 mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; 909 } 910 return super.dispatchTouchEvent(ev); 911 } 912 913 // if have a target, see if we're allowed to and want to intercept its 914 // events 915 if (!disallowIntercept && onInterceptTouchEvent(ev)) { 916 final float xc = scrolledXFloat - (float) target.mLeft; 917 final float yc = scrolledYFloat - (float) target.mTop; 918 mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; 919 ev.setAction(MotionEvent.ACTION_CANCEL); 920 ev.setLocation(xc, yc); 921 if (!target.dispatchTouchEvent(ev)) { 922 // target didn't handle ACTION_CANCEL. not much we can do 923 // but they should have. 924 } 925 // clear the target 926 mMotionTarget = null; 927 // Don't dispatch this event to our own view, because we already 928 // saw it when intercepting; we just want to give the following 929 // event to the normal onTouchEvent(). 930 return true; 931 } 932 933 if (isUpOrCancel) { 934 mMotionTarget = null; 935 } 936 937 // finally offset the event to the target's coordinate system and 938 // dispatch the event. 939 final float xc = scrolledXFloat - (float) target.mLeft; 940 final float yc = scrolledYFloat - (float) target.mTop; 941 ev.setLocation(xc, yc); 942 943 if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) { 944 ev.setAction(MotionEvent.ACTION_CANCEL); 945 target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; 946 mMotionTarget = null; 947 } 948 949 return target.dispatchTouchEvent(ev); 950 } 951 952 /** 953 * {@inheritDoc} 954 */ 955 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 956 957 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) { 958 // We're already in this state, assume our ancestors are too 959 return; 960 } 961 962 if (disallowIntercept) { 963 mGroupFlags |= FLAG_DISALLOW_INTERCEPT; 964 } else { 965 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; 966 } 967 968 // Pass it up to our parent 969 if (mParent != null) { 970 mParent.requestDisallowInterceptTouchEvent(disallowIntercept); 971 } 972 } 973 974 /** 975 * Implement this method to intercept all touch screen motion events. This 976 * allows you to watch events as they are dispatched to your children, and 977 * take ownership of the current gesture at any point. 978 * 979 * <p>Using this function takes some care, as it has a fairly complicated 980 * interaction with {@link View#onTouchEvent(MotionEvent) 981 * View.onTouchEvent(MotionEvent)}, and using it requires implementing 982 * that method as well as this one in the correct way. Events will be 983 * received in the following order: 984 * 985 * <ol> 986 * <li> You will receive the down event here. 987 * <li> The down event will be handled either by a child of this view 988 * group, or given to your own onTouchEvent() method to handle; this means 989 * you should implement onTouchEvent() to return true, so you will 990 * continue to see the rest of the gesture (instead of looking for 991 * a parent view to handle it). Also, by returning true from 992 * onTouchEvent(), you will not receive any following 993 * events in onInterceptTouchEvent() and all touch processing must 994 * happen in onTouchEvent() like normal. 995 * <li> For as long as you return false from this function, each following 996 * event (up to and including the final up) will be delivered first here 997 * and then to the target's onTouchEvent(). 998 * <li> If you return true from here, you will not receive any 999 * following events: the target view will receive the same event but 1000 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further 1001 * events will be delivered to your onTouchEvent() method and no longer 1002 * appear here. 1003 * </ol> 1004 * 1005 * @param ev The motion event being dispatched down the hierarchy. 1006 * @return Return true to steal motion events from the children and have 1007 * them dispatched to this ViewGroup through onTouchEvent(). 1008 * The current target will receive an ACTION_CANCEL event, and no further 1009 * messages will be delivered here. 1010 */ 1011 public boolean onInterceptTouchEvent(MotionEvent ev) { 1012 return false; 1013 } 1014 1015 /** 1016 * {@inheritDoc} 1017 * 1018 * Looks for a view to give focus to respecting the setting specified by 1019 * {@link #getDescendantFocusability()}. 1020 * 1021 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to 1022 * find focus within the children of this group when appropriate. 1023 * 1024 * @see #FOCUS_BEFORE_DESCENDANTS 1025 * @see #FOCUS_AFTER_DESCENDANTS 1026 * @see #FOCUS_BLOCK_DESCENDANTS 1027 * @see #onRequestFocusInDescendants 1028 */ 1029 @Override 1030 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 1031 if (DBG) { 1032 System.out.println(this + " ViewGroup.requestFocus direction=" 1033 + direction); 1034 } 1035 int descendantFocusability = getDescendantFocusability(); 1036 1037 switch (descendantFocusability) { 1038 case FOCUS_BLOCK_DESCENDANTS: 1039 return super.requestFocus(direction, previouslyFocusedRect); 1040 case FOCUS_BEFORE_DESCENDANTS: { 1041 final boolean took = super.requestFocus(direction, previouslyFocusedRect); 1042 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect); 1043 } 1044 case FOCUS_AFTER_DESCENDANTS: { 1045 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect); 1046 return took ? took : super.requestFocus(direction, previouslyFocusedRect); 1047 } 1048 default: 1049 throw new IllegalStateException("descendant focusability must be " 1050 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS " 1051 + "but is " + descendantFocusability); 1052 } 1053 } 1054 1055 /** 1056 * Look for a descendant to call {@link View#requestFocus} on. 1057 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)} 1058 * when it wants to request focus within its children. Override this to 1059 * customize how your {@link ViewGroup} requests focus within its children. 1060 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 1061 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 1062 * to give a finer grained hint about where focus is coming from. May be null 1063 * if there is no hint. 1064 * @return Whether focus was taken. 1065 */ 1066 @SuppressWarnings({"ConstantConditions"}) 1067 protected boolean onRequestFocusInDescendants(int direction, 1068 Rect previouslyFocusedRect) { 1069 int index; 1070 int increment; 1071 int end; 1072 int count = mChildrenCount; 1073 if ((direction & FOCUS_FORWARD) != 0) { 1074 index = 0; 1075 increment = 1; 1076 end = count; 1077 } else { 1078 index = count - 1; 1079 increment = -1; 1080 end = -1; 1081 } 1082 final View[] children = mChildren; 1083 for (int i = index; i != end; i += increment) { 1084 View child = children[i]; 1085 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 1086 if (child.requestFocus(direction, previouslyFocusedRect)) { 1087 return true; 1088 } 1089 } 1090 } 1091 return false; 1092 } 1093 1094 /** 1095 * {@inheritDoc} 1096 * 1097 * @hide 1098 */ 1099 @Override 1100 public void dispatchStartTemporaryDetach() { 1101 super.dispatchStartTemporaryDetach(); 1102 final int count = mChildrenCount; 1103 final View[] children = mChildren; 1104 for (int i = 0; i < count; i++) { 1105 children[i].dispatchStartTemporaryDetach(); 1106 } 1107 } 1108 1109 /** 1110 * {@inheritDoc} 1111 * 1112 * @hide 1113 */ 1114 @Override 1115 public void dispatchFinishTemporaryDetach() { 1116 super.dispatchFinishTemporaryDetach(); 1117 final int count = mChildrenCount; 1118 final View[] children = mChildren; 1119 for (int i = 0; i < count; i++) { 1120 children[i].dispatchFinishTemporaryDetach(); 1121 } 1122 } 1123 1124 /** 1125 * {@inheritDoc} 1126 */ 1127 @Override 1128 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 1129 super.dispatchAttachedToWindow(info, visibility); 1130 visibility |= mViewFlags & VISIBILITY_MASK; 1131 final int count = mChildrenCount; 1132 final View[] children = mChildren; 1133 for (int i = 0; i < count; i++) { 1134 children[i].dispatchAttachedToWindow(info, visibility); 1135 } 1136 } 1137 1138 @Override 1139 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 1140 boolean populated = false; 1141 for (int i = 0, count = getChildCount(); i < count; i++) { 1142 populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event); 1143 } 1144 return populated; 1145 } 1146 1147 /** 1148 * {@inheritDoc} 1149 */ 1150 @Override 1151 void dispatchDetachedFromWindow() { 1152 // If we still have a motion target, we are still in the process of 1153 // dispatching motion events to a child; we need to get rid of that 1154 // child to avoid dispatching events to it after the window is torn 1155 // down. To make sure we keep the child in a consistent state, we 1156 // first send it an ACTION_CANCEL motion event. 1157 if (mMotionTarget != null) { 1158 final long now = SystemClock.uptimeMillis(); 1159 final MotionEvent event = MotionEvent.obtain(now, now, 1160 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); 1161 mMotionTarget.dispatchTouchEvent(event); 1162 event.recycle(); 1163 mMotionTarget = null; 1164 } 1165 1166 final int count = mChildrenCount; 1167 final View[] children = mChildren; 1168 for (int i = 0; i < count; i++) { 1169 children[i].dispatchDetachedFromWindow(); 1170 } 1171 super.dispatchDetachedFromWindow(); 1172 } 1173 1174 /** 1175 * {@inheritDoc} 1176 */ 1177 @Override 1178 public void setPadding(int left, int top, int right, int bottom) { 1179 super.setPadding(left, top, right, bottom); 1180 1181 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) { 1182 mGroupFlags |= FLAG_PADDING_NOT_NULL; 1183 } else { 1184 mGroupFlags &= ~FLAG_PADDING_NOT_NULL; 1185 } 1186 } 1187 1188 /** 1189 * {@inheritDoc} 1190 */ 1191 @Override 1192 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 1193 super.dispatchSaveInstanceState(container); 1194 final int count = mChildrenCount; 1195 final View[] children = mChildren; 1196 for (int i = 0; i < count; i++) { 1197 View c = children[i]; 1198 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) { 1199 c.dispatchSaveInstanceState(container); 1200 } 1201 } 1202 } 1203 1204 /** 1205 * Perform dispatching of a {@link #saveHierarchyState freeze()} to only this view, 1206 * not to its children. For use when overriding 1207 * {@link #dispatchSaveInstanceState dispatchFreeze()} to allow subclasses to freeze 1208 * their own state but not the state of their children. 1209 * 1210 * @param container the container 1211 */ 1212 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) { 1213 super.dispatchSaveInstanceState(container); 1214 } 1215 1216 /** 1217 * {@inheritDoc} 1218 */ 1219 @Override 1220 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 1221 super.dispatchRestoreInstanceState(container); 1222 final int count = mChildrenCount; 1223 final View[] children = mChildren; 1224 for (int i = 0; i < count; i++) { 1225 View c = children[i]; 1226 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) { 1227 c.dispatchRestoreInstanceState(container); 1228 } 1229 } 1230 } 1231 1232 /** 1233 * Perform dispatching of a {@link #restoreHierarchyState thaw()} to only this view, 1234 * not to its children. For use when overriding 1235 * {@link #dispatchRestoreInstanceState dispatchThaw()} to allow subclasses to thaw 1236 * their own state but not the state of their children. 1237 * 1238 * @param container the container 1239 */ 1240 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) { 1241 super.dispatchRestoreInstanceState(container); 1242 } 1243 1244 /** 1245 * Enables or disables the drawing cache for each child of this view group. 1246 * 1247 * @param enabled true to enable the cache, false to dispose of it 1248 */ 1249 protected void setChildrenDrawingCacheEnabled(boolean enabled) { 1250 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) { 1251 final View[] children = mChildren; 1252 final int count = mChildrenCount; 1253 for (int i = 0; i < count; i++) { 1254 children[i].setDrawingCacheEnabled(enabled); 1255 } 1256 } 1257 } 1258 1259 @Override 1260 protected void onAnimationStart() { 1261 super.onAnimationStart(); 1262 1263 // When this ViewGroup's animation starts, build the cache for the children 1264 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) { 1265 final int count = mChildrenCount; 1266 final View[] children = mChildren; 1267 1268 for (int i = 0; i < count; i++) { 1269 final View child = children[i]; 1270 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 1271 child.setDrawingCacheEnabled(true); 1272 child.buildDrawingCache(true); 1273 } 1274 } 1275 1276 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE; 1277 } 1278 } 1279 1280 @Override 1281 protected void onAnimationEnd() { 1282 super.onAnimationEnd(); 1283 1284 // When this ViewGroup's animation ends, destroy the cache of the children 1285 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) { 1286 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE; 1287 1288 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) { 1289 setChildrenDrawingCacheEnabled(false); 1290 } 1291 } 1292 } 1293 1294 @Override 1295 Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 1296 int count = mChildrenCount; 1297 int[] visibilities = null; 1298 1299 if (skipChildren) { 1300 visibilities = new int[count]; 1301 for (int i = 0; i < count; i++) { 1302 View child = getChildAt(i); 1303 visibilities[i] = child.getVisibility(); 1304 if (visibilities[i] == View.VISIBLE) { 1305 child.setVisibility(INVISIBLE); 1306 } 1307 } 1308 } 1309 1310 Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren); 1311 1312 if (skipChildren) { 1313 for (int i = 0; i < count; i++) { 1314 getChildAt(i).setVisibility(visibilities[i]); 1315 } 1316 } 1317 1318 return b; 1319 } 1320 1321 /** 1322 * {@inheritDoc} 1323 */ 1324 @Override 1325 protected void dispatchDraw(Canvas canvas) { 1326 final int count = mChildrenCount; 1327 final View[] children = mChildren; 1328 int flags = mGroupFlags; 1329 1330 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) { 1331 final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE; 1332 1333 for (int i = 0; i < count; i++) { 1334 final View child = children[i]; 1335 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) { 1336 final LayoutParams params = child.getLayoutParams(); 1337 attachLayoutAnimationParameters(child, params, i, count); 1338 bindLayoutAnimation(child); 1339 if (cache) { 1340 child.setDrawingCacheEnabled(true); 1341 child.buildDrawingCache(true); 1342 } 1343 } 1344 } 1345 1346 final LayoutAnimationController controller = mLayoutAnimationController; 1347 if (controller.willOverlap()) { 1348 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE; 1349 } 1350 1351 controller.start(); 1352 1353 mGroupFlags &= ~FLAG_RUN_ANIMATION; 1354 mGroupFlags &= ~FLAG_ANIMATION_DONE; 1355 1356 if (cache) { 1357 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE; 1358 } 1359 1360 if (mAnimationListener != null) { 1361 mAnimationListener.onAnimationStart(controller.getAnimation()); 1362 } 1363 } 1364 1365 int saveCount = 0; 1366 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK; 1367 if (clipToPadding) { 1368 saveCount = canvas.save(); 1369 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop, 1370 mScrollX + mRight - mLeft - mPaddingRight, 1371 mScrollY + mBottom - mTop - mPaddingBottom); 1372 1373 } 1374 1375 // We will draw our child's animation, let's reset the flag 1376 mPrivateFlags &= ~DRAW_ANIMATION; 1377 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED; 1378 1379 boolean more = false; 1380 final long drawingTime = getDrawingTime(); 1381 1382 if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) { 1383 for (int i = 0; i < count; i++) { 1384 final View child = children[i]; 1385 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { 1386 more |= drawChild(canvas, child, drawingTime); 1387 } 1388 } 1389 } else { 1390 for (int i = 0; i < count; i++) { 1391 final View child = children[getChildDrawingOrder(count, i)]; 1392 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { 1393 more |= drawChild(canvas, child, drawingTime); 1394 } 1395 } 1396 } 1397 1398 // Draw any disappearing views that have animations 1399 if (mDisappearingChildren != null) { 1400 final ArrayList<View> disappearingChildren = mDisappearingChildren; 1401 final int disappearingCount = disappearingChildren.size() - 1; 1402 // Go backwards -- we may delete as animations finish 1403 for (int i = disappearingCount; i >= 0; i--) { 1404 final View child = disappearingChildren.get(i); 1405 more |= drawChild(canvas, child, drawingTime); 1406 } 1407 } 1408 1409 if (clipToPadding) { 1410 canvas.restoreToCount(saveCount); 1411 } 1412 1413 // mGroupFlags might have been updated by drawChild() 1414 flags = mGroupFlags; 1415 1416 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) { 1417 invalidate(); 1418 } 1419 1420 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 && 1421 mLayoutAnimationController.isDone() && !more) { 1422 // We want to erase the drawing cache and notify the listener after the 1423 // next frame is drawn because one extra invalidate() is caused by 1424 // drawChild() after the animation is over 1425 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER; 1426 final Runnable end = new Runnable() { 1427 public void run() { 1428 notifyAnimationListener(); 1429 } 1430 }; 1431 post(end); 1432 } 1433 } 1434 1435 /** 1436 * Returns the index of the child to draw for this iteration. Override this 1437 * if you want to change the drawing order of children. By default, it 1438 * returns i. 1439 * <p> 1440 * NOTE: In order for this method to be called, you must enable child ordering 1441 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}. 1442 * 1443 * @param i The current iteration. 1444 * @return The index of the child to draw this iteration. 1445 * 1446 * @see #setChildrenDrawingOrderEnabled(boolean) 1447 * @see #isChildrenDrawingOrderEnabled() 1448 */ 1449 protected int getChildDrawingOrder(int childCount, int i) { 1450 return i; 1451 } 1452 1453 private void notifyAnimationListener() { 1454 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER; 1455 mGroupFlags |= FLAG_ANIMATION_DONE; 1456 1457 if (mAnimationListener != null) { 1458 final Runnable end = new Runnable() { 1459 public void run() { 1460 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation()); 1461 } 1462 }; 1463 post(end); 1464 } 1465 1466 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) { 1467 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE; 1468 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) { 1469 setChildrenDrawingCacheEnabled(false); 1470 } 1471 } 1472 1473 invalidate(); 1474 } 1475 1476 /** 1477 * Draw one child of this View Group. This method is responsible for getting 1478 * the canvas in the right state. This includes clipping, translating so 1479 * that the child's scrolled origin is at 0, 0, and applying any animation 1480 * transformations. 1481 * 1482 * @param canvas The canvas on which to draw the child 1483 * @param child Who to draw 1484 * @param drawingTime The time at which draw is occuring 1485 * @return True if an invalidate() was issued 1486 */ 1487 protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 1488 boolean more = false; 1489 1490 final int cl = child.mLeft; 1491 final int ct = child.mTop; 1492 final int cr = child.mRight; 1493 final int cb = child.mBottom; 1494 1495 final int flags = mGroupFlags; 1496 1497 if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) { 1498 mChildTransformation.clear(); 1499 mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION; 1500 } 1501 1502 Transformation transformToApply = null; 1503 Transformation invalidationTransform; 1504 final Animation a = child.getAnimation(); 1505 boolean concatMatrix = false; 1506 1507 boolean scalingRequired = false; 1508 boolean caching = false; 1509 if (!canvas.isHardwareAccelerated() && 1510 (flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE || 1511 (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) { 1512 caching = true; 1513 if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired; 1514 } 1515 1516 if (a != null) { 1517 1518 final boolean initialized = a.isInitialized(); 1519 if (!initialized) { 1520 a.initialize(cr - cl, cb - ct, getWidth(), getHeight()); 1521 a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct); 1522 child.onAnimationStart(); 1523 } 1524 1525 more = a.getTransformation(drawingTime, mChildTransformation, 1526 scalingRequired ? mAttachInfo.mApplicationScale : 1f); 1527 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 1528 if (mInvalidationTransformation == null) { 1529 mInvalidationTransformation = new Transformation(); 1530 } 1531 invalidationTransform = mInvalidationTransformation; 1532 a.getTransformation(drawingTime, invalidationTransform, 1f); 1533 } else { 1534 invalidationTransform = mChildTransformation; 1535 } 1536 transformToApply = mChildTransformation; 1537 1538 concatMatrix = a.willChangeTransformationMatrix(); 1539 1540 if (more) { 1541 if (!a.willChangeBounds()) { 1542 if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) == 1543 FLAG_OPTIMIZE_INVALIDATE) { 1544 mGroupFlags |= FLAG_INVALIDATE_REQUIRED; 1545 } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) { 1546 // The child need to draw an animation, potentially offscreen, so 1547 // make sure we do not cancel invalidate requests 1548 mPrivateFlags |= DRAW_ANIMATION; 1549 invalidate(cl, ct, cr, cb); 1550 } 1551 } else { 1552 if (mInvalidateRegion == null) { 1553 mInvalidateRegion = new RectF(); 1554 } 1555 final RectF region = mInvalidateRegion; 1556 a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, invalidationTransform); 1557 1558 // The child need to draw an animation, potentially offscreen, so 1559 // make sure we do not cancel invalidate requests 1560 mPrivateFlags |= DRAW_ANIMATION; 1561 1562 final int left = cl + (int) region.left; 1563 final int top = ct + (int) region.top; 1564 invalidate(left, top, left + (int) region.width(), top + (int) region.height()); 1565 } 1566 } 1567 } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) == 1568 FLAG_SUPPORT_STATIC_TRANSFORMATIONS) { 1569 final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation); 1570 if (hasTransform) { 1571 final int transformType = mChildTransformation.getTransformationType(); 1572 transformToApply = transformType != Transformation.TYPE_IDENTITY ? 1573 mChildTransformation : null; 1574 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 1575 } 1576 } 1577 1578 // Sets the flag as early as possible to allow draw() implementations 1579 // to call invalidate() successfully when doing animations 1580 child.mPrivateFlags |= DRAWN; 1581 1582 if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) && 1583 (child.mPrivateFlags & DRAW_ANIMATION) == 0) { 1584 return more; 1585 } 1586 1587 child.computeScroll(); 1588 1589 final int sx = child.mScrollX; 1590 final int sy = child.mScrollY; 1591 1592 Bitmap cache = null; 1593 if (caching) { 1594 cache = child.getDrawingCache(true); 1595 } 1596 1597 final boolean hasNoCache = cache == null; 1598 1599 final int restoreTo = canvas.save(); 1600 if (hasNoCache) { 1601 canvas.translate(cl - sx, ct - sy); 1602 } else { 1603 canvas.translate(cl, ct); 1604 if (scalingRequired) { 1605 // mAttachInfo cannot be null, otherwise scalingRequired == false 1606 final float scale = 1.0f / mAttachInfo.mApplicationScale; 1607 canvas.scale(scale, scale); 1608 } 1609 } 1610 1611 float alpha = 1.0f; 1612 1613 if (transformToApply != null) { 1614 if (concatMatrix) { 1615 int transX = 0; 1616 int transY = 0; 1617 if (hasNoCache) { 1618 transX = -sx; 1619 transY = -sy; 1620 } 1621 // Undo the scroll translation, apply the transformation matrix, 1622 // then redo the scroll translate to get the correct result. 1623 canvas.translate(-transX, -transY); 1624 canvas.concat(transformToApply.getMatrix()); 1625 canvas.translate(transX, transY); 1626 mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; 1627 } 1628 1629 alpha = transformToApply.getAlpha(); 1630 if (alpha < 1.0f) { 1631 mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; 1632 } 1633 1634 if (alpha < 1.0f && hasNoCache) { 1635 final int multipliedAlpha = (int) (255 * alpha); 1636 if (!child.onSetAlpha(multipliedAlpha)) { 1637 canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct, multipliedAlpha, 1638 Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); 1639 } else { 1640 child.mPrivateFlags |= ALPHA_SET; 1641 } 1642 } 1643 } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) { 1644 child.onSetAlpha(255); 1645 } 1646 1647 if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { 1648 if (hasNoCache) { 1649 canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct)); 1650 } else { 1651 if (!scalingRequired) { 1652 canvas.clipRect(0, 0, cr - cl, cb - ct); 1653 } else { 1654 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 1655 } 1656 } 1657 } 1658 1659 if (hasNoCache) { 1660 // Fast path for layouts with no backgrounds 1661 if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { 1662 if (ViewDebug.TRACE_HIERARCHY) { 1663 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW); 1664 } 1665 child.mPrivateFlags &= ~DIRTY_MASK; 1666 child.dispatchDraw(canvas); 1667 } else { 1668 child.draw(canvas); 1669 } 1670 } else { 1671 final Paint cachePaint = mCachePaint; 1672 if (alpha < 1.0f) { 1673 cachePaint.setAlpha((int) (alpha * 255)); 1674 mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE; 1675 } else if ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) { 1676 cachePaint.setAlpha(255); 1677 mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE; 1678 } 1679 if (Config.DEBUG && ViewDebug.profileDrawing) { 1680 EventLog.writeEvent(60003, hashCode()); 1681 } 1682 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 1683 } 1684 1685 canvas.restoreToCount(restoreTo); 1686 1687 if (a != null && !more) { 1688 child.onSetAlpha(255); 1689 finishAnimatingView(child, a); 1690 } 1691 1692 return more; 1693 } 1694 1695 /** 1696 * By default, children are clipped to their bounds before drawing. This 1697 * allows view groups to override this behavior for animations, etc. 1698 * 1699 * @param clipChildren true to clip children to their bounds, 1700 * false otherwise 1701 * @attr ref android.R.styleable#ViewGroup_clipChildren 1702 */ 1703 public void setClipChildren(boolean clipChildren) { 1704 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren); 1705 } 1706 1707 /** 1708 * By default, children are clipped to the padding of the ViewGroup. This 1709 * allows view groups to override this behavior 1710 * 1711 * @param clipToPadding true to clip children to the padding of the 1712 * group, false otherwise 1713 * @attr ref android.R.styleable#ViewGroup_clipToPadding 1714 */ 1715 public void setClipToPadding(boolean clipToPadding) { 1716 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding); 1717 } 1718 1719 /** 1720 * {@inheritDoc} 1721 */ 1722 @Override 1723 public void dispatchSetSelected(boolean selected) { 1724 final View[] children = mChildren; 1725 final int count = mChildrenCount; 1726 for (int i = 0; i < count; i++) { 1727 children[i].setSelected(selected); 1728 } 1729 } 1730 1731 @Override 1732 protected void dispatchSetPressed(boolean pressed) { 1733 final View[] children = mChildren; 1734 final int count = mChildrenCount; 1735 for (int i = 0; i < count; i++) { 1736 children[i].setPressed(pressed); 1737 } 1738 } 1739 1740 /** 1741 * When this property is set to true, this ViewGroup supports static transformations on 1742 * children; this causes 1743 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be 1744 * invoked when a child is drawn. 1745 * 1746 * Any subclass overriding 1747 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should 1748 * set this property to true. 1749 * 1750 * @param enabled True to enable static transformations on children, false otherwise. 1751 * 1752 * @see #FLAG_SUPPORT_STATIC_TRANSFORMATIONS 1753 */ 1754 protected void setStaticTransformationsEnabled(boolean enabled) { 1755 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled); 1756 } 1757 1758 /** 1759 * {@inheritDoc} 1760 * 1761 * @see #setStaticTransformationsEnabled(boolean) 1762 */ 1763 protected boolean getChildStaticTransformation(View child, Transformation t) { 1764 return false; 1765 } 1766 1767 /** 1768 * {@hide} 1769 */ 1770 @Override 1771 protected View findViewTraversal(int id) { 1772 if (id == mID) { 1773 return this; 1774 } 1775 1776 final View[] where = mChildren; 1777 final int len = mChildrenCount; 1778 1779 for (int i = 0; i < len; i++) { 1780 View v = where[i]; 1781 1782 if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) { 1783 v = v.findViewById(id); 1784 1785 if (v != null) { 1786 return v; 1787 } 1788 } 1789 } 1790 1791 return null; 1792 } 1793 1794 /** 1795 * {@hide} 1796 */ 1797 @Override 1798 protected View findViewWithTagTraversal(Object tag) { 1799 if (tag != null && tag.equals(mTag)) { 1800 return this; 1801 } 1802 1803 final View[] where = mChildren; 1804 final int len = mChildrenCount; 1805 1806 for (int i = 0; i < len; i++) { 1807 View v = where[i]; 1808 1809 if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) { 1810 v = v.findViewWithTag(tag); 1811 1812 if (v != null) { 1813 return v; 1814 } 1815 } 1816 } 1817 1818 return null; 1819 } 1820 1821 /** 1822 * Adds a child view. If no layout parameters are already set on the child, the 1823 * default parameters for this ViewGroup are set on the child. 1824 * 1825 * @param child the child view to add 1826 * 1827 * @see #generateDefaultLayoutParams() 1828 */ 1829 public void addView(View child) { 1830 addView(child, -1); 1831 } 1832 1833 /** 1834 * Adds a child view. If no layout parameters are already set on the child, the 1835 * default parameters for this ViewGroup are set on the child. 1836 * 1837 * @param child the child view to add 1838 * @param index the position at which to add the child 1839 * 1840 * @see #generateDefaultLayoutParams() 1841 */ 1842 public void addView(View child, int index) { 1843 LayoutParams params = child.getLayoutParams(); 1844 if (params == null) { 1845 params = generateDefaultLayoutParams(); 1846 if (params == null) { 1847 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); 1848 } 1849 } 1850 addView(child, index, params); 1851 } 1852 1853 /** 1854 * Adds a child view with this ViewGroup's default layout parameters and the 1855 * specified width and height. 1856 * 1857 * @param child the child view to add 1858 */ 1859 public void addView(View child, int width, int height) { 1860 final LayoutParams params = generateDefaultLayoutParams(); 1861 params.width = width; 1862 params.height = height; 1863 addView(child, -1, params); 1864 } 1865 1866 /** 1867 * Adds a child view with the specified layout parameters. 1868 * 1869 * @param child the child view to add 1870 * @param params the layout parameters to set on the child 1871 */ 1872 public void addView(View child, LayoutParams params) { 1873 addView(child, -1, params); 1874 } 1875 1876 /** 1877 * Adds a child view with the specified layout parameters. 1878 * 1879 * @param child the child view to add 1880 * @param index the position at which to add the child 1881 * @param params the layout parameters to set on the child 1882 */ 1883 public void addView(View child, int index, LayoutParams params) { 1884 if (DBG) { 1885 System.out.println(this + " addView"); 1886 } 1887 1888 // addViewInner() will call child.requestLayout() when setting the new LayoutParams 1889 // therefore, we call requestLayout() on ourselves before, so that the child's request 1890 // will be blocked at our level 1891 requestLayout(); 1892 invalidate(); 1893 addViewInner(child, index, params, false); 1894 } 1895 1896 /** 1897 * {@inheritDoc} 1898 */ 1899 public void updateViewLayout(View view, ViewGroup.LayoutParams params) { 1900 if (!checkLayoutParams(params)) { 1901 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this); 1902 } 1903 if (view.mParent != this) { 1904 throw new IllegalArgumentException("Given view not a child of " + this); 1905 } 1906 view.setLayoutParams(params); 1907 } 1908 1909 /** 1910 * {@inheritDoc} 1911 */ 1912 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 1913 return p != null; 1914 } 1915 1916 /** 1917 * Interface definition for a callback to be invoked when the hierarchy 1918 * within this view changed. The hierarchy changes whenever a child is added 1919 * to or removed from this view. 1920 */ 1921 public interface OnHierarchyChangeListener { 1922 /** 1923 * Called when a new child is added to a parent view. 1924 * 1925 * @param parent the view in which a child was added 1926 * @param child the new child view added in the hierarchy 1927 */ 1928 void onChildViewAdded(View parent, View child); 1929 1930 /** 1931 * Called when a child is removed from a parent view. 1932 * 1933 * @param parent the view from which the child was removed 1934 * @param child the child removed from the hierarchy 1935 */ 1936 void onChildViewRemoved(View parent, View child); 1937 } 1938 1939 /** 1940 * Register a callback to be invoked when a child is added to or removed 1941 * from this view. 1942 * 1943 * @param listener the callback to invoke on hierarchy change 1944 */ 1945 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) { 1946 mOnHierarchyChangeListener = listener; 1947 } 1948 1949 /** 1950 * Adds a view during layout. This is useful if in your onLayout() method, 1951 * you need to add more views (as does the list view for example). 1952 * 1953 * If index is negative, it means put it at the end of the list. 1954 * 1955 * @param child the view to add to the group 1956 * @param index the index at which the child must be added 1957 * @param params the layout parameters to associate with the child 1958 * @return true if the child was added, false otherwise 1959 */ 1960 protected boolean addViewInLayout(View child, int index, LayoutParams params) { 1961 return addViewInLayout(child, index, params, false); 1962 } 1963 1964 /** 1965 * Adds a view during layout. This is useful if in your onLayout() method, 1966 * you need to add more views (as does the list view for example). 1967 * 1968 * If index is negative, it means put it at the end of the list. 1969 * 1970 * @param child the view to add to the group 1971 * @param index the index at which the child must be added 1972 * @param params the layout parameters to associate with the child 1973 * @param preventRequestLayout if true, calling this method will not trigger a 1974 * layout request on child 1975 * @return true if the child was added, false otherwise 1976 */ 1977 protected boolean addViewInLayout(View child, int index, LayoutParams params, 1978 boolean preventRequestLayout) { 1979 child.mParent = null; 1980 addViewInner(child, index, params, preventRequestLayout); 1981 child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN; 1982 return true; 1983 } 1984 1985 /** 1986 * Prevents the specified child to be laid out during the next layout pass. 1987 * 1988 * @param child the child on which to perform the cleanup 1989 */ 1990 protected void cleanupLayoutState(View child) { 1991 child.mPrivateFlags &= ~View.FORCE_LAYOUT; 1992 } 1993 1994 private void addViewInner(View child, int index, LayoutParams params, 1995 boolean preventRequestLayout) { 1996 1997 if (child.getParent() != null) { 1998 throw new IllegalStateException("The specified child already has a parent. " + 1999 "You must call removeView() on the child's parent first."); 2000 } 2001 2002 if (!checkLayoutParams(params)) { 2003 params = generateLayoutParams(params); 2004 } 2005 2006 if (preventRequestLayout) { 2007 child.mLayoutParams = params; 2008 } else { 2009 child.setLayoutParams(params); 2010 } 2011 2012 if (index < 0) { 2013 index = mChildrenCount; 2014 } 2015 2016 addInArray(child, index); 2017 2018 // tell our children 2019 if (preventRequestLayout) { 2020 child.assignParent(this); 2021 } else { 2022 child.mParent = this; 2023 } 2024 2025 if (child.hasFocus()) { 2026 requestChildFocus(child, child.findFocus()); 2027 } 2028 2029 AttachInfo ai = mAttachInfo; 2030 if (ai != null) { 2031 boolean lastKeepOn = ai.mKeepScreenOn; 2032 ai.mKeepScreenOn = false; 2033 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK)); 2034 if (ai.mKeepScreenOn) { 2035 needGlobalAttributesUpdate(true); 2036 } 2037 ai.mKeepScreenOn = lastKeepOn; 2038 } 2039 2040 if (mOnHierarchyChangeListener != null) { 2041 mOnHierarchyChangeListener.onChildViewAdded(this, child); 2042 } 2043 2044 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) { 2045 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE; 2046 } 2047 } 2048 2049 private void addInArray(View child, int index) { 2050 View[] children = mChildren; 2051 final int count = mChildrenCount; 2052 final int size = children.length; 2053 if (index == count) { 2054 if (size == count) { 2055 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT]; 2056 System.arraycopy(children, 0, mChildren, 0, size); 2057 children = mChildren; 2058 } 2059 children[mChildrenCount++] = child; 2060 } else if (index < count) { 2061 if (size == count) { 2062 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT]; 2063 System.arraycopy(children, 0, mChildren, 0, index); 2064 System.arraycopy(children, index, mChildren, index + 1, count - index); 2065 children = mChildren; 2066 } else { 2067 System.arraycopy(children, index, children, index + 1, count - index); 2068 } 2069 children[index] = child; 2070 mChildrenCount++; 2071 } else { 2072 throw new IndexOutOfBoundsException("index=" + index + " count=" + count); 2073 } 2074 } 2075 2076 // This method also sets the child's mParent to null 2077 private void removeFromArray(int index) { 2078 final View[] children = mChildren; 2079 children[index].mParent = null; 2080 final int count = mChildrenCount; 2081 if (index == count - 1) { 2082 children[--mChildrenCount] = null; 2083 } else if (index >= 0 && index < count) { 2084 System.arraycopy(children, index + 1, children, index, count - index - 1); 2085 children[--mChildrenCount] = null; 2086 } else { 2087 throw new IndexOutOfBoundsException(); 2088 } 2089 } 2090 2091 // This method also sets the children's mParent to null 2092 private void removeFromArray(int start, int count) { 2093 final View[] children = mChildren; 2094 final int childrenCount = mChildrenCount; 2095 2096 start = Math.max(0, start); 2097 final int end = Math.min(childrenCount, start + count); 2098 2099 if (start == end) { 2100 return; 2101 } 2102 2103 if (end == childrenCount) { 2104 for (int i = start; i < end; i++) { 2105 children[i].mParent = null; 2106 children[i] = null; 2107 } 2108 } else { 2109 for (int i = start; i < end; i++) { 2110 children[i].mParent = null; 2111 } 2112 2113 // Since we're looping above, we might as well do the copy, but is arraycopy() 2114 // faster than the extra 2 bounds checks we would do in the loop? 2115 System.arraycopy(children, end, children, start, childrenCount - end); 2116 2117 for (int i = childrenCount - (end - start); i < childrenCount; i++) { 2118 children[i] = null; 2119 } 2120 } 2121 2122 mChildrenCount -= (end - start); 2123 } 2124 2125 private void bindLayoutAnimation(View child) { 2126 Animation a = mLayoutAnimationController.getAnimationForView(child); 2127 child.setAnimation(a); 2128 } 2129 2130 /** 2131 * Subclasses should override this method to set layout animation 2132 * parameters on the supplied child. 2133 * 2134 * @param child the child to associate with animation parameters 2135 * @param params the child's layout parameters which hold the animation 2136 * parameters 2137 * @param index the index of the child in the view group 2138 * @param count the number of children in the view group 2139 */ 2140 protected void attachLayoutAnimationParameters(View child, 2141 LayoutParams params, int index, int count) { 2142 LayoutAnimationController.AnimationParameters animationParams = 2143 params.layoutAnimationParameters; 2144 if (animationParams == null) { 2145 animationParams = new LayoutAnimationController.AnimationParameters(); 2146 params.layoutAnimationParameters = animationParams; 2147 } 2148 2149 animationParams.count = count; 2150 animationParams.index = index; 2151 } 2152 2153 /** 2154 * {@inheritDoc} 2155 */ 2156 public void removeView(View view) { 2157 removeViewInternal(view); 2158 requestLayout(); 2159 invalidate(); 2160 } 2161 2162 /** 2163 * Removes a view during layout. This is useful if in your onLayout() method, 2164 * you need to remove more views. 2165 * 2166 * @param view the view to remove from the group 2167 */ 2168 public void removeViewInLayout(View view) { 2169 removeViewInternal(view); 2170 } 2171 2172 /** 2173 * Removes a range of views during layout. This is useful if in your onLayout() method, 2174 * you need to remove more views. 2175 * 2176 * @param start the index of the first view to remove from the group 2177 * @param count the number of views to remove from the group 2178 */ 2179 public void removeViewsInLayout(int start, int count) { 2180 removeViewsInternal(start, count); 2181 } 2182 2183 /** 2184 * Removes the view at the specified position in the group. 2185 * 2186 * @param index the position in the group of the view to remove 2187 */ 2188 public void removeViewAt(int index) { 2189 removeViewInternal(index, getChildAt(index)); 2190 requestLayout(); 2191 invalidate(); 2192 } 2193 2194 /** 2195 * Removes the specified range of views from the group. 2196 * 2197 * @param start the first position in the group of the range of views to remove 2198 * @param count the number of views to remove 2199 */ 2200 public void removeViews(int start, int count) { 2201 removeViewsInternal(start, count); 2202 requestLayout(); 2203 invalidate(); 2204 } 2205 2206 private void removeViewInternal(View view) { 2207 final int index = indexOfChild(view); 2208 if (index >= 0) { 2209 removeViewInternal(index, view); 2210 } 2211 } 2212 2213 private void removeViewInternal(int index, View view) { 2214 boolean clearChildFocus = false; 2215 if (view == mFocused) { 2216 view.clearFocusForRemoval(); 2217 clearChildFocus = true; 2218 } 2219 2220 if (view.getAnimation() != null) { 2221 addDisappearingView(view); 2222 } else if (view.mAttachInfo != null) { 2223 view.dispatchDetachedFromWindow(); 2224 } 2225 2226 if (mOnHierarchyChangeListener != null) { 2227 mOnHierarchyChangeListener.onChildViewRemoved(this, view); 2228 } 2229 2230 needGlobalAttributesUpdate(false); 2231 2232 removeFromArray(index); 2233 2234 if (clearChildFocus) { 2235 clearChildFocus(view); 2236 } 2237 } 2238 2239 private void removeViewsInternal(int start, int count) { 2240 final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener; 2241 final boolean notifyListener = onHierarchyChangeListener != null; 2242 final View focused = mFocused; 2243 final boolean detach = mAttachInfo != null; 2244 View clearChildFocus = null; 2245 2246 final View[] children = mChildren; 2247 final int end = start + count; 2248 2249 for (int i = start; i < end; i++) { 2250 final View view = children[i]; 2251 2252 if (view == focused) { 2253 view.clearFocusForRemoval(); 2254 clearChildFocus = view; 2255 } 2256 2257 if (view.getAnimation() != null) { 2258 addDisappearingView(view); 2259 } else if (detach) { 2260 view.dispatchDetachedFromWindow(); 2261 } 2262 2263 needGlobalAttributesUpdate(false); 2264 2265 if (notifyListener) { 2266 onHierarchyChangeListener.onChildViewRemoved(this, view); 2267 } 2268 } 2269 2270 removeFromArray(start, count); 2271 2272 if (clearChildFocus != null) { 2273 clearChildFocus(clearChildFocus); 2274 } 2275 } 2276 2277 /** 2278 * Call this method to remove all child views from the 2279 * ViewGroup. 2280 */ 2281 public void removeAllViews() { 2282 removeAllViewsInLayout(); 2283 requestLayout(); 2284 invalidate(); 2285 } 2286 2287 /** 2288 * Called by a ViewGroup subclass to remove child views from itself, 2289 * when it must first know its size on screen before it can calculate how many 2290 * child views it will render. An example is a Gallery or a ListView, which 2291 * may "have" 50 children, but actually only render the number of children 2292 * that can currently fit inside the object on screen. Do not call 2293 * this method unless you are extending ViewGroup and understand the 2294 * view measuring and layout pipeline. 2295 */ 2296 public void removeAllViewsInLayout() { 2297 final int count = mChildrenCount; 2298 if (count <= 0) { 2299 return; 2300 } 2301 2302 final View[] children = mChildren; 2303 mChildrenCount = 0; 2304 2305 final OnHierarchyChangeListener listener = mOnHierarchyChangeListener; 2306 final boolean notify = listener != null; 2307 final View focused = mFocused; 2308 final boolean detach = mAttachInfo != null; 2309 View clearChildFocus = null; 2310 2311 needGlobalAttributesUpdate(false); 2312 2313 for (int i = count - 1; i >= 0; i--) { 2314 final View view = children[i]; 2315 2316 if (view == focused) { 2317 view.clearFocusForRemoval(); 2318 clearChildFocus = view; 2319 } 2320 2321 if (view.getAnimation() != null) { 2322 addDisappearingView(view); 2323 } else if (detach) { 2324 view.dispatchDetachedFromWindow(); 2325 } 2326 2327 if (notify) { 2328 listener.onChildViewRemoved(this, view); 2329 } 2330 2331 view.mParent = null; 2332 children[i] = null; 2333 } 2334 2335 if (clearChildFocus != null) { 2336 clearChildFocus(clearChildFocus); 2337 } 2338 } 2339 2340 /** 2341 * Finishes the removal of a detached view. This method will dispatch the detached from 2342 * window event and notify the hierarchy change listener. 2343 * 2344 * @param child the child to be definitely removed from the view hierarchy 2345 * @param animate if true and the view has an animation, the view is placed in the 2346 * disappearing views list, otherwise, it is detached from the window 2347 * 2348 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 2349 * @see #detachAllViewsFromParent() 2350 * @see #detachViewFromParent(View) 2351 * @see #detachViewFromParent(int) 2352 */ 2353 protected void removeDetachedView(View child, boolean animate) { 2354 if (child == mFocused) { 2355 child.clearFocus(); 2356 } 2357 2358 if (animate && child.getAnimation() != null) { 2359 addDisappearingView(child); 2360 } else if (child.mAttachInfo != null) { 2361 child.dispatchDetachedFromWindow(); 2362 } 2363 2364 if (mOnHierarchyChangeListener != null) { 2365 mOnHierarchyChangeListener.onChildViewRemoved(this, child); 2366 } 2367 } 2368 2369 /** 2370 * Attaches a view to this view group. Attaching a view assigns this group as the parent, 2371 * sets the layout parameters and puts the view in the list of children so it can be retrieved 2372 * by calling {@link #getChildAt(int)}. 2373 * 2374 * This method should be called only for view which were detached from their parent. 2375 * 2376 * @param child the child to attach 2377 * @param index the index at which the child should be attached 2378 * @param params the layout parameters of the child 2379 * 2380 * @see #removeDetachedView(View, boolean) 2381 * @see #detachAllViewsFromParent() 2382 * @see #detachViewFromParent(View) 2383 * @see #detachViewFromParent(int) 2384 */ 2385 protected void attachViewToParent(View child, int index, LayoutParams params) { 2386 child.mLayoutParams = params; 2387 2388 if (index < 0) { 2389 index = mChildrenCount; 2390 } 2391 2392 addInArray(child, index); 2393 2394 child.mParent = this; 2395 child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) | DRAWN; 2396 2397 if (child.hasFocus()) { 2398 requestChildFocus(child, child.findFocus()); 2399 } 2400 } 2401 2402 /** 2403 * Detaches a view from its parent. Detaching a view should be temporary and followed 2404 * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)} 2405 * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, 2406 * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}. 2407 * 2408 * @param child the child to detach 2409 * 2410 * @see #detachViewFromParent(int) 2411 * @see #detachViewsFromParent(int, int) 2412 * @see #detachAllViewsFromParent() 2413 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 2414 * @see #removeDetachedView(View, boolean) 2415 */ 2416 protected void detachViewFromParent(View child) { 2417 removeFromArray(indexOfChild(child)); 2418 } 2419 2420 /** 2421 * Detaches a view from its parent. Detaching a view should be temporary and followed 2422 * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)} 2423 * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, 2424 * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}. 2425 * 2426 * @param index the index of the child to detach 2427 * 2428 * @see #detachViewFromParent(View) 2429 * @see #detachAllViewsFromParent() 2430 * @see #detachViewsFromParent(int, int) 2431 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 2432 * @see #removeDetachedView(View, boolean) 2433 */ 2434 protected void detachViewFromParent(int index) { 2435 removeFromArray(index); 2436 } 2437 2438 /** 2439 * Detaches a range of view from their parent. Detaching a view should be temporary and followed 2440 * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)} 2441 * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, its 2442 * parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}. 2443 * 2444 * @param start the first index of the childrend range to detach 2445 * @param count the number of children to detach 2446 * 2447 * @see #detachViewFromParent(View) 2448 * @see #detachViewFromParent(int) 2449 * @see #detachAllViewsFromParent() 2450 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 2451 * @see #removeDetachedView(View, boolean) 2452 */ 2453 protected void detachViewsFromParent(int start, int count) { 2454 removeFromArray(start, count); 2455 } 2456 2457 /** 2458 * Detaches all views from the parent. Detaching a view should be temporary and followed 2459 * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)} 2460 * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, 2461 * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}. 2462 * 2463 * @see #detachViewFromParent(View) 2464 * @see #detachViewFromParent(int) 2465 * @see #detachViewsFromParent(int, int) 2466 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams) 2467 * @see #removeDetachedView(View, boolean) 2468 */ 2469 protected void detachAllViewsFromParent() { 2470 final int count = mChildrenCount; 2471 if (count <= 0) { 2472 return; 2473 } 2474 2475 final View[] children = mChildren; 2476 mChildrenCount = 0; 2477 2478 for (int i = count - 1; i >= 0; i--) { 2479 children[i].mParent = null; 2480 children[i] = null; 2481 } 2482 } 2483 2484 /** 2485 * Don't call or override this method. It is used for the implementation of 2486 * the view hierarchy. 2487 */ 2488 public final void invalidateChild(View child, final Rect dirty) { 2489 if (ViewDebug.TRACE_HIERARCHY) { 2490 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD); 2491 } 2492 2493 ViewParent parent = this; 2494 2495 final AttachInfo attachInfo = mAttachInfo; 2496 if (attachInfo != null) { 2497 final int[] location = attachInfo.mInvalidateChildLocation; 2498 location[CHILD_LEFT_INDEX] = child.mLeft; 2499 location[CHILD_TOP_INDEX] = child.mTop; 2500 2501 // If the child is drawing an animation, we want to copy this flag onto 2502 // ourselves and the parent to make sure the invalidate request goes 2503 // through 2504 final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION; 2505 2506 // Check whether the child that requests the invalidate is fully opaque 2507 final boolean isOpaque = child.isOpaque() && !drawAnimation && 2508 child.getAnimation() != null; 2509 // Mark the child as dirty, using the appropriate flag 2510 // Make sure we do not set both flags at the same time 2511 final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY; 2512 2513 do { 2514 View view = null; 2515 if (parent instanceof View) { 2516 view = (View) parent; 2517 } 2518 2519 if (drawAnimation) { 2520 if (view != null) { 2521 view.mPrivateFlags |= DRAW_ANIMATION; 2522 } else if (parent instanceof ViewRoot) { 2523 ((ViewRoot) parent).mIsAnimating = true; 2524 } 2525 } 2526 2527 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque 2528 // flag coming from the child that initiated the invalidate 2529 if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) { 2530 view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag; 2531 } 2532 2533 parent = parent.invalidateChildInParent(location, dirty); 2534 } while (parent != null); 2535 } 2536 } 2537 2538 /** 2539 * Don't call or override this method. It is used for the implementation of 2540 * the view hierarchy. 2541 * 2542 * This implementation returns null if this ViewGroup does not have a parent, 2543 * if this ViewGroup is already fully invalidated or if the dirty rectangle 2544 * does not intersect with this ViewGroup's bounds. 2545 */ 2546 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) { 2547 if (ViewDebug.TRACE_HIERARCHY) { 2548 ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD_IN_PARENT); 2549 } 2550 2551 if ((mPrivateFlags & DRAWN) == DRAWN) { 2552 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) != 2553 FLAG_OPTIMIZE_INVALIDATE) { 2554 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX, 2555 location[CHILD_TOP_INDEX] - mScrollY); 2556 2557 final int left = mLeft; 2558 final int top = mTop; 2559 2560 if (dirty.intersect(0, 0, mRight - left, mBottom - top) || 2561 (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) { 2562 mPrivateFlags &= ~DRAWING_CACHE_VALID; 2563 2564 location[CHILD_LEFT_INDEX] = left; 2565 location[CHILD_TOP_INDEX] = top; 2566 2567 return mParent; 2568 } 2569 } else { 2570 mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID; 2571 2572 location[CHILD_LEFT_INDEX] = mLeft; 2573 location[CHILD_TOP_INDEX] = mTop; 2574 2575 dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX], 2576 mBottom - location[CHILD_TOP_INDEX]); 2577 2578 return mParent; 2579 } 2580 } 2581 2582 return null; 2583 } 2584 2585 /** 2586 * Offset a rectangle that is in a descendant's coordinate 2587 * space into our coordinate space. 2588 * @param descendant A descendant of this view 2589 * @param rect A rectangle defined in descendant's coordinate space. 2590 */ 2591 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) { 2592 offsetRectBetweenParentAndChild(descendant, rect, true, false); 2593 } 2594 2595 /** 2596 * Offset a rectangle that is in our coordinate space into an ancestor's 2597 * coordinate space. 2598 * @param descendant A descendant of this view 2599 * @param rect A rectangle defined in descendant's coordinate space. 2600 */ 2601 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) { 2602 offsetRectBetweenParentAndChild(descendant, rect, false, false); 2603 } 2604 2605 /** 2606 * Helper method that offsets a rect either from parent to descendant or 2607 * descendant to parent. 2608 */ 2609 void offsetRectBetweenParentAndChild(View descendant, Rect rect, 2610 boolean offsetFromChildToParent, boolean clipToBounds) { 2611 2612 // already in the same coord system :) 2613 if (descendant == this) { 2614 return; 2615 } 2616 2617 ViewParent theParent = descendant.mParent; 2618 2619 // search and offset up to the parent 2620 while ((theParent != null) 2621 && (theParent instanceof View) 2622 && (theParent != this)) { 2623 2624 if (offsetFromChildToParent) { 2625 rect.offset(descendant.mLeft - descendant.mScrollX, 2626 descendant.mTop - descendant.mScrollY); 2627 if (clipToBounds) { 2628 View p = (View) theParent; 2629 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop); 2630 } 2631 } else { 2632 if (clipToBounds) { 2633 View p = (View) theParent; 2634 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop); 2635 } 2636 rect.offset(descendant.mScrollX - descendant.mLeft, 2637 descendant.mScrollY - descendant.mTop); 2638 } 2639 2640 descendant = (View) theParent; 2641 theParent = descendant.mParent; 2642 } 2643 2644 // now that we are up to this view, need to offset one more time 2645 // to get into our coordinate space 2646 if (theParent == this) { 2647 if (offsetFromChildToParent) { 2648 rect.offset(descendant.mLeft - descendant.mScrollX, 2649 descendant.mTop - descendant.mScrollY); 2650 } else { 2651 rect.offset(descendant.mScrollX - descendant.mLeft, 2652 descendant.mScrollY - descendant.mTop); 2653 } 2654 } else { 2655 throw new IllegalArgumentException("parameter must be a descendant of this view"); 2656 } 2657 } 2658 2659 /** 2660 * Offset the vertical location of all children of this view by the specified number of pixels. 2661 * 2662 * @param offset the number of pixels to offset 2663 * 2664 * @hide 2665 */ 2666 public void offsetChildrenTopAndBottom(int offset) { 2667 final int count = mChildrenCount; 2668 final View[] children = mChildren; 2669 2670 for (int i = 0; i < count; i++) { 2671 final View v = children[i]; 2672 v.mTop += offset; 2673 v.mBottom += offset; 2674 } 2675 } 2676 2677 /** 2678 * {@inheritDoc} 2679 */ 2680 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) { 2681 int dx = child.mLeft - mScrollX; 2682 int dy = child.mTop - mScrollY; 2683 if (offset != null) { 2684 offset.x += dx; 2685 offset.y += dy; 2686 } 2687 r.offset(dx, dy); 2688 return r.intersect(0, 0, mRight - mLeft, mBottom - mTop) && 2689 (mParent == null || mParent.getChildVisibleRect(this, r, offset)); 2690 } 2691 2692 /** 2693 * {@inheritDoc} 2694 */ 2695 @Override 2696 protected abstract void onLayout(boolean changed, 2697 int l, int t, int r, int b); 2698 2699 /** 2700 * Indicates whether the view group has the ability to animate its children 2701 * after the first layout. 2702 * 2703 * @return true if the children can be animated, false otherwise 2704 */ 2705 protected boolean canAnimate() { 2706 return mLayoutAnimationController != null; 2707 } 2708 2709 /** 2710 * Runs the layout animation. Calling this method triggers a relayout of 2711 * this view group. 2712 */ 2713 public void startLayoutAnimation() { 2714 if (mLayoutAnimationController != null) { 2715 mGroupFlags |= FLAG_RUN_ANIMATION; 2716 requestLayout(); 2717 } 2718 } 2719 2720 /** 2721 * Schedules the layout animation to be played after the next layout pass 2722 * of this view group. This can be used to restart the layout animation 2723 * when the content of the view group changes or when the activity is 2724 * paused and resumed. 2725 */ 2726 public void scheduleLayoutAnimation() { 2727 mGroupFlags |= FLAG_RUN_ANIMATION; 2728 } 2729 2730 /** 2731 * Sets the layout animation controller used to animate the group's 2732 * children after the first layout. 2733 * 2734 * @param controller the animation controller 2735 */ 2736 public void setLayoutAnimation(LayoutAnimationController controller) { 2737 mLayoutAnimationController = controller; 2738 if (mLayoutAnimationController != null) { 2739 mGroupFlags |= FLAG_RUN_ANIMATION; 2740 } 2741 } 2742 2743 /** 2744 * Returns the layout animation controller used to animate the group's 2745 * children. 2746 * 2747 * @return the current animation controller 2748 */ 2749 public LayoutAnimationController getLayoutAnimation() { 2750 return mLayoutAnimationController; 2751 } 2752 2753 /** 2754 * Indicates whether the children's drawing cache is used during a layout 2755 * animation. By default, the drawing cache is enabled but this will prevent 2756 * nested layout animations from working. To nest animations, you must disable 2757 * the cache. 2758 * 2759 * @return true if the animation cache is enabled, false otherwise 2760 * 2761 * @see #setAnimationCacheEnabled(boolean) 2762 * @see View#setDrawingCacheEnabled(boolean) 2763 */ 2764 @ViewDebug.ExportedProperty 2765 public boolean isAnimationCacheEnabled() { 2766 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE; 2767 } 2768 2769 /** 2770 * Enables or disables the children's drawing cache during a layout animation. 2771 * By default, the drawing cache is enabled but this will prevent nested 2772 * layout animations from working. To nest animations, you must disable the 2773 * cache. 2774 * 2775 * @param enabled true to enable the animation cache, false otherwise 2776 * 2777 * @see #isAnimationCacheEnabled() 2778 * @see View#setDrawingCacheEnabled(boolean) 2779 */ 2780 public void setAnimationCacheEnabled(boolean enabled) { 2781 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled); 2782 } 2783 2784 /** 2785 * Indicates whether this ViewGroup will always try to draw its children using their 2786 * drawing cache. By default this property is enabled. 2787 * 2788 * @return true if the animation cache is enabled, false otherwise 2789 * 2790 * @see #setAlwaysDrawnWithCacheEnabled(boolean) 2791 * @see #setChildrenDrawnWithCacheEnabled(boolean) 2792 * @see View#setDrawingCacheEnabled(boolean) 2793 */ 2794 @ViewDebug.ExportedProperty 2795 public boolean isAlwaysDrawnWithCacheEnabled() { 2796 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE; 2797 } 2798 2799 /** 2800 * Indicates whether this ViewGroup will always try to draw its children using their 2801 * drawing cache. This property can be set to true when the cache rendering is 2802 * slightly different from the children's normal rendering. Renderings can be different, 2803 * for instance, when the cache's quality is set to low. 2804 * 2805 * When this property is disabled, the ViewGroup will use the drawing cache of its 2806 * children only when asked to. It's usually the task of subclasses to tell ViewGroup 2807 * when to start using the drawing cache and when to stop using it. 2808 * 2809 * @param always true to always draw with the drawing cache, false otherwise 2810 * 2811 * @see #isAlwaysDrawnWithCacheEnabled() 2812 * @see #setChildrenDrawnWithCacheEnabled(boolean) 2813 * @see View#setDrawingCacheEnabled(boolean) 2814 * @see View#setDrawingCacheQuality(int) 2815 */ 2816 public void setAlwaysDrawnWithCacheEnabled(boolean always) { 2817 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always); 2818 } 2819 2820 /** 2821 * Indicates whether the ViewGroup is currently drawing its children using 2822 * their drawing cache. 2823 * 2824 * @return true if children should be drawn with their cache, false otherwise 2825 * 2826 * @see #setAlwaysDrawnWithCacheEnabled(boolean) 2827 * @see #setChildrenDrawnWithCacheEnabled(boolean) 2828 */ 2829 @ViewDebug.ExportedProperty 2830 protected boolean isChildrenDrawnWithCacheEnabled() { 2831 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE; 2832 } 2833 2834 /** 2835 * Tells the ViewGroup to draw its children using their drawing cache. This property 2836 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache 2837 * will be used only if it has been enabled. 2838 * 2839 * Subclasses should call this method to start and stop using the drawing cache when 2840 * they perform performance sensitive operations, like scrolling or animating. 2841 * 2842 * @param enabled true if children should be drawn with their cache, false otherwise 2843 * 2844 * @see #setAlwaysDrawnWithCacheEnabled(boolean) 2845 * @see #isChildrenDrawnWithCacheEnabled() 2846 */ 2847 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 2848 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled); 2849 } 2850 2851 /** 2852 * Indicates whether the ViewGroup is drawing its children in the order defined by 2853 * {@link #getChildDrawingOrder(int, int)}. 2854 * 2855 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)}, 2856 * false otherwise 2857 * 2858 * @see #setChildrenDrawingOrderEnabled(boolean) 2859 * @see #getChildDrawingOrder(int, int) 2860 */ 2861 @ViewDebug.ExportedProperty 2862 protected boolean isChildrenDrawingOrderEnabled() { 2863 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER; 2864 } 2865 2866 /** 2867 * Tells the ViewGroup whether to draw its children in the order defined by the method 2868 * {@link #getChildDrawingOrder(int, int)}. 2869 * 2870 * @param enabled true if the order of the children when drawing is determined by 2871 * {@link #getChildDrawingOrder(int, int)}, false otherwise 2872 * 2873 * @see #isChildrenDrawingOrderEnabled() 2874 * @see #getChildDrawingOrder(int, int) 2875 */ 2876 protected void setChildrenDrawingOrderEnabled(boolean enabled) { 2877 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled); 2878 } 2879 2880 private void setBooleanFlag(int flag, boolean value) { 2881 if (value) { 2882 mGroupFlags |= flag; 2883 } else { 2884 mGroupFlags &= ~flag; 2885 } 2886 } 2887 2888 /** 2889 * Returns an integer indicating what types of drawing caches are kept in memory. 2890 * 2891 * @see #setPersistentDrawingCache(int) 2892 * @see #setAnimationCacheEnabled(boolean) 2893 * 2894 * @return one or a combination of {@link #PERSISTENT_NO_CACHE}, 2895 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE} 2896 * and {@link #PERSISTENT_ALL_CACHES} 2897 */ 2898 @ViewDebug.ExportedProperty(mapping = { 2899 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"), 2900 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"), 2901 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"), 2902 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL") 2903 }) 2904 public int getPersistentDrawingCache() { 2905 return mPersistentDrawingCache; 2906 } 2907 2908 /** 2909 * Indicates what types of drawing caches should be kept in memory after 2910 * they have been created. 2911 * 2912 * @see #getPersistentDrawingCache() 2913 * @see #setAnimationCacheEnabled(boolean) 2914 * 2915 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE}, 2916 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE} 2917 * and {@link #PERSISTENT_ALL_CACHES} 2918 */ 2919 public void setPersistentDrawingCache(int drawingCacheToKeep) { 2920 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES; 2921 } 2922 2923 /** 2924 * Returns a new set of layout parameters based on the supplied attributes set. 2925 * 2926 * @param attrs the attributes to build the layout parameters from 2927 * 2928 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one 2929 * of its descendants 2930 */ 2931 public LayoutParams generateLayoutParams(AttributeSet attrs) { 2932 return new LayoutParams(getContext(), attrs); 2933 } 2934 2935 /** 2936 * Returns a safe set of layout parameters based on the supplied layout params. 2937 * When a ViewGroup is passed a View whose layout params do not pass the test of 2938 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method 2939 * is invoked. This method should return a new set of layout params suitable for 2940 * this ViewGroup, possibly by copying the appropriate attributes from the 2941 * specified set of layout params. 2942 * 2943 * @param p The layout parameters to convert into a suitable set of layout parameters 2944 * for this ViewGroup. 2945 * 2946 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one 2947 * of its descendants 2948 */ 2949 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 2950 return p; 2951 } 2952 2953 /** 2954 * Returns a set of default layout parameters. These parameters are requested 2955 * when the View passed to {@link #addView(View)} has no layout parameters 2956 * already set. If null is returned, an exception is thrown from addView. 2957 * 2958 * @return a set of default layout parameters or null 2959 */ 2960 protected LayoutParams generateDefaultLayoutParams() { 2961 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 2962 } 2963 2964 /** 2965 * @hide 2966 */ 2967 @Override 2968 protected boolean dispatchConsistencyCheck(int consistency) { 2969 boolean result = super.dispatchConsistencyCheck(consistency); 2970 2971 final int count = mChildrenCount; 2972 final View[] children = mChildren; 2973 for (int i = 0; i < count; i++) { 2974 if (!children[i].dispatchConsistencyCheck(consistency)) result = false; 2975 } 2976 2977 return result; 2978 } 2979 2980 /** 2981 * @hide 2982 */ 2983 @Override 2984 protected boolean onConsistencyCheck(int consistency) { 2985 boolean result = super.onConsistencyCheck(consistency); 2986 2987 final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0; 2988 final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0; 2989 2990 if (checkLayout) { 2991 final int count = mChildrenCount; 2992 final View[] children = mChildren; 2993 for (int i = 0; i < count; i++) { 2994 if (children[i].getParent() != this) { 2995 result = false; 2996 android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, 2997 "View " + children[i] + " has no parent/a parent that is not " + this); 2998 } 2999 } 3000 } 3001 3002 if (checkDrawing) { 3003 // If this group is dirty, check that the parent is dirty as well 3004 if ((mPrivateFlags & DIRTY_MASK) != 0) { 3005 final ViewParent parent = getParent(); 3006 if (parent != null && !(parent instanceof ViewRoot)) { 3007 if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) { 3008 result = false; 3009 android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG, 3010 "ViewGroup " + this + " is dirty but its parent is not: " + this); 3011 } 3012 } 3013 } 3014 } 3015 3016 return result; 3017 } 3018 3019 /** 3020 * {@inheritDoc} 3021 */ 3022 @Override 3023 protected void debug(int depth) { 3024 super.debug(depth); 3025 String output; 3026 3027 if (mFocused != null) { 3028 output = debugIndent(depth); 3029 output += "mFocused"; 3030 Log.d(VIEW_LOG_TAG, output); 3031 } 3032 if (mChildrenCount != 0) { 3033 output = debugIndent(depth); 3034 output += "{"; 3035 Log.d(VIEW_LOG_TAG, output); 3036 } 3037 int count = mChildrenCount; 3038 for (int i = 0; i < count; i++) { 3039 View child = mChildren[i]; 3040 child.debug(depth + 1); 3041 } 3042 3043 if (mChildrenCount != 0) { 3044 output = debugIndent(depth); 3045 output += "}"; 3046 Log.d(VIEW_LOG_TAG, output); 3047 } 3048 } 3049 3050 /** 3051 * Returns the position in the group of the specified child view. 3052 * 3053 * @param child the view for which to get the position 3054 * @return a positive integer representing the position of the view in the 3055 * group, or -1 if the view does not exist in the group 3056 */ 3057 public int indexOfChild(View child) { 3058 final int count = mChildrenCount; 3059 final View[] children = mChildren; 3060 for (int i = 0; i < count; i++) { 3061 if (children[i] == child) { 3062 return i; 3063 } 3064 } 3065 return -1; 3066 } 3067 3068 /** 3069 * Returns the number of children in the group. 3070 * 3071 * @return a positive integer representing the number of children in 3072 * the group 3073 */ 3074 public int getChildCount() { 3075 return mChildrenCount; 3076 } 3077 3078 /** 3079 * Returns the view at the specified position in the group. 3080 * 3081 * @param index the position at which to get the view from 3082 * @return the view at the specified position or null if the position 3083 * does not exist within the group 3084 */ 3085 public View getChildAt(int index) { 3086 try { 3087 return mChildren[index]; 3088 } catch (IndexOutOfBoundsException ex) { 3089 return null; 3090 } 3091 } 3092 3093 /** 3094 * Ask all of the children of this view to measure themselves, taking into 3095 * account both the MeasureSpec requirements for this view and its padding. 3096 * We skip children that are in the GONE state The heavy lifting is done in 3097 * getChildMeasureSpec. 3098 * 3099 * @param widthMeasureSpec The width requirements for this view 3100 * @param heightMeasureSpec The height requirements for this view 3101 */ 3102 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) { 3103 final int size = mChildrenCount; 3104 final View[] children = mChildren; 3105 for (int i = 0; i < size; ++i) { 3106 final View child = children[i]; 3107 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) { 3108 measureChild(child, widthMeasureSpec, heightMeasureSpec); 3109 } 3110 } 3111 } 3112 3113 /** 3114 * Ask one of the children of this view to measure itself, taking into 3115 * account both the MeasureSpec requirements for this view and its padding. 3116 * The heavy lifting is done in getChildMeasureSpec. 3117 * 3118 * @param child The child to measure 3119 * @param parentWidthMeasureSpec The width requirements for this view 3120 * @param parentHeightMeasureSpec The height requirements for this view 3121 */ 3122 protected void measureChild(View child, int parentWidthMeasureSpec, 3123 int parentHeightMeasureSpec) { 3124 final LayoutParams lp = child.getLayoutParams(); 3125 3126 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, 3127 mPaddingLeft + mPaddingRight, lp.width); 3128 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, 3129 mPaddingTop + mPaddingBottom, lp.height); 3130 3131 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 3132 } 3133 3134 /** 3135 * Ask one of the children of this view to measure itself, taking into 3136 * account both the MeasureSpec requirements for this view and its padding 3137 * and margins. The child must have MarginLayoutParams The heavy lifting is 3138 * done in getChildMeasureSpec. 3139 * 3140 * @param child The child to measure 3141 * @param parentWidthMeasureSpec The width requirements for this view 3142 * @param widthUsed Extra space that has been used up by the parent 3143 * horizontally (possibly by other children of the parent) 3144 * @param parentHeightMeasureSpec The height requirements for this view 3145 * @param heightUsed Extra space that has been used up by the parent 3146 * vertically (possibly by other children of the parent) 3147 */ 3148 protected void measureChildWithMargins(View child, 3149 int parentWidthMeasureSpec, int widthUsed, 3150 int parentHeightMeasureSpec, int heightUsed) { 3151 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); 3152 3153 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, 3154 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin 3155 + widthUsed, lp.width); 3156 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, 3157 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin 3158 + heightUsed, lp.height); 3159 3160 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); 3161 } 3162 3163 /** 3164 * Does the hard part of measureChildren: figuring out the MeasureSpec to 3165 * pass to a particular child. This method figures out the right MeasureSpec 3166 * for one dimension (height or width) of one child view. 3167 * 3168 * The goal is to combine information from our MeasureSpec with the 3169 * LayoutParams of the child to get the best possible results. For example, 3170 * if the this view knows its size (because its MeasureSpec has a mode of 3171 * EXACTLY), and the child has indicated in its LayoutParams that it wants 3172 * to be the same size as the parent, the parent should ask the child to 3173 * layout given an exact size. 3174 * 3175 * @param spec The requirements for this view 3176 * @param padding The padding of this view for the current dimension and 3177 * margins, if applicable 3178 * @param childDimension How big the child wants to be in the current 3179 * dimension 3180 * @return a MeasureSpec integer for the child 3181 */ 3182 public static int getChildMeasureSpec(int spec, int padding, int childDimension) { 3183 int specMode = MeasureSpec.getMode(spec); 3184 int specSize = MeasureSpec.getSize(spec); 3185 3186 int size = Math.max(0, specSize - padding); 3187 3188 int resultSize = 0; 3189 int resultMode = 0; 3190 3191 switch (specMode) { 3192 // Parent has imposed an exact size on us 3193 case MeasureSpec.EXACTLY: 3194 if (childDimension >= 0) { 3195 resultSize = childDimension; 3196 resultMode = MeasureSpec.EXACTLY; 3197 } else if (childDimension == LayoutParams.MATCH_PARENT) { 3198 // Child wants to be our size. So be it. 3199 resultSize = size; 3200 resultMode = MeasureSpec.EXACTLY; 3201 } else if (childDimension == LayoutParams.WRAP_CONTENT) { 3202 // Child wants to determine its own size. It can't be 3203 // bigger than us. 3204 resultSize = size; 3205 resultMode = MeasureSpec.AT_MOST; 3206 } 3207 break; 3208 3209 // Parent has imposed a maximum size on us 3210 case MeasureSpec.AT_MOST: 3211 if (childDimension >= 0) { 3212 // Child wants a specific size... so be it 3213 resultSize = childDimension; 3214 resultMode = MeasureSpec.EXACTLY; 3215 } else if (childDimension == LayoutParams.MATCH_PARENT) { 3216 // Child wants to be our size, but our size is not fixed. 3217 // Constrain child to not be bigger than us. 3218 resultSize = size; 3219 resultMode = MeasureSpec.AT_MOST; 3220 } else if (childDimension == LayoutParams.WRAP_CONTENT) { 3221 // Child wants to determine its own size. It can't be 3222 // bigger than us. 3223 resultSize = size; 3224 resultMode = MeasureSpec.AT_MOST; 3225 } 3226 break; 3227 3228 // Parent asked to see how big we want to be 3229 case MeasureSpec.UNSPECIFIED: 3230 if (childDimension >= 0) { 3231 // Child wants a specific size... let him have it 3232 resultSize = childDimension; 3233 resultMode = MeasureSpec.EXACTLY; 3234 } else if (childDimension == LayoutParams.MATCH_PARENT) { 3235 // Child wants to be our size... find out how big it should 3236 // be 3237 resultSize = 0; 3238 resultMode = MeasureSpec.UNSPECIFIED; 3239 } else if (childDimension == LayoutParams.WRAP_CONTENT) { 3240 // Child wants to determine its own size.... find out how 3241 // big it should be 3242 resultSize = 0; 3243 resultMode = MeasureSpec.UNSPECIFIED; 3244 } 3245 break; 3246 } 3247 return MeasureSpec.makeMeasureSpec(resultSize, resultMode); 3248 } 3249 3250 3251 /** 3252 * Removes any pending animations for views that have been removed. Call 3253 * this if you don't want animations for exiting views to stack up. 3254 */ 3255 public void clearDisappearingChildren() { 3256 if (mDisappearingChildren != null) { 3257 mDisappearingChildren.clear(); 3258 } 3259 } 3260 3261 /** 3262 * Add a view which is removed from mChildren but still needs animation 3263 * 3264 * @param v View to add 3265 */ 3266 private void addDisappearingView(View v) { 3267 ArrayList<View> disappearingChildren = mDisappearingChildren; 3268 3269 if (disappearingChildren == null) { 3270 disappearingChildren = mDisappearingChildren = new ArrayList<View>(); 3271 } 3272 3273 disappearingChildren.add(v); 3274 } 3275 3276 /** 3277 * Cleanup a view when its animation is done. This may mean removing it from 3278 * the list of disappearing views. 3279 * 3280 * @param view The view whose animation has finished 3281 * @param animation The animation, cannot be null 3282 */ 3283 private void finishAnimatingView(final View view, Animation animation) { 3284 final ArrayList<View> disappearingChildren = mDisappearingChildren; 3285 if (disappearingChildren != null) { 3286 if (disappearingChildren.contains(view)) { 3287 disappearingChildren.remove(view); 3288 3289 if (view.mAttachInfo != null) { 3290 view.dispatchDetachedFromWindow(); 3291 } 3292 3293 view.clearAnimation(); 3294 mGroupFlags |= FLAG_INVALIDATE_REQUIRED; 3295 } 3296 } 3297 3298 if (animation != null && !animation.getFillAfter()) { 3299 view.clearAnimation(); 3300 } 3301 3302 if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) { 3303 view.onAnimationEnd(); 3304 // Should be performed by onAnimationEnd() but this avoid an infinite loop, 3305 // so we'd rather be safe than sorry 3306 view.mPrivateFlags &= ~ANIMATION_STARTED; 3307 // Draw one more frame after the animation is done 3308 mGroupFlags |= FLAG_INVALIDATE_REQUIRED; 3309 } 3310 } 3311 3312 /** 3313 * {@inheritDoc} 3314 */ 3315 @Override 3316 public boolean gatherTransparentRegion(Region region) { 3317 // If no transparent regions requested, we are always opaque. 3318 final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0; 3319 if (meOpaque && region == null) { 3320 // The caller doesn't care about the region, so stop now. 3321 return true; 3322 } 3323 super.gatherTransparentRegion(region); 3324 final View[] children = mChildren; 3325 final int count = mChildrenCount; 3326 boolean noneOfTheChildrenAreTransparent = true; 3327 for (int i = 0; i < count; i++) { 3328 final View child = children[i]; 3329 if ((child.mViewFlags & VISIBILITY_MASK) != GONE || child.getAnimation() != null) { 3330 if (!child.gatherTransparentRegion(region)) { 3331 noneOfTheChildrenAreTransparent = false; 3332 } 3333 } 3334 } 3335 return meOpaque || noneOfTheChildrenAreTransparent; 3336 } 3337 3338 /** 3339 * {@inheritDoc} 3340 */ 3341 public void requestTransparentRegion(View child) { 3342 if (child != null) { 3343 child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS; 3344 if (mParent != null) { 3345 mParent.requestTransparentRegion(this); 3346 } 3347 } 3348 } 3349 3350 3351 @Override 3352 protected boolean fitSystemWindows(Rect insets) { 3353 boolean done = super.fitSystemWindows(insets); 3354 if (!done) { 3355 final int count = mChildrenCount; 3356 final View[] children = mChildren; 3357 for (int i = 0; i < count; i++) { 3358 done = children[i].fitSystemWindows(insets); 3359 if (done) { 3360 break; 3361 } 3362 } 3363 } 3364 return done; 3365 } 3366 3367 /** 3368 * Returns the animation listener to which layout animation events are 3369 * sent. 3370 * 3371 * @return an {@link android.view.animation.Animation.AnimationListener} 3372 */ 3373 public Animation.AnimationListener getLayoutAnimationListener() { 3374 return mAnimationListener; 3375 } 3376 3377 @Override 3378 protected void drawableStateChanged() { 3379 super.drawableStateChanged(); 3380 3381 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) { 3382 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) { 3383 throw new IllegalStateException("addStateFromChildren cannot be enabled if a" 3384 + " child has duplicateParentState set to true"); 3385 } 3386 3387 final View[] children = mChildren; 3388 final int count = mChildrenCount; 3389 3390 for (int i = 0; i < count; i++) { 3391 final View child = children[i]; 3392 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) { 3393 child.refreshDrawableState(); 3394 } 3395 } 3396 } 3397 } 3398 3399 @Override 3400 protected int[] onCreateDrawableState(int extraSpace) { 3401 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) { 3402 return super.onCreateDrawableState(extraSpace); 3403 } 3404 3405 int need = 0; 3406 int n = getChildCount(); 3407 for (int i = 0; i < n; i++) { 3408 int[] childState = getChildAt(i).getDrawableState(); 3409 3410 if (childState != null) { 3411 need += childState.length; 3412 } 3413 } 3414 3415 int[] state = super.onCreateDrawableState(extraSpace + need); 3416 3417 for (int i = 0; i < n; i++) { 3418 int[] childState = getChildAt(i).getDrawableState(); 3419 3420 if (childState != null) { 3421 state = mergeDrawableStates(state, childState); 3422 } 3423 } 3424 3425 return state; 3426 } 3427 3428 /** 3429 * Sets whether this ViewGroup's drawable states also include 3430 * its children's drawable states. This is used, for example, to 3431 * make a group appear to be focused when its child EditText or button 3432 * is focused. 3433 */ 3434 public void setAddStatesFromChildren(boolean addsStates) { 3435 if (addsStates) { 3436 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN; 3437 } else { 3438 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN; 3439 } 3440 3441 refreshDrawableState(); 3442 } 3443 3444 /** 3445 * Returns whether this ViewGroup's drawable states also include 3446 * its children's drawable states. This is used, for example, to 3447 * make a group appear to be focused when its child EditText or button 3448 * is focused. 3449 */ 3450 public boolean addStatesFromChildren() { 3451 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0; 3452 } 3453 3454 /** 3455 * If {link #addStatesFromChildren} is true, refreshes this group's 3456 * drawable state (to include the states from its children). 3457 */ 3458 public void childDrawableStateChanged(View child) { 3459 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) { 3460 refreshDrawableState(); 3461 } 3462 } 3463 3464 /** 3465 * Specifies the animation listener to which layout animation events must 3466 * be sent. Only 3467 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)} 3468 * and 3469 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)} 3470 * are invoked. 3471 * 3472 * @param animationListener the layout animation listener 3473 */ 3474 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) { 3475 mAnimationListener = animationListener; 3476 } 3477 3478 /** 3479 * LayoutParams are used by views to tell their parents how they want to be 3480 * laid out. See 3481 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes} 3482 * for a list of all child view attributes that this class supports. 3483 * 3484 * <p> 3485 * The base LayoutParams class just describes how big the view wants to be 3486 * for both width and height. For each dimension, it can specify one of: 3487 * <ul> 3488 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which 3489 * means that the view wants to be as big as its parent (minus padding) 3490 * <li> WRAP_CONTENT, which means that the view wants to be just big enough 3491 * to enclose its content (plus padding) 3492 * <li> an exact number 3493 * </ul> 3494 * There are subclasses of LayoutParams for different subclasses of 3495 * ViewGroup. For example, AbsoluteLayout has its own subclass of 3496 * LayoutParams which adds an X and Y value. 3497 * 3498 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height 3499 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width 3500 */ 3501 public static class LayoutParams { 3502 /** 3503 * Special value for the height or width requested by a View. 3504 * FILL_PARENT means that the view wants to be as big as its parent, 3505 * minus the parent's padding, if any. This value is deprecated 3506 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}. 3507 */ 3508 @SuppressWarnings({"UnusedDeclaration"}) 3509 @Deprecated 3510 public static final int FILL_PARENT = -1; 3511 3512 /** 3513 * Special value for the height or width requested by a View. 3514 * MATCH_PARENT means that the view wants to be as big as its parent, 3515 * minus the parent's padding, if any. Introduced in API Level 8. 3516 */ 3517 public static final int MATCH_PARENT = -1; 3518 3519 /** 3520 * Special value for the height or width requested by a View. 3521 * WRAP_CONTENT means that the view wants to be just large enough to fit 3522 * its own internal content, taking its own padding into account. 3523 */ 3524 public static final int WRAP_CONTENT = -2; 3525 3526 /** 3527 * Information about how wide the view wants to be. Can be one of the 3528 * constants FILL_PARENT (replaced by MATCH_PARENT , 3529 * in API Level 8) or WRAP_CONTENT. or an exact size. 3530 */ 3531 @ViewDebug.ExportedProperty(mapping = { 3532 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"), 3533 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT") 3534 }) 3535 public int width; 3536 3537 /** 3538 * Information about how tall the view wants to be. Can be one of the 3539 * constants FILL_PARENT (replaced by MATCH_PARENT , 3540 * in API Level 8) or WRAP_CONTENT. or an exact size. 3541 */ 3542 @ViewDebug.ExportedProperty(mapping = { 3543 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"), 3544 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT") 3545 }) 3546 public int height; 3547 3548 /** 3549 * Used to animate layouts. 3550 */ 3551 public LayoutAnimationController.AnimationParameters layoutAnimationParameters; 3552 3553 /** 3554 * Creates a new set of layout parameters. The values are extracted from 3555 * the supplied attributes set and context. The XML attributes mapped 3556 * to this set of layout parameters are: 3557 * 3558 * <ul> 3559 * <li><code>layout_width</code>: the width, either an exact value, 3560 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by 3561 * {@link #MATCH_PARENT} in API Level 8)</li> 3562 * <li><code>layout_height</code>: the height, either an exact value, 3563 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by 3564 * {@link #MATCH_PARENT} in API Level 8)</li> 3565 * </ul> 3566 * 3567 * @param c the application environment 3568 * @param attrs the set of attributes from which to extract the layout 3569 * parameters' values 3570 */ 3571 public LayoutParams(Context c, AttributeSet attrs) { 3572 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout); 3573 setBaseAttributes(a, 3574 R.styleable.ViewGroup_Layout_layout_width, 3575 R.styleable.ViewGroup_Layout_layout_height); 3576 a.recycle(); 3577 } 3578 3579 /** 3580 * Creates a new set of layout parameters with the specified width 3581 * and height. 3582 * 3583 * @param width the width, either {@link #WRAP_CONTENT}, 3584 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in 3585 * API Level 8), or a fixed size in pixels 3586 * @param height the height, either {@link #WRAP_CONTENT}, 3587 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in 3588 * API Level 8), or a fixed size in pixels 3589 */ 3590 public LayoutParams(int width, int height) { 3591 this.width = width; 3592 this.height = height; 3593 } 3594 3595 /** 3596 * Copy constructor. Clones the width and height values of the source. 3597 * 3598 * @param source The layout params to copy from. 3599 */ 3600 public LayoutParams(LayoutParams source) { 3601 this.width = source.width; 3602 this.height = source.height; 3603 } 3604 3605 /** 3606 * Used internally by MarginLayoutParams. 3607 * @hide 3608 */ 3609 LayoutParams() { 3610 } 3611 3612 /** 3613 * Extracts the layout parameters from the supplied attributes. 3614 * 3615 * @param a the style attributes to extract the parameters from 3616 * @param widthAttr the identifier of the width attribute 3617 * @param heightAttr the identifier of the height attribute 3618 */ 3619 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) { 3620 width = a.getLayoutDimension(widthAttr, "layout_width"); 3621 height = a.getLayoutDimension(heightAttr, "layout_height"); 3622 } 3623 3624 /** 3625 * Returns a String representation of this set of layout parameters. 3626 * 3627 * @param output the String to prepend to the internal representation 3628 * @return a String with the following format: output + 3629 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }" 3630 * 3631 * @hide 3632 */ 3633 public String debug(String output) { 3634 return output + "ViewGroup.LayoutParams={ width=" 3635 + sizeToString(width) + ", height=" + sizeToString(height) + " }"; 3636 } 3637 3638 /** 3639 * Converts the specified size to a readable String. 3640 * 3641 * @param size the size to convert 3642 * @return a String instance representing the supplied size 3643 * 3644 * @hide 3645 */ 3646 protected static String sizeToString(int size) { 3647 if (size == WRAP_CONTENT) { 3648 return "wrap-content"; 3649 } 3650 if (size == MATCH_PARENT) { 3651 return "match-parent"; 3652 } 3653 return String.valueOf(size); 3654 } 3655 } 3656 3657 /** 3658 * Per-child layout information for layouts that support margins. 3659 * See 3660 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes} 3661 * for a list of all child view attributes that this class supports. 3662 */ 3663 public static class MarginLayoutParams extends ViewGroup.LayoutParams { 3664 /** 3665 * The left margin in pixels of the child. 3666 */ 3667 @ViewDebug.ExportedProperty 3668 public int leftMargin; 3669 3670 /** 3671 * The top margin in pixels of the child. 3672 */ 3673 @ViewDebug.ExportedProperty 3674 public int topMargin; 3675 3676 /** 3677 * The right margin in pixels of the child. 3678 */ 3679 @ViewDebug.ExportedProperty 3680 public int rightMargin; 3681 3682 /** 3683 * The bottom margin in pixels of the child. 3684 */ 3685 @ViewDebug.ExportedProperty 3686 public int bottomMargin; 3687 3688 /** 3689 * Creates a new set of layout parameters. The values are extracted from 3690 * the supplied attributes set and context. 3691 * 3692 * @param c the application environment 3693 * @param attrs the set of attributes from which to extract the layout 3694 * parameters' values 3695 */ 3696 public MarginLayoutParams(Context c, AttributeSet attrs) { 3697 super(); 3698 3699 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout); 3700 setBaseAttributes(a, 3701 R.styleable.ViewGroup_MarginLayout_layout_width, 3702 R.styleable.ViewGroup_MarginLayout_layout_height); 3703 3704 int margin = a.getDimensionPixelSize( 3705 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1); 3706 if (margin >= 0) { 3707 leftMargin = margin; 3708 topMargin = margin; 3709 rightMargin= margin; 3710 bottomMargin = margin; 3711 } else { 3712 leftMargin = a.getDimensionPixelSize( 3713 R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0); 3714 topMargin = a.getDimensionPixelSize( 3715 R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0); 3716 rightMargin = a.getDimensionPixelSize( 3717 R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0); 3718 bottomMargin = a.getDimensionPixelSize( 3719 R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0); 3720 } 3721 3722 a.recycle(); 3723 } 3724 3725 /** 3726 * {@inheritDoc} 3727 */ 3728 public MarginLayoutParams(int width, int height) { 3729 super(width, height); 3730 } 3731 3732 /** 3733 * Copy constructor. Clones the width, height and margin values of the source. 3734 * 3735 * @param source The layout params to copy from. 3736 */ 3737 public MarginLayoutParams(MarginLayoutParams source) { 3738 this.width = source.width; 3739 this.height = source.height; 3740 3741 this.leftMargin = source.leftMargin; 3742 this.topMargin = source.topMargin; 3743 this.rightMargin = source.rightMargin; 3744 this.bottomMargin = source.bottomMargin; 3745 } 3746 3747 /** 3748 * {@inheritDoc} 3749 */ 3750 public MarginLayoutParams(LayoutParams source) { 3751 super(source); 3752 } 3753 3754 /** 3755 * Sets the margins, in pixels. 3756 * 3757 * @param left the left margin size 3758 * @param top the top margin size 3759 * @param right the right margin size 3760 * @param bottom the bottom margin size 3761 * 3762 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft 3763 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop 3764 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight 3765 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom 3766 */ 3767 public void setMargins(int left, int top, int right, int bottom) { 3768 leftMargin = left; 3769 topMargin = top; 3770 rightMargin = right; 3771 bottomMargin = bottom; 3772 } 3773 } 3774} 3775