1 /* 2 * Copyright (C) 2018 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 17 package android.view.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertSame; 24 import static org.junit.Assert.assertTrue; 25 import static org.junit.Assert.fail; 26 import static org.mockito.ArgumentMatchers.any; 27 import static org.mockito.ArgumentMatchers.eq; 28 import static org.mockito.Mockito.inOrder; 29 import static org.mockito.Mockito.mock; 30 import static org.mockito.Mockito.never; 31 import static org.mockito.Mockito.spy; 32 import static org.mockito.Mockito.times; 33 import static org.mockito.Mockito.verify; 34 import static org.mockito.Mockito.when; 35 36 import android.app.Activity; 37 import android.content.Context; 38 import android.content.Intent; 39 import android.content.pm.PackageManager; 40 import android.content.res.XmlResourceParser; 41 import android.graphics.Bitmap; 42 import android.graphics.Bitmap.Config; 43 import android.graphics.Canvas; 44 import android.graphics.Insets; 45 import android.graphics.Point; 46 import android.graphics.Rect; 47 import android.graphics.Region; 48 import android.graphics.drawable.BitmapDrawable; 49 import android.os.Parcelable; 50 import android.os.SystemClock; 51 import android.util.AttributeSet; 52 import android.util.DisplayMetrics; 53 import android.util.SparseArray; 54 import android.view.ActionMode; 55 import android.view.Display; 56 import android.view.KeyEvent; 57 import android.view.Menu; 58 import android.view.MenuInflater; 59 import android.view.MenuItem; 60 import android.view.MotionEvent; 61 import android.view.PointerIcon; 62 import android.view.View; 63 import android.view.View.BaseSavedState; 64 import android.view.View.MeasureSpec; 65 import android.view.View.OnApplyWindowInsetsListener; 66 import android.view.ViewGroup; 67 import android.view.ViewGroup.LayoutParams; 68 import android.view.WindowInsets; 69 import android.view.WindowManager; 70 import android.view.animation.AlphaAnimation; 71 import android.view.animation.Animation; 72 import android.view.animation.Animation.AnimationListener; 73 import android.view.animation.LayoutAnimationController; 74 import android.view.animation.RotateAnimation; 75 import android.view.animation.Transformation; 76 import android.view.cts.util.EventUtils; 77 import android.view.cts.util.ScrollBarUtils; 78 import android.view.cts.util.XmlUtils; 79 import android.widget.Button; 80 import android.widget.TextView; 81 82 import androidx.annotation.NonNull; 83 import androidx.test.InstrumentationRegistry; 84 import androidx.test.annotation.UiThreadTest; 85 import androidx.test.filters.LargeTest; 86 import androidx.test.filters.MediumTest; 87 import androidx.test.rule.ActivityTestRule; 88 import androidx.test.runner.AndroidJUnit4; 89 90 import com.android.compatibility.common.util.CTSResult; 91 92 import org.junit.Before; 93 import org.junit.Ignore; 94 import org.junit.Rule; 95 import org.junit.Test; 96 import org.junit.runner.RunWith; 97 import org.mockito.InOrder; 98 99 import java.util.ArrayList; 100 101 @MediumTest 102 @RunWith(AndroidJUnit4.class) 103 public class ViewGroupTest implements CTSResult { 104 private Context mContext; 105 private MotionEvent mMotionEvent; 106 private int mResultCode; 107 108 private MockViewGroup mMockViewGroup; 109 private TextView mTextView; 110 private MockTextView mMockTextView; 111 112 @Rule 113 public ActivityTestRule<CtsActivity> mCtsActivityRule = 114 new ActivityTestRule<>(CtsActivity.class, false, false); 115 116 private final Sync mSync = new Sync(); 117 private static class Sync { 118 boolean mHasNotify; 119 } 120 121 @UiThreadTest 122 @Before setup()123 public void setup() { 124 mContext = InstrumentationRegistry.getTargetContext(); 125 mMockViewGroup = new MockViewGroup(mContext); 126 mTextView = new TextView(mContext); 127 mMockTextView = new MockTextView(mContext); 128 } 129 130 @Test testConstructor()131 public void testConstructor() { 132 new MockViewGroup(mContext); 133 new MockViewGroup(mContext, null); 134 new MockViewGroup(mContext, null, 0); 135 } 136 137 @UiThreadTest 138 @Test testAddFocusables()139 public void testAddFocusables() { 140 mMockViewGroup.setFocusable(true); 141 142 // Child is focusable. 143 ArrayList<View> list = new ArrayList<>(); 144 list.add(mTextView); 145 mMockViewGroup.addView(mTextView); 146 mMockViewGroup.addFocusables(list, 0); 147 148 assertEquals(2, list.size()); 149 150 // Parent blocks descendants. 151 list = new ArrayList<>(); 152 list.add(mTextView); 153 mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 154 mMockViewGroup.setFocusable(false); 155 mMockViewGroup.addFocusables(list, 0); 156 assertEquals(1, list.size()); 157 158 // Both parent and child are focusable. 159 list.clear(); 160 mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); 161 mTextView.setFocusable(true); 162 mMockViewGroup.setFocusable(true); 163 mMockViewGroup.addFocusables(list, 0); 164 assertEquals(2, list.size()); 165 } 166 167 @UiThreadTest 168 @Test testAddKeyboardNavigationClusters()169 public void testAddKeyboardNavigationClusters() { 170 View v1 = new MockView(mContext); 171 v1.setFocusableInTouchMode(true); 172 View v2 = new MockView(mContext); 173 v2.setFocusableInTouchMode(true); 174 mMockViewGroup.addView(v1); 175 mMockViewGroup.addView(v2); 176 177 // No clusters. 178 ArrayList<View> list = new ArrayList<>(); 179 mMockViewGroup.addKeyboardNavigationClusters(list, 0); 180 assertEquals(0, list.size()); 181 182 // A cluster and a non-cluster child. 183 v1.setKeyboardNavigationCluster(true); 184 mMockViewGroup.addKeyboardNavigationClusters(list, 0); 185 assertEquals(1, list.size()); 186 assertEquals(v1, list.get(0)); 187 list.clear(); 188 189 // Blocking descendants from getting focus also blocks group search. 190 mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 191 mMockViewGroup.addKeyboardNavigationClusters(list, 0); 192 assertEquals(0, list.size()); 193 mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); 194 195 // Testing the results ordering. 196 v2.setKeyboardNavigationCluster(true); 197 mMockViewGroup.addKeyboardNavigationClusters(list, 0); 198 assertEquals(2, list.size()); 199 assertEquals(v1, list.get(0)); 200 assertEquals(v2, list.get(1)); 201 list.clear(); 202 203 // 3-level hierarchy. 204 ViewGroup parent = new MockViewGroup(mContext); 205 parent.addView(mMockViewGroup); 206 mMockViewGroup.removeView(v2); 207 parent.addKeyboardNavigationClusters(list, 0); 208 assertEquals(1, list.size()); 209 assertEquals(v1, list.get(0)); 210 list.clear(); 211 212 // Cluster with no focusables gets ignored 213 mMockViewGroup.addView(v2); 214 v2.setFocusable(false); 215 mMockViewGroup.addKeyboardNavigationClusters(list, 0); 216 assertEquals(1, list.size()); 217 list.clear(); 218 219 // Invisible children get ignored. 220 mMockViewGroup.setVisibility(View.GONE); 221 parent.addKeyboardNavigationClusters(list, 0); 222 assertEquals(0, list.size()); 223 list.clear(); 224 225 // Nested clusters are ignored 226 TestClusterHier h = new TestClusterHier(); 227 h.nestedGroup.setKeyboardNavigationCluster(true); 228 h.cluster2.setKeyboardNavigationCluster(false); 229 h.top.addKeyboardNavigationClusters(list, View.FOCUS_FORWARD); 230 assertTrue(list.contains(h.nestedGroup)); 231 list.clear(); 232 h.cluster2.setKeyboardNavigationCluster(true); 233 h.top.addKeyboardNavigationClusters(list, View.FOCUS_FORWARD); 234 assertFalse(list.contains(h.nestedGroup)); 235 list.clear(); 236 } 237 238 @UiThreadTest 239 @Test testAddStatesFromChildren()240 public void testAddStatesFromChildren() { 241 mMockViewGroup.addView(mTextView); 242 assertFalse(mMockViewGroup.addStatesFromChildren()); 243 244 mMockViewGroup.setAddStatesFromChildren(true); 245 mTextView.performClick(); 246 assertTrue(mMockViewGroup.addStatesFromChildren()); 247 assertTrue(mMockViewGroup.isDrawableStateChangedCalled); 248 } 249 250 @UiThreadTest 251 @Test testAddTouchables()252 public void testAddTouchables() { 253 mMockViewGroup.setFocusable(true); 254 255 ArrayList<View> list = new ArrayList<>(); 256 mTextView.setVisibility(View.VISIBLE); 257 mTextView.setClickable(true); 258 mTextView.setEnabled(true); 259 260 list.add(mTextView); 261 mMockViewGroup.addView(mTextView); 262 mMockViewGroup.addTouchables(list); 263 264 assertEquals(2, list.size()); 265 266 View v = mMockViewGroup.getChildAt(0); 267 assertSame(mTextView, v); 268 269 v = mMockViewGroup.getChildAt(-1); 270 assertNull(v); 271 272 v = mMockViewGroup.getChildAt(1); 273 assertNull(v); 274 275 v = mMockViewGroup.getChildAt(100); 276 assertNull(v); 277 278 v = mMockViewGroup.getChildAt(-100); 279 assertNull(v); 280 } 281 282 @UiThreadTest 283 @Test testAddView()284 public void testAddView() { 285 assertEquals(0, mMockViewGroup.getChildCount()); 286 287 mMockViewGroup.addView(mTextView); 288 assertEquals(1, mMockViewGroup.getChildCount()); 289 assertTrue(mMockViewGroup.isOnViewAddedCalled); 290 } 291 292 @UiThreadTest 293 @Test testAddViewWithParaViewInt()294 public void testAddViewWithParaViewInt() { 295 assertEquals(0, mMockViewGroup.getChildCount()); 296 297 mMockViewGroup.addView(mTextView, -1); 298 assertEquals(1, mMockViewGroup.getChildCount()); 299 assertTrue(mMockViewGroup.isOnViewAddedCalled); 300 } 301 302 @UiThreadTest 303 @Test testAddViewWithParaViewLayoutPara()304 public void testAddViewWithParaViewLayoutPara() { 305 assertEquals(0, mMockViewGroup.getChildCount()); 306 307 mMockViewGroup.addView(mTextView, new ViewGroup.LayoutParams(100, 200)); 308 309 assertEquals(1, mMockViewGroup.getChildCount()); 310 assertTrue(mMockViewGroup.isOnViewAddedCalled); 311 } 312 313 @UiThreadTest 314 @Test testAddViewWithParaViewIntInt()315 public void testAddViewWithParaViewIntInt() { 316 final int width = 100; 317 final int height = 200; 318 319 assertEquals(0, mMockViewGroup.getChildCount()); 320 321 mMockViewGroup.addView(mTextView, width, height); 322 assertEquals(width, mTextView.getLayoutParams().width); 323 assertEquals(height, mTextView.getLayoutParams().height); 324 325 assertEquals(1, mMockViewGroup.getChildCount()); 326 assertTrue(mMockViewGroup.isOnViewAddedCalled); 327 } 328 329 @UiThreadTest 330 @Test testAddViewWidthParaViewIntLayoutParam()331 public void testAddViewWidthParaViewIntLayoutParam() { 332 assertEquals(0, mMockViewGroup.getChildCount()); 333 334 mMockViewGroup.addView(mTextView, -1, new ViewGroup.LayoutParams(100, 200)); 335 336 assertEquals(1, mMockViewGroup.getChildCount()); 337 assertTrue(mMockViewGroup.isOnViewAddedCalled); 338 } 339 340 @UiThreadTest 341 @Test testAddViewInLayout()342 public void testAddViewInLayout() { 343 assertEquals(0, mMockViewGroup.getChildCount()); 344 345 assertTrue(mMockViewGroup.isRequestLayoutCalled); 346 mMockViewGroup.isRequestLayoutCalled = false; 347 assertTrue(mMockViewGroup.addViewInLayout( 348 mTextView, -1, new ViewGroup.LayoutParams(100, 200))); 349 assertEquals(1, mMockViewGroup.getChildCount()); 350 // check that calling addViewInLayout() does not trigger a 351 // requestLayout() on this ViewGroup 352 assertFalse(mMockViewGroup.isRequestLayoutCalled); 353 assertTrue(mMockViewGroup.isOnViewAddedCalled); 354 } 355 356 @UiThreadTest 357 @Test testAttachLayoutAnimationParameters()358 public void testAttachLayoutAnimationParameters() { 359 ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(10, 10); 360 361 mMockViewGroup.attachLayoutAnimationParameters(null, param, 1, 2); 362 assertEquals(2, param.layoutAnimationParameters.count); 363 assertEquals(1, param.layoutAnimationParameters.index); 364 } 365 366 @UiThreadTest 367 @Test testAttachViewToParent()368 public void testAttachViewToParent() { 369 mMockViewGroup.setFocusable(true); 370 assertEquals(0, mMockViewGroup.getChildCount()); 371 372 ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(10, 10); 373 374 mTextView.setFocusable(true); 375 mMockViewGroup.attachViewToParent(mTextView, -1, param); 376 assertSame(mMockViewGroup, mTextView.getParent()); 377 assertEquals(1, mMockViewGroup.getChildCount()); 378 assertSame(mTextView, mMockViewGroup.getChildAt(0)); 379 } 380 381 @UiThreadTest 382 @Test testAddViewInLayoutWithParamViewIntLayB()383 public void testAddViewInLayoutWithParamViewIntLayB() { 384 assertEquals(0, mMockViewGroup.getChildCount()); 385 386 assertTrue(mMockViewGroup.isRequestLayoutCalled); 387 mMockViewGroup.isRequestLayoutCalled = false; 388 assertTrue(mMockViewGroup.addViewInLayout( 389 mTextView, -1, new ViewGroup.LayoutParams(100, 200), true)); 390 391 assertEquals(1, mMockViewGroup.getChildCount()); 392 // check that calling addViewInLayout() does not trigger a 393 // requestLayout() on this ViewGroup 394 assertFalse(mMockViewGroup.isRequestLayoutCalled); 395 assertTrue(mMockViewGroup.isOnViewAddedCalled); 396 } 397 398 @UiThreadTest 399 @Test testBringChildToFront()400 public void testBringChildToFront() { 401 TextView textView1 = new TextView(mContext); 402 TextView textView2 = new TextView(mContext); 403 404 assertEquals(0, mMockViewGroup.getChildCount()); 405 406 mMockViewGroup.addView(textView1); 407 mMockViewGroup.addView(textView2); 408 assertEquals(2, mMockViewGroup.getChildCount()); 409 410 mMockViewGroup.bringChildToFront(textView1); 411 assertEquals(mMockViewGroup, textView1.getParent()); 412 assertEquals(2, mMockViewGroup.getChildCount()); 413 assertNotNull(mMockViewGroup.getChildAt(0)); 414 assertSame(textView2, mMockViewGroup.getChildAt(0)); 415 416 mMockViewGroup.bringChildToFront(textView2); 417 assertEquals(mMockViewGroup, textView2.getParent()); 418 assertEquals(2, mMockViewGroup.getChildCount()); 419 assertNotNull(mMockViewGroup.getChildAt(0)); 420 assertSame(textView1, mMockViewGroup.getChildAt(0)); 421 } 422 423 @UiThreadTest 424 @Test testCanAnimate()425 public void testCanAnimate() { 426 assertFalse(mMockViewGroup.canAnimate()); 427 428 RotateAnimation animation = new RotateAnimation(0.1f, 0.1f); 429 LayoutAnimationController la = new LayoutAnimationController(animation); 430 mMockViewGroup.setLayoutAnimation(la); 431 assertTrue(mMockViewGroup.canAnimate()); 432 } 433 434 @UiThreadTest 435 @Test testCheckLayoutParams()436 public void testCheckLayoutParams() { 437 assertFalse(mMockViewGroup.checkLayoutParams(null)); 438 439 assertTrue(mMockViewGroup.checkLayoutParams(new ViewGroup.LayoutParams(100, 200))); 440 } 441 442 @UiThreadTest 443 @Test testChildDrawableStateChanged()444 public void testChildDrawableStateChanged() { 445 mMockViewGroup.setAddStatesFromChildren(true); 446 447 mMockViewGroup.childDrawableStateChanged(null); 448 assertTrue(mMockViewGroup.isRefreshDrawableStateCalled); 449 } 450 451 @UiThreadTest 452 @Test testCleanupLayoutState()453 public void testCleanupLayoutState() { 454 assertTrue(mTextView.isLayoutRequested()); 455 456 mMockViewGroup.cleanupLayoutState(mTextView); 457 assertFalse(mTextView.isLayoutRequested()); 458 } 459 460 @UiThreadTest 461 @Test testClearChildFocus()462 public void testClearChildFocus() { 463 mMockViewGroup.addView(mTextView); 464 mMockViewGroup.requestChildFocus(mTextView, null); 465 466 View focusedView = mMockViewGroup.getFocusedChild(); 467 assertSame(mTextView, focusedView); 468 469 mMockViewGroup.clearChildFocus(mTextView); 470 assertNull(mMockViewGroup.getFocusedChild()); 471 } 472 473 @UiThreadTest 474 @Test testClearDisappearingChildren()475 public void testClearDisappearingChildren() { 476 Canvas canvas = new Canvas(); 477 MockViewGroup child = new MockViewGroup(mContext); 478 child.setAnimation(new MockAnimation()); 479 mMockViewGroup.addView(child); 480 assertEquals(1, mMockViewGroup.getChildCount()); 481 482 assertNotNull(child.getAnimation()); 483 mMockViewGroup.dispatchDraw(canvas); 484 assertEquals(1, mMockViewGroup.drawChildCalledTime); 485 486 child.setAnimation(new MockAnimation()); 487 mMockViewGroup.removeAllViewsInLayout(); 488 489 mMockViewGroup.drawChildCalledTime = 0; 490 mMockViewGroup.dispatchDraw(canvas); 491 assertEquals(1, mMockViewGroup.drawChildCalledTime); 492 493 child.setAnimation(new MockAnimation()); 494 mMockViewGroup.clearDisappearingChildren(); 495 496 mMockViewGroup.drawChildCalledTime = 0; 497 mMockViewGroup.dispatchDraw(canvas); 498 assertEquals(0, mMockViewGroup.drawChildCalledTime); 499 } 500 501 @UiThreadTest 502 @Test testClearFocus()503 public void testClearFocus() { 504 mMockViewGroup.addView(mMockTextView); 505 mMockViewGroup.requestChildFocus(mMockTextView, null); 506 mMockViewGroup.clearFocus(); 507 assertTrue(mMockTextView.isClearFocusCalled); 508 } 509 510 @UiThreadTest 511 @Test testDetachAllViewsFromParent()512 public void testDetachAllViewsFromParent() { 513 mMockViewGroup.addView(mTextView); 514 assertEquals(1, mMockViewGroup.getChildCount()); 515 assertSame(mMockViewGroup, mTextView.getParent()); 516 mMockViewGroup.detachAllViewsFromParent(); 517 assertEquals(0, mMockViewGroup.getChildCount()); 518 assertNull(mTextView.getParent()); 519 } 520 521 @UiThreadTest 522 @Test testDetachViewFromParent()523 public void testDetachViewFromParent() { 524 mMockViewGroup.addView(mTextView); 525 assertEquals(1, mMockViewGroup.getChildCount()); 526 527 mMockViewGroup.detachViewFromParent(0); 528 529 assertEquals(0, mMockViewGroup.getChildCount()); 530 assertNull(mTextView.getParent()); 531 } 532 533 @UiThreadTest 534 @Test testDetachViewFromParentWithParamView()535 public void testDetachViewFromParentWithParamView() { 536 mMockViewGroup.addView(mTextView); 537 assertEquals(1, mMockViewGroup.getChildCount()); 538 assertSame(mMockViewGroup, mTextView.getParent()); 539 540 mMockViewGroup.detachViewFromParent(mTextView); 541 542 assertEquals(0, mMockViewGroup.getChildCount()); 543 assertNull(mMockViewGroup.getParent()); 544 } 545 546 @UiThreadTest 547 @Test testDetachViewsFromParent()548 public void testDetachViewsFromParent() { 549 TextView textView1 = new TextView(mContext); 550 TextView textView2 = new TextView(mContext); 551 TextView textView3 = new TextView(mContext); 552 553 mMockViewGroup.addView(textView1); 554 mMockViewGroup.addView(textView2); 555 mMockViewGroup.addView(textView3); 556 assertEquals(3, mMockViewGroup.getChildCount()); 557 558 mMockViewGroup.detachViewsFromParent(0, 2); 559 560 assertEquals(1, mMockViewGroup.getChildCount()); 561 assertNull(textView1.getParent()); 562 assertNull(textView2.getParent()); 563 } 564 565 @UiThreadTest 566 @Test testDispatchDraw()567 public void testDispatchDraw() { 568 Canvas canvas = new Canvas(); 569 570 mMockViewGroup.draw(canvas); 571 assertTrue(mMockViewGroup.isDispatchDrawCalled); 572 assertSame(canvas, mMockViewGroup.canvas); 573 } 574 575 @UiThreadTest 576 @Test testDispatchFreezeSelfOnly()577 public void testDispatchFreezeSelfOnly() { 578 mMockViewGroup.setId(1); 579 mMockViewGroup.setSaveEnabled(true); 580 581 SparseArray container = new SparseArray(); 582 assertEquals(0, container.size()); 583 mMockViewGroup.dispatchFreezeSelfOnly(container); 584 assertEquals(1, container.size()); 585 } 586 587 @UiThreadTest 588 @Test testDispatchKeyEvent()589 public void testDispatchKeyEvent() { 590 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER); 591 assertFalse(mMockViewGroup.dispatchKeyEvent(event)); 592 593 mMockViewGroup.addView(mMockTextView); 594 mMockViewGroup.requestChildFocus(mMockTextView, null); 595 mMockTextView.layout(1, 1, 100, 100); 596 597 assertTrue(mMockViewGroup.dispatchKeyEvent(event)); 598 } 599 600 @UiThreadTest 601 @Test testDispatchSaveInstanceState()602 public void testDispatchSaveInstanceState() { 603 mMockViewGroup.setId(2); 604 mMockViewGroup.setSaveEnabled(true); 605 mMockTextView.setSaveEnabled(true); 606 mMockTextView.setId(1); 607 mMockViewGroup.addView(mMockTextView); 608 609 SparseArray array = new SparseArray(); 610 mMockViewGroup.dispatchSaveInstanceState(array); 611 612 assertTrue(array.size() > 0); 613 assertNotNull(array.get(2)); 614 615 array = new SparseArray(); 616 mMockViewGroup.dispatchRestoreInstanceState(array); 617 assertTrue(mMockTextView.isDispatchRestoreInstanceStateCalled); 618 } 619 620 @UiThreadTest 621 @Test testDispatchSetPressed()622 public void testDispatchSetPressed() { 623 mMockViewGroup.addView(mMockTextView); 624 625 mMockViewGroup.dispatchSetPressed(true); 626 assertTrue(mMockTextView.isPressed()); 627 628 mMockViewGroup.dispatchSetPressed(false); 629 assertFalse(mMockTextView.isPressed()); 630 } 631 632 @UiThreadTest 633 @Test testDispatchSetSelected()634 public void testDispatchSetSelected() { 635 mMockViewGroup.addView(mMockTextView); 636 637 mMockViewGroup.dispatchSetSelected(true); 638 assertTrue(mMockTextView.isSelected()); 639 640 mMockViewGroup.dispatchSetSelected(false); 641 assertFalse(mMockTextView.isSelected()); 642 } 643 644 @UiThreadTest 645 @Test testDispatchThawSelfOnly()646 public void testDispatchThawSelfOnly() { 647 mMockViewGroup.setId(1); 648 SparseArray array = new SparseArray(); 649 array.put(1, BaseSavedState.EMPTY_STATE); 650 651 mMockViewGroup.dispatchThawSelfOnly(array); 652 assertTrue(mMockViewGroup.isOnRestoreInstanceStateCalled); 653 } 654 655 @UiThreadTest 656 @Test testDispatchTouchEvent()657 public void testDispatchTouchEvent() { 658 DisplayMetrics metrics = new DisplayMetrics(); 659 WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 660 Display d = wm.getDefaultDisplay(); 661 d.getMetrics(metrics); 662 int screenWidth = metrics.widthPixels; 663 int screenHeight = metrics.heightPixels; 664 mMockViewGroup.layout(0, 0, screenWidth, screenHeight); 665 mMockViewGroup.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight)); 666 667 mMotionEvent = null; 668 mMockTextView.setOnTouchListener((View v, MotionEvent event) -> { 669 mMotionEvent = event; 670 return true; 671 }); 672 673 mMockTextView.setVisibility(View.VISIBLE); 674 mMockTextView.setEnabled(true); 675 676 mMockViewGroup.addView(mMockTextView, new LayoutParams(screenWidth, screenHeight)); 677 678 mMockViewGroup.requestDisallowInterceptTouchEvent(true); 679 MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(), 680 SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 681 screenWidth / 2, screenHeight / 2, 0); 682 683 assertFalse(mMockViewGroup.dispatchTouchEvent(me)); 684 assertNull(mMotionEvent); 685 686 mMockTextView.layout(0, 0, screenWidth, screenHeight); 687 assertTrue(mMockViewGroup.dispatchTouchEvent(me)); 688 assertSame(me, mMotionEvent); 689 } 690 691 @UiThreadTest 692 @Test testDispatchTrackballEvent()693 public void testDispatchTrackballEvent() { 694 MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(), 695 SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 100, 100, 696 0); 697 assertFalse(mMockViewGroup.dispatchTrackballEvent(me)); 698 699 mMockViewGroup.addView(mMockTextView); 700 mMockTextView.layout(1, 1, 100, 100); 701 mMockViewGroup.requestChildFocus(mMockTextView, null); 702 assertTrue(mMockViewGroup.dispatchTrackballEvent(me)); 703 } 704 705 @UiThreadTest 706 @Test testDispatchUnhandledMove()707 public void testDispatchUnhandledMove() { 708 assertFalse(mMockViewGroup.dispatchUnhandledMove(mMockTextView, View.FOCUS_DOWN)); 709 710 mMockViewGroup.addView(mMockTextView); 711 mMockTextView.layout(1, 1, 100, 100); 712 mMockViewGroup.requestChildFocus(mMockTextView, null); 713 assertTrue(mMockViewGroup.dispatchUnhandledMove(mMockTextView, View.FOCUS_DOWN)); 714 } 715 716 @UiThreadTest 717 @Test testDispatchWindowFocusChanged()718 public void testDispatchWindowFocusChanged() { 719 mMockViewGroup.addView(mMockTextView); 720 mMockTextView.setPressed(true); 721 assertTrue(mMockTextView.isPressed()); 722 723 mMockViewGroup.dispatchWindowFocusChanged(false); 724 assertFalse(mMockTextView.isPressed()); 725 } 726 727 @UiThreadTest 728 @Test testDispatchWindowVisibilityChanged()729 public void testDispatchWindowVisibilityChanged() { 730 int expected = 10; 731 732 mMockViewGroup.addView(mMockTextView); 733 mMockViewGroup.dispatchWindowVisibilityChanged(expected); 734 assertEquals(expected, mMockTextView.visibility); 735 } 736 737 @UiThreadTest 738 @Test testDrawableStateChanged()739 public void testDrawableStateChanged() { 740 mMockTextView.setDuplicateParentStateEnabled(true); 741 742 mMockViewGroup.addView(mMockTextView); 743 mMockViewGroup.setAddStatesFromChildren(false); 744 mMockViewGroup.drawableStateChanged(); 745 assertTrue(mMockTextView.mIsRefreshDrawableStateCalled); 746 } 747 748 @UiThreadTest 749 @Test testDrawChild()750 public void testDrawChild() { 751 mMockViewGroup.addView(mMockTextView); 752 753 MockCanvas canvas = new MockCanvas(); 754 mMockTextView.setBackgroundDrawable(new BitmapDrawable(Bitmap.createBitmap(100, 100, 755 Config.ALPHA_8))); 756 // Configure the size of the view to be non-empty to ensure canvas quickReject calls 757 // will not skip drawing the child 758 mMockTextView.setLeftTopRightBottom(0, 0, 100, 100); 759 assertFalse(mMockViewGroup.drawChild(canvas, mMockTextView, 100)); 760 // test whether child's draw method is called. 761 assertTrue(mMockTextView.isDrawCalled); 762 } 763 764 @UiThreadTest 765 @Test testFindFocus()766 public void testFindFocus() { 767 assertNull(mMockViewGroup.findFocus()); 768 mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 769 mMockViewGroup.setFocusable(true); 770 mMockViewGroup.setVisibility(View.VISIBLE); 771 mMockViewGroup.setFocusableInTouchMode(true); 772 assertTrue(mMockViewGroup.requestFocus(1, new Rect())); 773 774 assertSame(mMockViewGroup, mMockViewGroup.findFocus()); 775 } 776 777 static class MockView extends ViewGroup { 778 779 public int mWidthMeasureSpec; 780 public int mHeightMeasureSpec; 781 MockView(Context context)782 public MockView(Context context) { 783 super(context); 784 } 785 786 @Override onLayout(boolean changed, int l, int t, int r, int b)787 public void onLayout(boolean changed, int l, int t, int r, int b) { 788 } 789 790 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)791 public void onMeasure(int widthMeasureSpec, 792 int heightMeasureSpec) { 793 mWidthMeasureSpec = widthMeasureSpec; 794 mHeightMeasureSpec = heightMeasureSpec; 795 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 796 } 797 } 798 799 @UiThreadTest 800 @Test testFocusableViewAvailable()801 public void testFocusableViewAvailable() { 802 MockView child = new MockView(mContext); 803 mMockViewGroup.addView(child); 804 805 child.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); 806 child.focusableViewAvailable(mMockViewGroup); 807 808 assertTrue(mMockViewGroup.isFocusableViewAvailable); 809 } 810 811 @UiThreadTest 812 @Test testFocusSearch()813 public void testFocusSearch() { 814 MockView child = new MockView(mContext); 815 mMockViewGroup.addView(child); 816 child.addView(mMockTextView); 817 assertSame(mMockTextView, child.focusSearch(mMockTextView, 1)); 818 } 819 820 @UiThreadTest 821 @Test testGatherTransparentRegion()822 public void testGatherTransparentRegion() { 823 Region region = new Region(); 824 mMockTextView.setAnimation(new AlphaAnimation(mContext, null)); 825 mMockTextView.setVisibility(100); 826 mMockViewGroup.addView(mMockTextView); 827 assertEquals(1, mMockViewGroup.getChildCount()); 828 829 assertTrue(mMockViewGroup.gatherTransparentRegion(region)); 830 assertTrue(mMockViewGroup.gatherTransparentRegion(null)); 831 } 832 833 @UiThreadTest 834 @Test testGenerateDefaultLayoutParams()835 public void testGenerateDefaultLayoutParams(){ 836 LayoutParams lp = mMockViewGroup.generateDefaultLayoutParams(); 837 838 assertEquals(LayoutParams.WRAP_CONTENT, lp.width); 839 assertEquals(LayoutParams.WRAP_CONTENT, lp.height); 840 } 841 842 @UiThreadTest 843 @Test testGenerateLayoutParamsWithParaAttributeSet()844 public void testGenerateLayoutParamsWithParaAttributeSet() throws Exception { 845 XmlResourceParser set = mContext.getResources().getLayout( 846 android.view.cts.R.layout.abslistview_layout); 847 XmlUtils.beginDocument(set, "ViewGroup_Layout"); 848 LayoutParams lp = mMockViewGroup.generateLayoutParams(set); 849 assertNotNull(lp); 850 assertEquals(25, lp.height); 851 assertEquals(25, lp.width); 852 } 853 854 @UiThreadTest 855 @Test testGenerateLayoutParams()856 public void testGenerateLayoutParams() { 857 LayoutParams p = new LayoutParams(LayoutParams.WRAP_CONTENT, 858 LayoutParams.MATCH_PARENT); 859 LayoutParams generatedParams = mMockViewGroup.generateLayoutParams(p); 860 assertEquals(generatedParams.getClass(), p.getClass()); 861 assertEquals(p.width, generatedParams.width); 862 assertEquals(p.height, generatedParams.height); 863 } 864 865 @UiThreadTest 866 @Test testGetChildDrawingOrder()867 public void testGetChildDrawingOrder() { 868 assertEquals(1, mMockViewGroup.getChildDrawingOrder(0, 1)); 869 assertEquals(2, mMockViewGroup.getChildDrawingOrder(0, 2)); 870 } 871 872 @Test testGetChildMeasureSpec()873 public void testGetChildMeasureSpec() { 874 int spec = 1; 875 int padding = 1; 876 int childDimension = 1; 877 assertEquals(MeasureSpec.makeMeasureSpec(childDimension, MeasureSpec.EXACTLY), 878 ViewGroup.getChildMeasureSpec(spec, padding, childDimension)); 879 spec = 4; 880 padding = 6; 881 childDimension = 9; 882 assertEquals(MeasureSpec.makeMeasureSpec(childDimension, MeasureSpec.EXACTLY), 883 ViewGroup.getChildMeasureSpec(spec, padding, childDimension)); 884 } 885 886 @UiThreadTest 887 @Test testGetChildStaticTransformation()888 public void testGetChildStaticTransformation() { 889 assertFalse(mMockViewGroup.getChildStaticTransformation(null, null)); 890 } 891 892 @UiThreadTest 893 @Test testGetChildVisibleRect()894 public void testGetChildVisibleRect() { 895 mMockTextView.layout(1, 1, 100, 100); 896 Rect rect = new Rect(1, 1, 50, 50); 897 Point p = new Point(); 898 assertFalse(mMockViewGroup.getChildVisibleRect(mMockTextView, rect, p)); 899 900 mMockTextView.layout(0, 0, 0, 0); 901 mMockViewGroup.layout(20, 20, 60, 60); 902 rect = new Rect(10, 10, 40, 40); 903 p = new Point(); 904 assertTrue(mMockViewGroup.getChildVisibleRect(mMockTextView, rect, p)); 905 } 906 907 @UiThreadTest 908 @Test testGetDescendantFocusability()909 public void testGetDescendantFocusability() { 910 final int FLAG_MASK_FOCUSABILITY = 0x60000; 911 assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0); 912 913 mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 914 assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0); 915 } 916 917 @UiThreadTest 918 @Test testGetLayoutAnimation()919 public void testGetLayoutAnimation() { 920 assertNull(mMockViewGroup.getLayoutAnimation()); 921 RotateAnimation animation = new RotateAnimation(0.1f, 0.1f); 922 LayoutAnimationController la = new LayoutAnimationController(animation); 923 mMockViewGroup.setLayoutAnimation(la); 924 assertTrue(mMockViewGroup.canAnimate()); 925 assertSame(la, mMockViewGroup.getLayoutAnimation()); 926 } 927 928 @UiThreadTest 929 @Test testGetLayoutAnimationListener()930 public void testGetLayoutAnimationListener() { 931 assertNull(mMockViewGroup.getLayoutAnimationListener()); 932 933 AnimationListener al = new AnimationListener() { 934 @Override 935 public void onAnimationEnd(Animation animation) { 936 } 937 938 @Override 939 public void onAnimationRepeat(Animation animation) { 940 } 941 942 @Override 943 public void onAnimationStart(Animation animation) { 944 } 945 }; 946 mMockViewGroup.setLayoutAnimationListener(al); 947 assertSame(al, mMockViewGroup.getLayoutAnimationListener()); 948 } 949 950 @UiThreadTest 951 @Test testGetPersistentDrawingCache()952 public void testGetPersistentDrawingCache() { 953 final int mPersistentDrawingCache1 = 2; 954 final int mPersistentDrawingCache2 = 3; 955 assertEquals(mPersistentDrawingCache1, mMockViewGroup.getPersistentDrawingCache()); 956 957 mMockViewGroup.setPersistentDrawingCache(mPersistentDrawingCache2); 958 assertEquals(mPersistentDrawingCache2, mMockViewGroup.getPersistentDrawingCache()); 959 } 960 961 @UiThreadTest 962 @Test testHasFocus()963 public void testHasFocus() { 964 assertFalse(mMockViewGroup.hasFocus()); 965 966 mMockViewGroup.addView(mTextView); 967 mMockViewGroup.requestChildFocus(mTextView, null); 968 969 assertTrue(mMockViewGroup.hasFocus()); 970 } 971 972 @UiThreadTest 973 @Test testHasFocusable()974 public void testHasFocusable() { 975 assertFalse(mMockViewGroup.hasFocusable()); 976 977 mMockViewGroup.setVisibility(View.VISIBLE); 978 mMockViewGroup.setFocusable(true); 979 assertTrue(mMockViewGroup.hasFocusable()); 980 } 981 982 @UiThreadTest 983 @Test testIndexOfChild()984 public void testIndexOfChild() { 985 assertEquals(-1, mMockViewGroup.indexOfChild(mTextView)); 986 987 mMockViewGroup.addView(mTextView); 988 assertEquals(0, mMockViewGroup.indexOfChild(mTextView)); 989 } 990 991 @LargeTest 992 @Test testInvalidateChild()993 public void testInvalidateChild() { 994 ViewGroupInvalidateChildCtsActivity.setResult(this); 995 996 Context context = InstrumentationRegistry.getTargetContext(); 997 Intent intent = new Intent(context, ViewGroupInvalidateChildCtsActivity.class); 998 intent.setAction(ViewGroupInvalidateChildCtsActivity.ACTION_INVALIDATE_CHILD); 999 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1000 context.startActivity(intent); 1001 1002 waitForResult(); 1003 assertEquals(CTSResult.RESULT_OK, mResultCode); 1004 } 1005 1006 @Test onInterceptHoverEvent_verticalCanScroll_intercepts()1007 public void onInterceptHoverEvent_verticalCanScroll_intercepts() { 1008 onInterceptHoverEvent_scrollabilityAffectsResult(true, true, true); 1009 } 1010 1011 @Test onInterceptHoverEvent_verticalCantScroll_doesntIntercept()1012 public void onInterceptHoverEvent_verticalCantScroll_doesntIntercept() { 1013 onInterceptHoverEvent_scrollabilityAffectsResult(true, false, false); 1014 } 1015 1016 @Test onInterceptHoverEvent_horizontalCanScroll_intercepts()1017 public void onInterceptHoverEvent_horizontalCanScroll_intercepts() { 1018 onInterceptHoverEvent_scrollabilityAffectsResult(false, true, true); 1019 } 1020 1021 @Test onInterceptHoverEvent_horizontalCantScroll_doesntIntercept()1022 public void onInterceptHoverEvent_horizontalCantScroll_doesntIntercept() { 1023 onInterceptHoverEvent_scrollabilityAffectsResult(false, false, false); 1024 } 1025 onInterceptHoverEvent_scrollabilityAffectsResult(boolean vertical, boolean canScroll, boolean intercepts)1026 private void onInterceptHoverEvent_scrollabilityAffectsResult(boolean vertical, 1027 boolean canScroll, boolean intercepts) { 1028 1029 // Arrange 1030 1031 int range = canScroll ? 101 : 100; 1032 1033 final ScrollTestView viewGroup = spy(new ScrollTestView(mContext)); 1034 viewGroup.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT); 1035 viewGroup.setHorizontalScrollBarEnabled(true); 1036 viewGroup.setVerticalScrollBarEnabled(true); 1037 viewGroup.setScrollBarSize(10); 1038 viewGroup.layout(0, 0, 100, 100); 1039 1040 when(viewGroup.computeVerticalScrollExtent()).thenReturn(100); 1041 when(viewGroup.computeVerticalScrollRange()).thenReturn(range); 1042 when(viewGroup.computeHorizontalScrollExtent()).thenReturn(100); 1043 when(viewGroup.computeHorizontalScrollRange()).thenReturn(range); 1044 1045 int touchX = vertical ? 95 : 50; 1046 int touchY = vertical ? 50 : 95; 1047 MotionEvent event = 1048 EventUtils.generateMouseEvent(touchX, touchY, MotionEvent.ACTION_HOVER_ENTER, 0); 1049 1050 // Act 1051 1052 boolean actualResult = viewGroup.onInterceptHoverEvent(event); 1053 event.recycle(); 1054 1055 // Assert 1056 1057 assertEquals(actualResult, intercepts); 1058 } 1059 1060 @Test onInterceptTouchEvent_verticalCanScroll_intercepts()1061 public void onInterceptTouchEvent_verticalCanScroll_intercepts() { 1062 onInterceptTouchEvent_scrollabilityAffectsResult(true, true, true); 1063 } 1064 1065 @Test onInterceptTouchEvent_verticalCantScroll_doesntIntercept()1066 public void onInterceptTouchEvent_verticalCantScroll_doesntIntercept() { 1067 onInterceptTouchEvent_scrollabilityAffectsResult(true, false, false); 1068 } 1069 1070 @Test onInterceptTouchEvent_horizontalCanScroll_intercepts()1071 public void onInterceptTouchEvent_horizontalCanScroll_intercepts() { 1072 onInterceptTouchEvent_scrollabilityAffectsResult(false, true, true); 1073 } 1074 1075 @Test onInterceptTouchEvent_horizontalCantScroll_doesntIntercept()1076 public void onInterceptTouchEvent_horizontalCantScroll_doesntIntercept() { 1077 onInterceptTouchEvent_scrollabilityAffectsResult(false, false, false); 1078 } 1079 onInterceptTouchEvent_scrollabilityAffectsResult(boolean vertical, boolean canScroll, boolean intercepts)1080 private void onInterceptTouchEvent_scrollabilityAffectsResult(boolean vertical, 1081 boolean canScroll, boolean intercepts) { 1082 int range = canScroll ? 101 : 100; 1083 int thumbLength = ScrollBarUtils.getThumbLength(1, 10, 100, range); 1084 1085 PointerIcon expectedPointerIcon = PointerIcon.getSystemIcon(mContext, 1086 PointerIcon.TYPE_HAND); 1087 1088 final ScrollTestView viewGroup = spy(new ScrollTestView(mContext)); 1089 viewGroup.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT); 1090 viewGroup.setHorizontalScrollBarEnabled(true); 1091 viewGroup.setVerticalScrollBarEnabled(true); 1092 viewGroup.setScrollBarSize(10); 1093 viewGroup.setPointerIcon(expectedPointerIcon); 1094 viewGroup.layout(0, 0, 100, 100); 1095 1096 when(viewGroup.computeVerticalScrollExtent()).thenReturn(100); 1097 when(viewGroup.computeVerticalScrollRange()).thenReturn(range); 1098 when(viewGroup.computeHorizontalScrollExtent()).thenReturn(100); 1099 when(viewGroup.computeHorizontalScrollRange()).thenReturn(range); 1100 1101 int touchX = vertical ? 95 : thumbLength / 2; 1102 int touchY = vertical ? thumbLength / 2 : 95; 1103 MotionEvent event = EventUtils.generateMouseEvent(touchX, touchY, MotionEvent.ACTION_DOWN, 1104 MotionEvent.BUTTON_PRIMARY); 1105 1106 // Act 1107 1108 boolean actualResult = viewGroup.onInterceptTouchEvent(event); 1109 event.recycle(); 1110 1111 // Assert 1112 1113 assertEquals(intercepts, actualResult); 1114 } 1115 1116 @Test onResolvePointerIcon_verticalCanScroll_pointerIsArrow()1117 public void onResolvePointerIcon_verticalCanScroll_pointerIsArrow() { 1118 onResolvePointerIcon_scrollabilityAffectsPointerIcon(true, true, true); 1119 } 1120 1121 @Test onResolvePointerIcon_verticalCantScroll_pointerIsProperty()1122 public void onResolvePointerIcon_verticalCantScroll_pointerIsProperty() { 1123 onResolvePointerIcon_scrollabilityAffectsPointerIcon(true, false, false); 1124 } 1125 1126 @Test onResolvePointerIcon_horizontalCanScroll_pointerIsArrow()1127 public void onResolvePointerIcon_horizontalCanScroll_pointerIsArrow() { 1128 onResolvePointerIcon_scrollabilityAffectsPointerIcon(false, true, true); 1129 } 1130 1131 @Test onResolvePointerIcon_horizontalCantScroll_pointerIsProperty()1132 public void onResolvePointerIcon_horizontalCantScroll_pointerIsProperty() { 1133 onResolvePointerIcon_scrollabilityAffectsPointerIcon(false, false, false); 1134 } 1135 onResolvePointerIcon_scrollabilityAffectsPointerIcon(boolean vertical, boolean canScroll, boolean pointerIsSystemArrow)1136 private void onResolvePointerIcon_scrollabilityAffectsPointerIcon(boolean vertical, 1137 boolean canScroll, boolean pointerIsSystemArrow) { 1138 1139 // Arrange 1140 1141 int range = canScroll ? 101 : 100; 1142 int thumbLength = ScrollBarUtils.getThumbLength(1, 10, 100, range); 1143 1144 PointerIcon expectedPointerIcon = PointerIcon.getSystemIcon(mContext, 1145 PointerIcon.TYPE_HAND); 1146 1147 final ScrollTestView viewGroup = spy(new ScrollTestView(mContext)); 1148 viewGroup.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT); 1149 viewGroup.setHorizontalScrollBarEnabled(true); 1150 viewGroup.setVerticalScrollBarEnabled(true); 1151 viewGroup.setScrollBarSize(10); 1152 viewGroup.setPointerIcon(expectedPointerIcon); 1153 viewGroup.layout(0, 0, 100, 100); 1154 1155 when(viewGroup.computeVerticalScrollExtent()).thenReturn(100); 1156 when(viewGroup.computeVerticalScrollRange()).thenReturn(range); 1157 when(viewGroup.computeHorizontalScrollExtent()).thenReturn(100); 1158 when(viewGroup.computeHorizontalScrollRange()).thenReturn(range); 1159 1160 int touchX = vertical ? 95 : thumbLength / 2; 1161 int touchY = vertical ? thumbLength / 2 : 95; 1162 MotionEvent event = 1163 EventUtils.generateMouseEvent(touchX, touchY, MotionEvent.ACTION_HOVER_ENTER, 0); 1164 1165 // Act 1166 1167 PointerIcon actualResult = viewGroup.onResolvePointerIcon(event, 0); 1168 event.recycle(); 1169 1170 // Assert 1171 1172 if (pointerIsSystemArrow) { 1173 assertEquals(PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW), actualResult); 1174 } else { 1175 assertEquals(expectedPointerIcon, actualResult); 1176 } 1177 } 1178 1179 1180 @Test testOnDescendantInvalidated()1181 public void testOnDescendantInvalidated() throws Throwable { 1182 Activity activity = null; 1183 try { 1184 activity = mCtsActivityRule.launchActivity(new Intent()); 1185 1186 mCtsActivityRule.runOnUiThread(() -> { 1187 View child = mTextView; 1188 MockViewGroup parent = mMockViewGroup; 1189 MockViewGroup grandParent = new MockViewGroup(mContext); 1190 parent.addView(child); 1191 grandParent.addView(parent); 1192 mCtsActivityRule.getActivity().setContentView(grandParent); 1193 1194 parent.isOnDescendantInvalidatedCalled = false; 1195 grandParent.isOnDescendantInvalidatedCalled = false; 1196 1197 parent.invalidateChild(child, new Rect(0, 0, 1, 1)); 1198 1199 assertTrue(parent.isOnDescendantInvalidatedCalled); 1200 assertTrue(grandParent.isOnDescendantInvalidatedCalled); 1201 1202 parent.isOnDescendantInvalidatedCalled = false; 1203 grandParent.isOnDescendantInvalidatedCalled = false; 1204 1205 grandParent.invalidateChild(child, new Rect(0, 0, 1, 1)); 1206 1207 assertFalse(parent.isOnDescendantInvalidatedCalled); 1208 assertTrue(grandParent.isOnDescendantInvalidatedCalled); 1209 }); 1210 } finally { 1211 if (activity != null) { 1212 activity.finish(); 1213 } 1214 } 1215 } 1216 waitForResult()1217 private void waitForResult() { 1218 synchronized (mSync) { 1219 while(!mSync.mHasNotify) { 1220 try { 1221 mSync.wait(); 1222 } catch (InterruptedException e) { 1223 } 1224 } 1225 } 1226 } 1227 1228 @UiThreadTest 1229 @Test testIsAlwaysDrawnWithCacheEnabled()1230 public void testIsAlwaysDrawnWithCacheEnabled() { 1231 assertTrue(mMockViewGroup.isAlwaysDrawnWithCacheEnabled()); 1232 1233 mMockViewGroup.setAlwaysDrawnWithCacheEnabled(false); 1234 assertFalse(mMockViewGroup.isAlwaysDrawnWithCacheEnabled()); 1235 mMockViewGroup.setAlwaysDrawnWithCacheEnabled(true); 1236 assertTrue(mMockViewGroup.isAlwaysDrawnWithCacheEnabled()); 1237 } 1238 1239 @UiThreadTest 1240 @Test testIsAnimationCacheEnabled()1241 public void testIsAnimationCacheEnabled() { 1242 assertTrue(mMockViewGroup.isAnimationCacheEnabled()); 1243 1244 mMockViewGroup.setAnimationCacheEnabled(false); 1245 assertFalse(mMockViewGroup.isAnimationCacheEnabled()); 1246 mMockViewGroup.setAnimationCacheEnabled(true); 1247 assertTrue(mMockViewGroup.isAnimationCacheEnabled()); 1248 } 1249 1250 @UiThreadTest 1251 @Test testIsChildrenDrawnWithCacheEnabled()1252 public void testIsChildrenDrawnWithCacheEnabled() { 1253 assertFalse(mMockViewGroup.isChildrenDrawnWithCacheEnabled()); 1254 1255 mMockViewGroup.setChildrenDrawnWithCacheEnabled(true); 1256 assertTrue(mMockViewGroup.isChildrenDrawnWithCacheEnabled()); 1257 } 1258 1259 @UiThreadTest 1260 @Test testMeasureChild()1261 public void testMeasureChild() { 1262 final int width = 100; 1263 final int height = 200; 1264 MockView child = new MockView(mContext); 1265 child.setLayoutParams(new LayoutParams(width, height)); 1266 child.forceLayout(); 1267 mMockViewGroup.addView(child); 1268 1269 final int parentWidthMeasureSpec = 1; 1270 final int parentHeightMeasureSpec = 2; 1271 mMockViewGroup.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec); 1272 assertEquals(ViewGroup.getChildMeasureSpec(parentWidthMeasureSpec, 0, width), 1273 child.mWidthMeasureSpec); 1274 assertEquals(ViewGroup.getChildMeasureSpec(parentHeightMeasureSpec, 0, height), 1275 child.mHeightMeasureSpec); 1276 } 1277 1278 @UiThreadTest 1279 @Test testMeasureChildren()1280 public void testMeasureChildren() { 1281 final int widthMeasureSpec = 100; 1282 final int heightMeasureSpec = 200; 1283 MockTextView textView1 = new MockTextView(mContext); 1284 1285 mMockViewGroup.addView(textView1); 1286 mMockViewGroup.measureChildCalledTime = 0; 1287 mMockViewGroup.measureChildren(widthMeasureSpec, heightMeasureSpec); 1288 assertEquals(1, mMockViewGroup.measureChildCalledTime); 1289 1290 MockTextView textView2 = new MockTextView(mContext); 1291 textView2.setVisibility(View.GONE); 1292 mMockViewGroup.addView(textView2); 1293 1294 mMockViewGroup.measureChildCalledTime = 0; 1295 mMockViewGroup.measureChildren(widthMeasureSpec, heightMeasureSpec); 1296 assertEquals(1, mMockViewGroup.measureChildCalledTime); 1297 } 1298 1299 @UiThreadTest 1300 @Test testMeasureChildWithMargins()1301 public void testMeasureChildWithMargins() { 1302 final int width = 10; 1303 final int height = 20; 1304 final int parentWidthMeasureSpec = 1; 1305 final int widthUsed = 2; 1306 final int parentHeightMeasureSpec = 3; 1307 final int heightUsed = 4; 1308 MockView child = new MockView(mContext); 1309 1310 mMockViewGroup.addView(child); 1311 child.setLayoutParams(new ViewGroup.LayoutParams(width, height)); 1312 try { 1313 mMockViewGroup.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, 1314 parentHeightMeasureSpec, heightUsed); 1315 fail("measureChildWithMargins should throw out class cast exception"); 1316 } catch (RuntimeException e) { 1317 } 1318 child.setLayoutParams(new ViewGroup.MarginLayoutParams(width, height)); 1319 1320 mMockViewGroup.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, 1321 parentHeightMeasureSpec, heightUsed); 1322 assertEquals(ViewGroup.getChildMeasureSpec(parentWidthMeasureSpec, parentHeightMeasureSpec, 1323 width), child.mWidthMeasureSpec); 1324 assertEquals(ViewGroup.getChildMeasureSpec(widthUsed, heightUsed, height), 1325 child.mHeightMeasureSpec); 1326 } 1327 1328 @UiThreadTest 1329 @Test testOffsetDescendantRectToMyCoords()1330 public void testOffsetDescendantRectToMyCoords() { 1331 try { 1332 mMockViewGroup.offsetDescendantRectToMyCoords(mMockTextView, new Rect()); 1333 fail("offsetDescendantRectToMyCoords should throw out " 1334 + "IllegalArgumentException"); 1335 } catch (RuntimeException e) { 1336 // expected 1337 } 1338 mMockViewGroup.addView(mMockTextView); 1339 mMockTextView.layout(1, 2, 3, 4); 1340 Rect rect = new Rect(); 1341 mMockViewGroup.offsetDescendantRectToMyCoords(mMockTextView, rect); 1342 assertEquals(2, rect.bottom); 1343 assertEquals(2, rect.top); 1344 assertEquals(1, rect.left); 1345 assertEquals(1, rect.right); 1346 } 1347 1348 @UiThreadTest 1349 @Test testOffsetRectIntoDescendantCoords()1350 public void testOffsetRectIntoDescendantCoords() { 1351 mMockViewGroup.layout(10, 20, 30, 40); 1352 1353 try { 1354 mMockViewGroup.offsetRectIntoDescendantCoords(mMockTextView, new Rect()); 1355 fail("offsetRectIntoDescendantCoords should throw out " 1356 + "IllegalArgumentException"); 1357 } catch (RuntimeException e) { 1358 // expected 1359 } 1360 mMockTextView.layout(1, 2, 3, 4); 1361 mMockViewGroup.addView(mMockTextView); 1362 1363 Rect rect = new Rect(5, 6, 7, 8); 1364 mMockViewGroup.offsetRectIntoDescendantCoords(mMockTextView, rect); 1365 assertEquals(6, rect.bottom); 1366 assertEquals(4, rect.top); 1367 assertEquals(4, rect.left); 1368 assertEquals(6, rect.right); 1369 } 1370 1371 @UiThreadTest 1372 @Test testOnAnimationEnd()1373 public void testOnAnimationEnd() { 1374 // this function is a call back function it should be tested in ViewGroup#drawChild. 1375 MockViewGroup parent = new MockViewGroup(mContext); 1376 MockViewGroup child = new MockViewGroup(mContext); 1377 child.setAnimation(new MockAnimation()); 1378 // this call will make mPrivateFlags |= ANIMATION_STARTED; 1379 child.onAnimationStart(); 1380 parent.addView(child); 1381 1382 MockCanvas canvas = new MockCanvas(); 1383 assertFalse(parent.drawChild(canvas, child, 100)); 1384 assertTrue(child.isOnAnimationEndCalled); 1385 } 1386 1387 private class MockAnimation extends Animation { MockAnimation()1388 public MockAnimation() { 1389 super(); 1390 } 1391 MockAnimation(Context context, AttributeSet attrs)1392 public MockAnimation(Context context, AttributeSet attrs) { 1393 super(context, attrs); 1394 } 1395 1396 @Override getTransformation(long currentTime, Transformation outTransformation)1397 public boolean getTransformation(long currentTime, Transformation outTransformation) { 1398 super.getTransformation(currentTime, outTransformation); 1399 return false; 1400 } 1401 } 1402 1403 @UiThreadTest 1404 @Test testOnAnimationStart()1405 public void testOnAnimationStart() { 1406 // This is a call back method. It should be tested in ViewGroup#drawChild. 1407 MockViewGroup parent = new MockViewGroup(mContext); 1408 MockViewGroup child = new MockViewGroup(mContext); 1409 1410 parent.addView(child); 1411 1412 MockCanvas canvas = new MockCanvas(); 1413 try { 1414 assertFalse(parent.drawChild(canvas, child, 100)); 1415 assertFalse(child.isOnAnimationStartCalled); 1416 } catch (Exception e) { 1417 // expected 1418 } 1419 1420 child.setAnimation(new MockAnimation()); 1421 assertFalse(parent.drawChild(canvas, child, 100)); 1422 assertTrue(child.isOnAnimationStartCalled); 1423 } 1424 1425 @UiThreadTest 1426 @Test testOnCreateDrawableState()1427 public void testOnCreateDrawableState() { 1428 // Call back function. Called in View#getDrawableState() 1429 int[] data = mMockViewGroup.getDrawableState(); 1430 assertTrue(mMockViewGroup.isOnCreateDrawableStateCalled); 1431 assertEquals(1, data.length); 1432 } 1433 1434 @UiThreadTest 1435 @Test testOnInterceptTouchEvent()1436 public void testOnInterceptTouchEvent() { 1437 MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(), 1438 SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 100, 100, 0); 1439 1440 assertFalse(mMockViewGroup.dispatchTouchEvent(me)); 1441 assertTrue(mMockViewGroup.isOnInterceptTouchEventCalled); 1442 } 1443 1444 @UiThreadTest 1445 @Test testOnLayout()1446 public void testOnLayout() { 1447 final int left = 1; 1448 final int top = 2; 1449 final int right = 100; 1450 final int bottom = 200; 1451 mMockViewGroup.layout(left, top, right, bottom); 1452 assertEquals(left, mMockViewGroup.left); 1453 assertEquals(top, mMockViewGroup.top); 1454 assertEquals(right, mMockViewGroup.right); 1455 assertEquals(bottom, mMockViewGroup.bottom); 1456 } 1457 1458 @UiThreadTest 1459 @Test testOnRequestFocusInDescendants()1460 public void testOnRequestFocusInDescendants() { 1461 mMockViewGroup.requestFocus(View.FOCUS_DOWN, new Rect()); 1462 assertTrue(mMockViewGroup.isOnRequestFocusInDescendantsCalled); 1463 } 1464 1465 @UiThreadTest 1466 @Test testRemoveAllViews()1467 public void testRemoveAllViews() { 1468 assertEquals(0, mMockViewGroup.getChildCount()); 1469 1470 mMockViewGroup.addView(mMockTextView); 1471 assertEquals(1, mMockViewGroup.getChildCount()); 1472 1473 mMockViewGroup.removeAllViews(); 1474 assertEquals(0, mMockViewGroup.getChildCount()); 1475 assertNull(mMockTextView.getParent()); 1476 } 1477 1478 @UiThreadTest 1479 @Test testRemoveAllViewsInLayout()1480 public void testRemoveAllViewsInLayout() { 1481 MockViewGroup parent = new MockViewGroup(mContext); 1482 MockViewGroup child = new MockViewGroup(mContext); 1483 1484 assertEquals(0, parent.getChildCount()); 1485 1486 child.addView(mMockTextView); 1487 parent.addView(child); 1488 assertEquals(1, parent.getChildCount()); 1489 1490 parent.removeAllViewsInLayout(); 1491 assertEquals(0, parent.getChildCount()); 1492 assertEquals(1, child.getChildCount()); 1493 assertNull(child.getParent()); 1494 assertSame(child, mMockTextView.getParent()); 1495 } 1496 1497 @UiThreadTest 1498 @Test testRemoveDetachedView()1499 public void testRemoveDetachedView() { 1500 MockViewGroup parent = new MockViewGroup(mContext); 1501 MockViewGroup child1 = new MockViewGroup(mContext); 1502 MockViewGroup child2 = new MockViewGroup(mContext); 1503 ViewGroup.OnHierarchyChangeListener listener = 1504 mock(ViewGroup.OnHierarchyChangeListener.class); 1505 parent.setOnHierarchyChangeListener(listener); 1506 parent.addView(child1); 1507 parent.addView(child2); 1508 1509 parent.removeDetachedView(child1, false); 1510 1511 InOrder inOrder = inOrder(listener); 1512 inOrder.verify(listener, times(1)).onChildViewAdded(parent, child1); 1513 inOrder.verify(listener, times(1)).onChildViewAdded(parent, child2); 1514 inOrder.verify(listener, times(1)).onChildViewRemoved(parent, child1); 1515 } 1516 1517 @UiThreadTest 1518 @Test testRemoveView()1519 public void testRemoveView() { 1520 MockViewGroup parent = new MockViewGroup(mContext); 1521 MockViewGroup child = new MockViewGroup(mContext); 1522 1523 assertEquals(0, parent.getChildCount()); 1524 1525 parent.addView(child); 1526 assertEquals(1, parent.getChildCount()); 1527 1528 parent.removeView(child); 1529 assertEquals(0, parent.getChildCount()); 1530 assertNull(child.getParent()); 1531 assertTrue(parent.isOnViewRemovedCalled); 1532 } 1533 1534 @UiThreadTest 1535 @Test testRemoveViewAt()1536 public void testRemoveViewAt() { 1537 MockViewGroup parent = new MockViewGroup(mContext); 1538 MockViewGroup child = new MockViewGroup(mContext); 1539 1540 assertEquals(0, parent.getChildCount()); 1541 1542 parent.addView(child); 1543 assertEquals(1, parent.getChildCount()); 1544 1545 try { 1546 parent.removeViewAt(2); 1547 fail("should throw out null pointer exception"); 1548 } catch (RuntimeException e) { 1549 // expected 1550 } 1551 assertEquals(1, parent.getChildCount()); 1552 1553 parent.removeViewAt(0); 1554 assertEquals(0, parent.getChildCount()); 1555 assertNull(child.getParent()); 1556 assertTrue(parent.isOnViewRemovedCalled); 1557 } 1558 1559 @UiThreadTest 1560 @Test testRemoveViewInLayout()1561 public void testRemoveViewInLayout() { 1562 MockViewGroup parent = new MockViewGroup(mContext); 1563 MockViewGroup child = new MockViewGroup(mContext); 1564 1565 assertEquals(0, parent.getChildCount()); 1566 1567 parent.addView(child); 1568 assertEquals(1, parent.getChildCount()); 1569 1570 parent.removeViewInLayout(child); 1571 assertEquals(0, parent.getChildCount()); 1572 assertNull(child.getParent()); 1573 assertTrue(parent.isOnViewRemovedCalled); 1574 } 1575 1576 @UiThreadTest 1577 @Test testRemoveViews()1578 public void testRemoveViews() { 1579 MockViewGroup parent = new MockViewGroup(mContext); 1580 MockViewGroup child1 = new MockViewGroup(mContext); 1581 MockViewGroup child2 = new MockViewGroup(mContext); 1582 1583 assertEquals(0, parent.getChildCount()); 1584 parent.addView(child1); 1585 parent.addView(child2); 1586 assertEquals(2, parent.getChildCount()); 1587 1588 try { 1589 parent.removeViews(-1, 1); // negative begin 1590 fail("should fail with IndexOutOfBoundsException"); 1591 } catch (IndexOutOfBoundsException e) {} 1592 1593 try { 1594 parent.removeViews(0, -1); // negative count 1595 fail("should fail with IndexOutOfBoundsException"); 1596 } catch (IndexOutOfBoundsException e) {} 1597 1598 try { 1599 parent.removeViews(1, 2); // past end 1600 fail("should fail with IndexOutOfBoundsException"); 1601 } catch (IndexOutOfBoundsException e) {} 1602 assertEquals(2, parent.getChildCount()); // child list unmodified 1603 1604 parent.removeViews(0, 1); 1605 assertEquals(1, parent.getChildCount()); 1606 assertNull(child1.getParent()); 1607 1608 parent.removeViews(0, 1); 1609 assertEquals(0, parent.getChildCount()); 1610 assertNull(child2.getParent()); 1611 assertTrue(parent.isOnViewRemovedCalled); 1612 } 1613 1614 @UiThreadTest 1615 @Test testRemoveViewsInLayout()1616 public void testRemoveViewsInLayout() { 1617 MockViewGroup parent = new MockViewGroup(mContext); 1618 MockViewGroup child1 = new MockViewGroup(mContext); 1619 MockViewGroup child2 = new MockViewGroup(mContext); 1620 1621 assertEquals(0, parent.getChildCount()); 1622 parent.addView(child1); 1623 parent.addView(child2); 1624 assertEquals(2, parent.getChildCount()); 1625 1626 try { 1627 parent.removeViewsInLayout(-1, 1); // negative begin 1628 fail("should fail with IndexOutOfBoundsException"); 1629 } catch (IndexOutOfBoundsException e) {} 1630 1631 try { 1632 parent.removeViewsInLayout(0, -1); // negative count 1633 fail("should fail with IndexOutOfBoundsException"); 1634 } catch (IndexOutOfBoundsException e) {} 1635 1636 try { 1637 parent.removeViewsInLayout(1, 2); // past end 1638 fail("should fail with IndexOutOfBoundsException"); 1639 } catch (IndexOutOfBoundsException e) {} 1640 assertEquals(2, parent.getChildCount()); // child list unmodified 1641 1642 parent.removeViewsInLayout(0, 1); 1643 assertEquals(1, parent.getChildCount()); 1644 assertNull(child1.getParent()); 1645 1646 parent.removeViewsInLayout(0, 1); 1647 assertEquals(0, parent.getChildCount()); 1648 assertNull(child2.getParent()); 1649 assertTrue(parent.isOnViewRemovedCalled); 1650 } 1651 1652 @UiThreadTest 1653 @Test testRequestChildFocus()1654 public void testRequestChildFocus() { 1655 mMockViewGroup.addView(mTextView); 1656 mMockViewGroup.requestChildFocus(mTextView, null); 1657 1658 assertNotNull(mMockViewGroup.getFocusedChild()); 1659 1660 mMockViewGroup.clearChildFocus(mTextView); 1661 assertNull(mMockViewGroup.getFocusedChild()); 1662 } 1663 1664 @UiThreadTest 1665 @Test testRequestChildRectangleOnScreen()1666 public void testRequestChildRectangleOnScreen() { 1667 assertFalse(mMockViewGroup.requestChildRectangleOnScreen(null, null, false)); 1668 } 1669 1670 @UiThreadTest 1671 @Test testRequestDisallowInterceptTouchEvent()1672 public void testRequestDisallowInterceptTouchEvent() { 1673 MockView child = new MockView(mContext); 1674 1675 mMockViewGroup.addView(child); 1676 child.requestDisallowInterceptTouchEvent(true); 1677 child.requestDisallowInterceptTouchEvent(false); 1678 assertTrue(mMockViewGroup.isRequestDisallowInterceptTouchEventCalled); 1679 } 1680 1681 @UiThreadTest 1682 @Test testRequestFocus()1683 public void testRequestFocus() { 1684 mMockViewGroup.requestFocus(View.FOCUS_DOWN, new Rect()); 1685 assertTrue(mMockViewGroup.isOnRequestFocusInDescendantsCalled); 1686 } 1687 1688 private class TestClusterHier { 1689 public MockViewGroup top = new MockViewGroup(mContext); 1690 public MockViewGroup cluster1 = new MockViewGroup(mContext); 1691 public Button c1view1 = new Button(mContext); 1692 public Button c1view2 = new Button(mContext); 1693 public MockViewGroup cluster2 = new MockViewGroup(mContext); 1694 public MockViewGroup nestedGroup = new MockViewGroup(mContext); 1695 public Button c2view1 = new Button(mContext); 1696 public Button c2view2 = new Button(mContext); TestClusterHier()1697 TestClusterHier() { 1698 this(true); 1699 } TestClusterHier(boolean inTouchMode)1700 TestClusterHier(boolean inTouchMode) { 1701 for (Button bt : new Button[]{c1view1, c1view2, c2view1, c2view2}) { 1702 // Otherwise this test won't work during suite-run. 1703 bt.setFocusableInTouchMode(inTouchMode); 1704 } 1705 for (MockViewGroup mvg : new MockViewGroup[]{top, cluster1, cluster2, nestedGroup}) { 1706 mvg.returnActualFocusSearchResult = true; 1707 } 1708 top.setIsRootNamespace(true); 1709 cluster1.setKeyboardNavigationCluster(true); 1710 cluster2.setKeyboardNavigationCluster(true); 1711 cluster1.addView(c1view1); 1712 cluster1.addView(c1view2); 1713 cluster2.addView(c2view1); 1714 nestedGroup.addView(c2view2); 1715 cluster2.addView(nestedGroup); 1716 top.addView(cluster1); 1717 top.addView(cluster2); 1718 } 1719 } 1720 1721 @UiThreadTest 1722 @Test testRestoreFocusInCluster()1723 public void testRestoreFocusInCluster() { 1724 TestClusterHier h = new TestClusterHier(); 1725 h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN); 1726 assertSame(h.c1view1, h.top.findFocus()); 1727 1728 h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN); 1729 assertSame(h.c2view1, h.top.findFocus()); 1730 1731 h.c2view2.setFocusedInCluster(); 1732 h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN); 1733 assertSame(h.c2view2, h.top.findFocus()); 1734 h.c2view1.setFocusedInCluster(); 1735 h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN); 1736 assertSame(h.c2view1, h.top.findFocus()); 1737 1738 h.c1view2.setFocusedInCluster(); 1739 h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN); 1740 assertSame(h.c1view2, h.top.findFocus()); 1741 1742 h = new TestClusterHier(); 1743 h.cluster1.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 1744 h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN); 1745 assertNull(h.top.findFocus()); 1746 1747 h.c2view1.setVisibility(View.INVISIBLE); 1748 h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN); 1749 assertSame(h.c2view2, h.top.findFocus()); 1750 1751 // Nested clusters should be ignored. 1752 h = new TestClusterHier(); 1753 h.c1view1.setFocusedInCluster(); 1754 h.nestedGroup.setKeyboardNavigationCluster(true); 1755 h.c2view2.setFocusedInCluster(); 1756 h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN); 1757 assertSame(h.c2view2, h.top.findFocus()); 1758 } 1759 1760 @UiThreadTest 1761 @Test testDefaultCluster()1762 public void testDefaultCluster() { 1763 TestClusterHier h = new TestClusterHier(); 1764 h.cluster2.setKeyboardNavigationCluster(false); 1765 assertTrue(h.top.restoreFocusNotInCluster()); 1766 assertSame(h.c2view1, h.top.findFocus()); 1767 1768 // Check saves state within non-cluster 1769 h = new TestClusterHier(); 1770 h.cluster2.setKeyboardNavigationCluster(false); 1771 h.c2view2.setFocusedInCluster(); 1772 assertTrue(h.top.restoreFocusNotInCluster()); 1773 assertSame(h.c2view2, h.top.findFocus()); 1774 1775 // Check that focusable view groups have descendantFocusability honored. 1776 h = new TestClusterHier(); 1777 h.cluster2.setKeyboardNavigationCluster(false); 1778 h.cluster2.setFocusableInTouchMode(true); 1779 h.cluster2.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); 1780 assertTrue(h.top.restoreFocusNotInCluster()); 1781 assertSame(h.c2view1, h.top.findFocus()); 1782 h = new TestClusterHier(); 1783 h.cluster2.setKeyboardNavigationCluster(false); 1784 h.cluster2.setFocusableInTouchMode(true); 1785 h.cluster2.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); 1786 assertTrue(h.top.restoreFocusNotInCluster()); 1787 assertSame(h.cluster2, h.top.findFocus()); 1788 1789 // Check that we return false if nothing out-of-cluster is focusable 1790 // (also tests FOCUS_BLOCK_DESCENDANTS) 1791 h = new TestClusterHier(); 1792 h.cluster2.setKeyboardNavigationCluster(false); 1793 h.cluster2.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 1794 assertFalse(h.top.restoreFocusNotInCluster()); 1795 assertNull(h.top.findFocus()); 1796 } 1797 1798 @UiThreadTest 1799 @Test testFocusInClusterRemovals()1800 public void testFocusInClusterRemovals() { 1801 // Removing focused-in-cluster view from its parent in various ways. 1802 TestClusterHier h = new TestClusterHier(); 1803 h.c1view1.setFocusedInCluster(); 1804 h.cluster1.removeView(h.c1view1); 1805 h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN); 1806 assertSame(h.c1view2, h.cluster1.findFocus()); 1807 1808 h = new TestClusterHier(); 1809 h.c1view1.setFocusedInCluster(); 1810 h.cluster1.removeViews(0, 1); 1811 h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN); 1812 assertSame(h.c1view2, h.cluster1.findFocus()); 1813 1814 h = new TestClusterHier(); 1815 h.c2view1.setFocusedInCluster(); 1816 h.cluster2.removeAllViewsInLayout(); 1817 h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN); 1818 assertNull(h.cluster2.findFocus()); 1819 1820 h = new TestClusterHier(); 1821 h.c1view1.setFocusedInCluster(); 1822 h.cluster1.detachViewFromParent(h.c1view1); 1823 h.cluster1.attachViewToParent(h.c1view1, 1, null); 1824 h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN); 1825 assertSame(h.c1view1, h.cluster1.findFocus()); 1826 1827 h = new TestClusterHier(); 1828 h.c1view1.setFocusedInCluster(); 1829 h.cluster1.detachViewFromParent(h.c1view1); 1830 h.cluster1.removeDetachedView(h.c1view1, false); 1831 h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN); 1832 assertSame(h.c1view2, h.cluster1.findFocus()); 1833 } 1834 1835 @UiThreadTest 1836 @Test testFocusInClusterFocusableChanges()1837 public void testFocusInClusterFocusableChanges() { 1838 TestClusterHier h = new TestClusterHier(); 1839 h.cluster1.setKeyboardNavigationCluster(false); 1840 h.c1view2.setFocusedInCluster(); 1841 h.c2view1.requestFocus(); 1842 assertSame(h.top.findFocus(), h.c2view1); 1843 assertTrue(h.top.restoreFocusNotInCluster()); 1844 assertSame(h.top.findFocus(), h.c1view2); 1845 h.c1view1.setFocusable(false); 1846 // making it invisible should clear focusNotInCluster chain 1847 h.c1view2.setVisibility(View.INVISIBLE); 1848 assertFalse(h.top.restoreFocusNotInCluster()); 1849 h.c1view2.setVisibility(View.VISIBLE); 1850 h.c1view2.requestFocus(); 1851 h.c1view2.setFocusedInCluster(); 1852 h.c2view1.setFocusable(false); 1853 h.c2view2.setFocusable(false); 1854 assertFalse(h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN)); 1855 } 1856 1857 @UiThreadTest 1858 @Test testRestoreDefaultFocus()1859 public void testRestoreDefaultFocus() { 1860 TestClusterHier h = new TestClusterHier(); 1861 h.c1view2.setFocusedByDefault(true); 1862 h.top.restoreDefaultFocus(); 1863 assertSame(h.c1view2, h.top.findFocus()); 1864 1865 h.c1view2.setFocusedByDefault(false); 1866 h.top.restoreDefaultFocus(); 1867 assertSame(h.c1view1, h.top.findFocus()); 1868 1869 // default focus favors higher-up views 1870 h.c1view2.setFocusedByDefault(true); 1871 h.cluster1.setFocusedByDefault(true); 1872 h.top.restoreDefaultFocus(); 1873 assertSame(h.c1view2, h.top.findFocus()); 1874 h.c2view1.setFocusedByDefault(true); 1875 h.top.restoreDefaultFocus(); 1876 assertSame(h.c1view2, h.top.findFocus()); 1877 h.cluster2.setFocusedByDefault(true); 1878 h.cluster1.setFocusedByDefault(false); 1879 h.top.restoreDefaultFocus(); 1880 assertSame(h.c2view1, h.top.findFocus()); 1881 1882 // removing default receivers should resolve to an existing default 1883 h = new TestClusterHier(); 1884 h.c1view2.setFocusedByDefault(true); 1885 h.cluster1.setFocusedByDefault(true); 1886 h.c2view2.setFocusedByDefault(true); 1887 h.top.restoreDefaultFocus(); 1888 assertSame(h.c1view2, h.top.findFocus()); 1889 h.c1view2.setFocusedByDefault(false); 1890 h.cluster1.setFocusedByDefault(false); 1891 // only 1 focused-by-default view left, but its in a different branch. Should still pull 1892 // default focus. 1893 h.top.restoreDefaultFocus(); 1894 assertSame(h.c2view2, h.top.findFocus()); 1895 } 1896 1897 @UiThreadTest 1898 @Test testDefaultFocusViewRemoved()1899 public void testDefaultFocusViewRemoved() { 1900 // Removing default-focus view from its parent in various ways. 1901 TestClusterHier h = new TestClusterHier(); 1902 h.c1view1.setFocusedByDefault(true); 1903 h.cluster1.removeView(h.c1view1); 1904 h.cluster1.restoreDefaultFocus(); 1905 assertSame(h.c1view2, h.cluster1.findFocus()); 1906 1907 h = new TestClusterHier(); 1908 h.c1view1.setFocusedByDefault(true); 1909 h.cluster1.removeViews(0, 1); 1910 h.cluster1.restoreDefaultFocus(); 1911 assertSame(h.c1view2, h.cluster1.findFocus()); 1912 1913 h = new TestClusterHier(); 1914 h.c1view1.setFocusedByDefault(true); 1915 h.cluster1.removeAllViewsInLayout(); 1916 h.cluster1.restoreDefaultFocus(); 1917 assertNull(h.cluster1.findFocus()); 1918 1919 h = new TestClusterHier(); 1920 h.c1view1.setFocusedByDefault(true); 1921 h.cluster1.detachViewFromParent(h.c1view1); 1922 h.cluster1.attachViewToParent(h.c1view1, 1, null); 1923 h.cluster1.restoreDefaultFocus(); 1924 assertSame(h.c1view1, h.cluster1.findFocus()); 1925 1926 h = new TestClusterHier(); 1927 h.c1view1.setFocusedByDefault(true); 1928 h.cluster1.detachViewFromParent(h.c1view1); 1929 h.cluster1.removeDetachedView(h.c1view1, false); 1930 h.cluster1.restoreDefaultFocus(); 1931 assertSame(h.c1view2, h.cluster1.findFocus()); 1932 } 1933 1934 @UiThreadTest 1935 @Test testAddViewWithDefaultFocus()1936 public void testAddViewWithDefaultFocus() { 1937 // Adding a view that has default focus propagates the default focus chain to the root. 1938 mMockViewGroup = new MockViewGroup(mContext); 1939 mMockTextView = new MockTextView(mContext); 1940 mMockTextView.setFocusable(true); 1941 mTextView = new TextView(mContext); 1942 mTextView.setFocusable(true); 1943 mTextView.setFocusableInTouchMode(true); 1944 mTextView.setFocusedByDefault(true); 1945 mMockViewGroup.addView(mMockTextView); 1946 mMockViewGroup.addView(mTextView); 1947 mMockViewGroup.restoreDefaultFocus(); 1948 assertTrue(mTextView.isFocused()); 1949 } 1950 1951 @UiThreadTest 1952 @Test testDefaultFocusWorksForClusters()1953 public void testDefaultFocusWorksForClusters() { 1954 TestClusterHier h = new TestClusterHier(); 1955 h.c2view2.setFocusedByDefault(true); 1956 h.cluster1.setFocusedByDefault(true); 1957 h.top.restoreDefaultFocus(); 1958 assertSame(h.c1view1, h.top.findFocus()); 1959 h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN); 1960 assertSame(h.c2view2, h.top.findFocus()); 1961 1962 // make sure focused in cluster takes priority in cluster-focus 1963 h.c1view2.setFocusedByDefault(true); 1964 h.c1view1.setFocusedInCluster(); 1965 h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN); 1966 assertSame(h.c1view1, h.top.findFocus()); 1967 } 1968 1969 @UiThreadTest 1970 @Test testTouchscreenBlocksFocus()1971 public void testTouchscreenBlocksFocus() { 1972 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) { 1973 return; 1974 } 1975 InstrumentationRegistry.getInstrumentation().setInTouchMode(false); 1976 1977 // Can't focus/default-focus an element in touchscreenBlocksFocus 1978 TestClusterHier h = new TestClusterHier(false); 1979 h.cluster1.setTouchscreenBlocksFocus(true); 1980 h.c1view2.setFocusedByDefault(true); 1981 h.top.restoreDefaultFocus(); 1982 assertSame(h.c2view1, h.top.findFocus()); 1983 ArrayList<View> views = new ArrayList<>(); 1984 h.top.addFocusables(views, View.FOCUS_DOWN); 1985 for (View v : views) { 1986 assertFalse(v.getParent() == h.cluster1); 1987 } 1988 views.clear(); 1989 1990 // Can cluster navigate into it though 1991 h.top.addKeyboardNavigationClusters(views, View.FOCUS_DOWN); 1992 assertTrue(views.contains(h.cluster1)); 1993 views.clear(); 1994 h.cluster1.restoreFocusInCluster(View.FOCUS_DOWN); 1995 assertSame(h.c1view2, h.top.findFocus()); 1996 // can normal-navigate around once inside 1997 h.top.addFocusables(views, View.FOCUS_DOWN); 1998 assertTrue(views.contains(h.c1view1)); 1999 views.clear(); 2000 h.c1view1.requestFocus(); 2001 assertSame(h.c1view1, h.top.findFocus()); 2002 // focus loops within cluster (doesn't leave) 2003 h.c1view2.requestFocus(); 2004 View next = h.top.focusSearch(h.c1view2, View.FOCUS_FORWARD); 2005 assertSame(h.c1view1, next); 2006 // but once outside, can no-longer navigate in. 2007 h.c2view2.requestFocus(); 2008 h.c1view1.requestFocus(); 2009 assertSame(h.c2view2, h.top.findFocus()); 2010 2011 h = new TestClusterHier(false); 2012 h.c1view1.requestFocus(); 2013 h.nestedGroup.setKeyboardNavigationCluster(true); 2014 h.nestedGroup.setTouchscreenBlocksFocus(true); 2015 // since cluster is nested, it should ignore its touchscreenBlocksFocus behavior. 2016 h.c2view2.requestFocus(); 2017 assertSame(h.c2view2, h.top.findFocus()); 2018 h.top.addFocusables(views, View.FOCUS_DOWN); 2019 assertTrue(views.contains(h.c2view2)); 2020 views.clear(); 2021 } 2022 2023 @UiThreadTest 2024 @Test testRequestTransparentRegion()2025 public void testRequestTransparentRegion() { 2026 MockViewGroup parent = new MockViewGroup(mContext); 2027 MockView child1 = new MockView(mContext); 2028 MockView child2 = new MockView(mContext); 2029 child1.addView(child2); 2030 parent.addView(child1); 2031 child1.requestTransparentRegion(child2); 2032 assertTrue(parent.isRequestTransparentRegionCalled); 2033 } 2034 2035 @UiThreadTest 2036 @Test testScheduleLayoutAnimation()2037 public void testScheduleLayoutAnimation() { 2038 Animation animation = new AlphaAnimation(mContext, null); 2039 2040 LayoutAnimationController al = spy(new LayoutAnimationController(animation)); 2041 mMockViewGroup.setLayoutAnimation(al); 2042 mMockViewGroup.scheduleLayoutAnimation(); 2043 mMockViewGroup.dispatchDraw(new Canvas()); 2044 verify(al, times(1)).start(); 2045 } 2046 2047 @UiThreadTest 2048 @Test testSetAddStatesFromChildren()2049 public void testSetAddStatesFromChildren() { 2050 mMockViewGroup.setAddStatesFromChildren(true); 2051 assertTrue(mMockViewGroup.addStatesFromChildren()); 2052 2053 mMockViewGroup.setAddStatesFromChildren(false); 2054 assertFalse(mMockViewGroup.addStatesFromChildren()); 2055 } 2056 2057 @UiThreadTest 2058 @Test testSetChildrenDrawingCacheEnabled()2059 public void testSetChildrenDrawingCacheEnabled() { 2060 assertTrue(mMockViewGroup.isAnimationCacheEnabled()); 2061 2062 mMockViewGroup.setAnimationCacheEnabled(false); 2063 assertFalse(mMockViewGroup.isAnimationCacheEnabled()); 2064 2065 mMockViewGroup.setAnimationCacheEnabled(true); 2066 assertTrue(mMockViewGroup.isAnimationCacheEnabled()); 2067 } 2068 2069 @UiThreadTest 2070 @Test testSetChildrenDrawnWithCacheEnabled()2071 public void testSetChildrenDrawnWithCacheEnabled() { 2072 assertFalse(mMockViewGroup.isChildrenDrawnWithCacheEnabled()); 2073 2074 mMockViewGroup.setChildrenDrawnWithCacheEnabled(true); 2075 assertTrue(mMockViewGroup.isChildrenDrawnWithCacheEnabled()); 2076 2077 mMockViewGroup.setChildrenDrawnWithCacheEnabled(false); 2078 assertFalse(mMockViewGroup.isChildrenDrawnWithCacheEnabled()); 2079 } 2080 2081 @UiThreadTest 2082 @Test testSetClipChildren()2083 public void testSetClipChildren() { 2084 Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 2085 2086 mMockTextView.layout(1, 2, 30, 40); 2087 mMockViewGroup.layout(1, 1, 100, 200); 2088 mMockViewGroup.setClipChildren(true); 2089 2090 MockCanvas canvas = new MockCanvas(bitmap); 2091 mMockViewGroup.drawChild(canvas, mMockTextView, 100); 2092 Rect rect = canvas.getClipBounds(); 2093 assertEquals(0, rect.top); 2094 assertEquals(100, rect.bottom); 2095 assertEquals(0, rect.left); 2096 assertEquals(100, rect.right); 2097 } 2098 2099 class MockCanvas extends Canvas { 2100 2101 public int mLeft; 2102 public int mTop; 2103 public int mRight; 2104 public int mBottom; 2105 MockCanvas()2106 public MockCanvas() { 2107 super(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)); 2108 } 2109 MockCanvas(Bitmap bitmap)2110 public MockCanvas(Bitmap bitmap) { 2111 super(bitmap); 2112 } 2113 2114 @Override quickReject(float left, float top, float right, float bottom, EdgeType type)2115 public boolean quickReject(float left, float top, float right, 2116 float bottom, EdgeType type) { 2117 super.quickReject(left, top, right, bottom, type); 2118 return false; 2119 } 2120 2121 @Override clipRect(int left, int top, int right, int bottom)2122 public boolean clipRect(int left, int top, int right, int bottom) { 2123 mLeft = left; 2124 mTop = top; 2125 mRight = right; 2126 mBottom = bottom; 2127 return super.clipRect(left, top, right, bottom); 2128 } 2129 } 2130 2131 @UiThreadTest 2132 @Test testSetClipToPadding()2133 public void testSetClipToPadding() { 2134 final int frameLeft = 1; 2135 final int frameTop = 2; 2136 final int frameRight = 100; 2137 final int frameBottom = 200; 2138 mMockViewGroup.layout(frameLeft, frameTop, frameRight, frameBottom); 2139 2140 mMockViewGroup.setClipToPadding(true); 2141 MockCanvas canvas = new MockCanvas(); 2142 final int paddingLeft = 10; 2143 final int paddingTop = 20; 2144 final int paddingRight = 100; 2145 final int paddingBottom = 200; 2146 mMockViewGroup.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); 2147 mMockViewGroup.dispatchDraw(canvas); 2148 //check that the clip region does not contain the padding area 2149 assertEquals(10, canvas.mLeft); 2150 assertEquals(20, canvas.mTop); 2151 assertEquals(-frameLeft, canvas.mRight); 2152 assertEquals(-frameTop, canvas.mBottom); 2153 2154 mMockViewGroup.setClipToPadding(false); 2155 canvas = new MockCanvas(); 2156 mMockViewGroup.dispatchDraw(canvas); 2157 assertEquals(0, canvas.mLeft); 2158 assertEquals(0, canvas.mTop); 2159 assertEquals(0, canvas.mRight); 2160 assertEquals(0, canvas.mBottom); 2161 } 2162 2163 @UiThreadTest 2164 @Test testSetDescendantFocusability()2165 public void testSetDescendantFocusability() { 2166 final int FLAG_MASK_FOCUSABILITY = 0x60000; 2167 assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0); 2168 2169 mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 2170 assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0); 2171 2172 mMockViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); 2173 assertFalse((mMockViewGroup.getDescendantFocusability() & FLAG_MASK_FOCUSABILITY) == 0); 2174 assertFalse((mMockViewGroup.getDescendantFocusability() & 2175 ViewGroup.FOCUS_BEFORE_DESCENDANTS) == 0); 2176 } 2177 2178 @UiThreadTest 2179 @Test testSetOnHierarchyChangeListener()2180 public void testSetOnHierarchyChangeListener() { 2181 MockViewGroup parent = new MockViewGroup(mContext); 2182 MockViewGroup child = new MockViewGroup(mContext); 2183 ViewGroup.OnHierarchyChangeListener listener = 2184 mock(ViewGroup.OnHierarchyChangeListener.class); 2185 parent.setOnHierarchyChangeListener(listener); 2186 parent.addView(child); 2187 2188 parent.removeDetachedView(child, false); 2189 InOrder inOrder = inOrder(listener); 2190 inOrder.verify(listener, times(1)).onChildViewAdded(parent, child); 2191 inOrder.verify(listener, times(1)).onChildViewRemoved(parent, child); 2192 } 2193 2194 @UiThreadTest 2195 @Test testSetPadding()2196 public void testSetPadding() { 2197 final int left = 1; 2198 final int top = 2; 2199 final int right = 3; 2200 final int bottom = 4; 2201 2202 assertEquals(0, mMockViewGroup.getPaddingBottom()); 2203 assertEquals(0, mMockViewGroup.getPaddingTop()); 2204 assertEquals(0, mMockViewGroup.getPaddingLeft()); 2205 assertEquals(0, mMockViewGroup.getPaddingRight()); 2206 assertEquals(0, mMockViewGroup.getPaddingStart()); 2207 assertEquals(0, mMockViewGroup.getPaddingEnd()); 2208 2209 mMockViewGroup.setPadding(left, top, right, bottom); 2210 2211 assertEquals(bottom, mMockViewGroup.getPaddingBottom()); 2212 assertEquals(top, mMockViewGroup.getPaddingTop()); 2213 assertEquals(left, mMockViewGroup.getPaddingLeft()); 2214 assertEquals(right, mMockViewGroup.getPaddingRight()); 2215 2216 assertEquals(left, mMockViewGroup.getPaddingStart()); 2217 assertEquals(right, mMockViewGroup.getPaddingEnd()); 2218 assertEquals(false, mMockViewGroup.isPaddingRelative()); 2219 2220 // force RTL direction 2221 mMockViewGroup.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); 2222 2223 assertEquals(bottom, mMockViewGroup.getPaddingBottom()); 2224 assertEquals(top, mMockViewGroup.getPaddingTop()); 2225 assertEquals(left, mMockViewGroup.getPaddingLeft()); 2226 assertEquals(right, mMockViewGroup.getPaddingRight()); 2227 2228 assertEquals(right, mMockViewGroup.getPaddingStart()); 2229 assertEquals(left, mMockViewGroup.getPaddingEnd()); 2230 assertEquals(false, mMockViewGroup.isPaddingRelative()); 2231 } 2232 2233 @UiThreadTest 2234 @Test testSetPaddingRelative()2235 public void testSetPaddingRelative() { 2236 final int start = 1; 2237 final int top = 2; 2238 final int end = 3; 2239 final int bottom = 4; 2240 2241 assertEquals(0, mMockViewGroup.getPaddingBottom()); 2242 assertEquals(0, mMockViewGroup.getPaddingTop()); 2243 assertEquals(0, mMockViewGroup.getPaddingLeft()); 2244 assertEquals(0, mMockViewGroup.getPaddingRight()); 2245 assertEquals(0, mMockViewGroup.getPaddingStart()); 2246 assertEquals(0, mMockViewGroup.getPaddingEnd()); 2247 2248 mMockViewGroup.setPaddingRelative(start, top, end, bottom); 2249 2250 assertEquals(bottom, mMockViewGroup.getPaddingBottom()); 2251 assertEquals(top, mMockViewGroup.getPaddingTop()); 2252 assertEquals(start, mMockViewGroup.getPaddingLeft()); 2253 assertEquals(end, mMockViewGroup.getPaddingRight()); 2254 2255 assertEquals(start, mMockViewGroup.getPaddingStart()); 2256 assertEquals(end, mMockViewGroup.getPaddingEnd()); 2257 assertEquals(true, mMockViewGroup.isPaddingRelative()); 2258 2259 // force RTL direction after setting relative padding 2260 mMockViewGroup.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); 2261 2262 assertEquals(bottom, mMockViewGroup.getPaddingBottom()); 2263 assertEquals(top, mMockViewGroup.getPaddingTop()); 2264 assertEquals(end, mMockViewGroup.getPaddingLeft()); 2265 assertEquals(start, mMockViewGroup.getPaddingRight()); 2266 2267 assertEquals(start, mMockViewGroup.getPaddingStart()); 2268 assertEquals(end, mMockViewGroup.getPaddingEnd()); 2269 assertEquals(true, mMockViewGroup.isPaddingRelative()); 2270 2271 // force RTL direction before setting relative padding 2272 mMockViewGroup = new MockViewGroup(mContext); 2273 mMockViewGroup.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); 2274 2275 assertEquals(0, mMockViewGroup.getPaddingBottom()); 2276 assertEquals(0, mMockViewGroup.getPaddingTop()); 2277 assertEquals(0, mMockViewGroup.getPaddingLeft()); 2278 assertEquals(0, mMockViewGroup.getPaddingRight()); 2279 assertEquals(0, mMockViewGroup.getPaddingStart()); 2280 assertEquals(0, mMockViewGroup.getPaddingEnd()); 2281 2282 mMockViewGroup.setPaddingRelative(start, top, end, bottom); 2283 2284 assertEquals(bottom, mMockViewGroup.getPaddingBottom()); 2285 assertEquals(top, mMockViewGroup.getPaddingTop()); 2286 assertEquals(end, mMockViewGroup.getPaddingLeft()); 2287 assertEquals(start, mMockViewGroup.getPaddingRight()); 2288 2289 assertEquals(start, mMockViewGroup.getPaddingStart()); 2290 assertEquals(end, mMockViewGroup.getPaddingEnd()); 2291 assertEquals(true, mMockViewGroup.isPaddingRelative()); 2292 } 2293 2294 @UiThreadTest 2295 @Test testSetPersistentDrawingCache()2296 public void testSetPersistentDrawingCache() { 2297 mMockViewGroup.setPersistentDrawingCache(1); 2298 assertEquals(1 & ViewGroup.PERSISTENT_ALL_CACHES, mMockViewGroup 2299 .getPersistentDrawingCache()); 2300 } 2301 2302 @UiThreadTest 2303 @Test testShowContextMenuForChild()2304 public void testShowContextMenuForChild() { 2305 MockViewGroup parent = new MockViewGroup(mContext); 2306 MockViewGroup child = new MockViewGroup(mContext); 2307 parent.addView(child); 2308 2309 child.showContextMenuForChild(null); 2310 assertTrue(parent.isShowContextMenuForChildCalled); 2311 } 2312 2313 @UiThreadTest 2314 @Test testShowContextMenuForChild_WithXYCoords()2315 public void testShowContextMenuForChild_WithXYCoords() { 2316 MockViewGroup parent = new MockViewGroup(mContext); 2317 MockViewGroup child = new MockViewGroup(mContext); 2318 parent.addView(child); 2319 2320 child.showContextMenuForChild(null, 48, 48); 2321 assertTrue(parent.isShowContextMenuForChildCalledWithXYCoords); 2322 } 2323 2324 @UiThreadTest 2325 @Test testStartLayoutAnimation()2326 public void testStartLayoutAnimation() { 2327 RotateAnimation animation = new RotateAnimation(0.1f, 0.1f); 2328 LayoutAnimationController la = new LayoutAnimationController(animation); 2329 mMockViewGroup.setLayoutAnimation(la); 2330 2331 mMockViewGroup.layout(1, 1, 100, 100); 2332 assertFalse(mMockViewGroup.isLayoutRequested()); 2333 mMockViewGroup.startLayoutAnimation(); 2334 assertTrue(mMockViewGroup.isLayoutRequested()); 2335 } 2336 2337 @UiThreadTest 2338 @Test testUpdateViewLayout()2339 public void testUpdateViewLayout() { 2340 MockViewGroup parent = new MockViewGroup(mContext); 2341 MockViewGroup child = new MockViewGroup(mContext); 2342 2343 parent.addView(child); 2344 LayoutParams param = new LayoutParams(100, 200); 2345 parent.updateViewLayout(child, param); 2346 assertEquals(param.width, child.getLayoutParams().width); 2347 assertEquals(param.height, child.getLayoutParams().height); 2348 } 2349 2350 @UiThreadTest 2351 @Test testDebug()2352 public void testDebug() { 2353 final int EXPECTED = 100; 2354 MockViewGroup parent = new MockViewGroup(mContext); 2355 MockViewGroup child = new MockViewGroup(mContext); 2356 parent.addView(child); 2357 2358 parent.debug(EXPECTED); 2359 assertEquals(EXPECTED + 1, child.debugDepth); 2360 } 2361 2362 @UiThreadTest 2363 @Test testDispatchKeyEventPreIme()2364 public void testDispatchKeyEventPreIme() { 2365 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER); 2366 assertFalse(mMockViewGroup.dispatchKeyEventPreIme(event)); 2367 assertFalse(mMockViewGroup.dispatchKeyShortcutEvent(event)); 2368 2369 mMockViewGroup.addView(mMockTextView); 2370 mMockViewGroup.requestChildFocus(mMockTextView, null); 2371 mMockViewGroup.layout(0, 0, 100, 200); 2372 assertFalse(mMockViewGroup.dispatchKeyEventPreIme(event)); 2373 assertFalse(mMockViewGroup.dispatchKeyShortcutEvent(event)); 2374 2375 mMockViewGroup.requestChildFocus(mMockTextView, null); 2376 mMockTextView.layout(0, 0, 50, 50); 2377 assertTrue(mMockViewGroup.dispatchKeyEventPreIme(event)); 2378 assertTrue(mMockViewGroup.dispatchKeyShortcutEvent(event)); 2379 2380 mMockViewGroup.setStaticTransformationsEnabled(true); 2381 Canvas canvas = new Canvas(); 2382 mMockViewGroup.drawChild(canvas, mMockTextView, 100); 2383 assertTrue(mMockViewGroup.isGetChildStaticTransformationCalled); 2384 mMockViewGroup.isGetChildStaticTransformationCalled = false; 2385 mMockViewGroup.setStaticTransformationsEnabled(false); 2386 mMockViewGroup.drawChild(canvas, mMockTextView, 100); 2387 assertFalse(mMockViewGroup.isGetChildStaticTransformationCalled); 2388 } 2389 2390 @UiThreadTest 2391 @Test testStartActionModeForChildRespectsSubclassModeOnPrimary()2392 public void testStartActionModeForChildRespectsSubclassModeOnPrimary() { 2393 MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext); 2394 MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext); 2395 vg.shouldReturnOwnTypelessActionMode = true; 2396 vgParent.addView(vg); 2397 vg.addView(mMockTextView); 2398 2399 mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_PRIMARY); 2400 2401 assertTrue(vg.isStartActionModeForChildTypedCalled); 2402 assertTrue(vg.isStartActionModeForChildTypelessCalled); 2403 // Call should not bubble up as we have an intercepting implementation. 2404 assertFalse(vgParent.isStartActionModeForChildTypedCalled); 2405 } 2406 2407 @UiThreadTest 2408 @Test testStartActionModeForChildIgnoresSubclassModeOnFloating()2409 public void testStartActionModeForChildIgnoresSubclassModeOnFloating() { 2410 MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext); 2411 MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext); 2412 vg.shouldReturnOwnTypelessActionMode = true; 2413 vgParent.addView(vg); 2414 vg.addView(mMockTextView); 2415 2416 mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_FLOATING); 2417 2418 assertTrue(vg.isStartActionModeForChildTypedCalled); 2419 assertFalse(vg.isStartActionModeForChildTypelessCalled); 2420 // Call should bubble up as we have a floating type. 2421 assertTrue(vgParent.isStartActionModeForChildTypedCalled); 2422 } 2423 2424 @UiThreadTest 2425 @Test testStartActionModeForChildTypedBubblesUpToParent()2426 public void testStartActionModeForChildTypedBubblesUpToParent() { 2427 MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext); 2428 MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext); 2429 vgParent.addView(vg); 2430 vg.addView(mMockTextView); 2431 2432 mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK, ActionMode.TYPE_FLOATING); 2433 2434 assertTrue(vg.isStartActionModeForChildTypedCalled); 2435 assertTrue(vgParent.isStartActionModeForChildTypedCalled); 2436 } 2437 2438 @UiThreadTest 2439 @Test testStartActionModeForChildTypelessBubblesUpToParent()2440 public void testStartActionModeForChildTypelessBubblesUpToParent() { 2441 MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext); 2442 MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext); 2443 vgParent.addView(vg); 2444 vg.addView(mMockTextView); 2445 2446 mMockTextView.startActionMode(NO_OP_ACTION_MODE_CALLBACK); 2447 2448 assertTrue(vg.isStartActionModeForChildTypedCalled); 2449 assertTrue(vg.isStartActionModeForChildTypelessCalled); 2450 assertTrue(vgParent.isStartActionModeForChildTypedCalled); 2451 } 2452 2453 @UiThreadTest 2454 @Test testTemporaryDetach()2455 public void testTemporaryDetach() { 2456 // [vgParent] 2457 // - [viewParent1] 2458 // - [viewParent1] 2459 // - [mMockViewGroup] 2460 // - [view1] 2461 // - [view2] 2462 MockViewGroupSubclass vgParent = new MockViewGroupSubclass(mContext); 2463 TemporaryDetachingMockView viewParent1 = new TemporaryDetachingMockView(mContext); 2464 TemporaryDetachingMockView viewParent2 = new TemporaryDetachingMockView(mContext); 2465 vgParent.addView(viewParent1); 2466 vgParent.addView(viewParent2); 2467 MockViewGroupSubclass vg = new MockViewGroupSubclass(mContext); 2468 vgParent.addView(vg); 2469 TemporaryDetachingMockView view1 = new TemporaryDetachingMockView(mContext); 2470 TemporaryDetachingMockView view2 = new TemporaryDetachingMockView(mContext); 2471 vg.addView(view1); 2472 vg.addView(view2); 2473 2474 // Make sure that no View is temporarity detached in the initial state. 2475 assertFalse(viewParent1.isTemporarilyDetached()); 2476 assertEquals(0, viewParent1.getDispatchStartTemporaryDetachCount()); 2477 assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount()); 2478 assertEquals(0, viewParent1.getOnStartTemporaryDetachCount()); 2479 assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount()); 2480 assertFalse(viewParent2.isTemporarilyDetached()); 2481 assertEquals(0, viewParent2.getDispatchStartTemporaryDetachCount()); 2482 assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount()); 2483 assertEquals(0, viewParent2.getOnStartTemporaryDetachCount()); 2484 assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount()); 2485 assertFalse(view1.isTemporarilyDetached()); 2486 assertEquals(0, view1.getDispatchStartTemporaryDetachCount()); 2487 assertEquals(0, view1.getDispatchFinishTemporaryDetachCount()); 2488 assertEquals(0, view1.getOnStartTemporaryDetachCount()); 2489 assertEquals(0, view1.getOnFinishTemporaryDetachCount()); 2490 assertFalse(view2.isTemporarilyDetached()); 2491 assertEquals(0, view2.getDispatchStartTemporaryDetachCount()); 2492 assertEquals(0, view2.getDispatchFinishTemporaryDetachCount()); 2493 assertEquals(0, view2.getOnStartTemporaryDetachCount()); 2494 assertEquals(0, view2.getOnFinishTemporaryDetachCount()); 2495 2496 // [vgParent] 2497 // - [viewParent1] 2498 // - [viewParent1] 2499 // - [mMockViewGroup] <- dispatchStartTemporaryDetach() 2500 // - [view1] 2501 // - [view2] 2502 vg.dispatchStartTemporaryDetach(); 2503 2504 assertFalse(viewParent1.isTemporarilyDetached()); 2505 assertEquals(0, viewParent1.getDispatchStartTemporaryDetachCount()); 2506 assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount()); 2507 assertEquals(0, viewParent1.getOnStartTemporaryDetachCount()); 2508 assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount()); 2509 assertFalse(viewParent2.isTemporarilyDetached()); 2510 assertEquals(0, viewParent2.getDispatchStartTemporaryDetachCount()); 2511 assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount()); 2512 assertEquals(0, viewParent2.getOnStartTemporaryDetachCount()); 2513 assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount()); 2514 assertTrue(view1.isTemporarilyDetached()); 2515 assertEquals(1, view1.getDispatchStartTemporaryDetachCount()); 2516 assertEquals(0, view1.getDispatchFinishTemporaryDetachCount()); 2517 assertEquals(1, view1.getOnStartTemporaryDetachCount()); 2518 assertEquals(0, view1.getOnFinishTemporaryDetachCount()); 2519 assertTrue(view2.isTemporarilyDetached()); 2520 assertEquals(1, view2.getDispatchStartTemporaryDetachCount()); 2521 assertEquals(0, view2.getDispatchFinishTemporaryDetachCount()); 2522 assertEquals(1, view2.getOnStartTemporaryDetachCount()); 2523 assertEquals(0, view2.getOnFinishTemporaryDetachCount()); 2524 2525 // [vgParent] 2526 // - [viewParent1] 2527 // - [viewParent1] 2528 // - [mMockViewGroup] <- dispatchFinishTemporaryDetach() 2529 // - [view1] 2530 // - [view2] 2531 vg.dispatchFinishTemporaryDetach(); 2532 2533 assertFalse(viewParent1.isTemporarilyDetached()); 2534 assertEquals(0, viewParent1.getDispatchStartTemporaryDetachCount()); 2535 assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount()); 2536 assertEquals(0, viewParent1.getOnStartTemporaryDetachCount()); 2537 assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount()); 2538 assertFalse(viewParent2.isTemporarilyDetached()); 2539 assertEquals(0, viewParent2.getDispatchStartTemporaryDetachCount()); 2540 assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount()); 2541 assertEquals(0, viewParent2.getOnStartTemporaryDetachCount()); 2542 assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount()); 2543 assertFalse(view1.isTemporarilyDetached()); 2544 assertEquals(1, view1.getDispatchStartTemporaryDetachCount()); 2545 assertEquals(1, view1.getDispatchFinishTemporaryDetachCount()); 2546 assertEquals(1, view1.getOnStartTemporaryDetachCount()); 2547 assertEquals(1, view1.getOnFinishTemporaryDetachCount()); 2548 assertFalse(view2.isTemporarilyDetached()); 2549 assertEquals(1, view2.getDispatchStartTemporaryDetachCount()); 2550 assertEquals(1, view2.getDispatchFinishTemporaryDetachCount()); 2551 assertEquals(1, view2.getOnStartTemporaryDetachCount()); 2552 assertEquals(1, view2.getOnFinishTemporaryDetachCount()); 2553 2554 // [vgParent] <- dispatchStartTemporaryDetach() 2555 // - [viewParent1] 2556 // - [viewParent1] 2557 // - [mMockViewGroup] 2558 // - [view1] 2559 // - [view2] 2560 vgParent.dispatchStartTemporaryDetach(); 2561 2562 assertTrue(viewParent1.isTemporarilyDetached()); 2563 assertEquals(1, viewParent1.getDispatchStartTemporaryDetachCount()); 2564 assertEquals(0, viewParent1.getDispatchFinishTemporaryDetachCount()); 2565 assertEquals(1, viewParent1.getOnStartTemporaryDetachCount()); 2566 assertEquals(0, viewParent1.getOnFinishTemporaryDetachCount()); 2567 assertTrue(viewParent2.isTemporarilyDetached()); 2568 assertEquals(1, viewParent2.getDispatchStartTemporaryDetachCount()); 2569 assertEquals(0, viewParent2.getDispatchFinishTemporaryDetachCount()); 2570 assertEquals(1, viewParent2.getOnStartTemporaryDetachCount()); 2571 assertEquals(0, viewParent2.getOnFinishTemporaryDetachCount()); 2572 assertTrue(view1.isTemporarilyDetached()); 2573 assertEquals(2, view1.getDispatchStartTemporaryDetachCount()); 2574 assertEquals(1, view1.getDispatchFinishTemporaryDetachCount()); 2575 assertEquals(2, view1.getOnStartTemporaryDetachCount()); 2576 assertEquals(1, view1.getOnFinishTemporaryDetachCount()); 2577 assertTrue(view2.isTemporarilyDetached()); 2578 assertEquals(2, view2.getDispatchStartTemporaryDetachCount()); 2579 assertEquals(1, view2.getDispatchFinishTemporaryDetachCount()); 2580 assertEquals(2, view2.getOnStartTemporaryDetachCount()); 2581 assertEquals(1, view2.getOnFinishTemporaryDetachCount()); 2582 2583 // [vgParent] <- dispatchFinishTemporaryDetach() 2584 // - [viewParent1] 2585 // - [viewParent1] 2586 // - [mMockViewGroup] 2587 // - [view1] 2588 // - [view2] 2589 vgParent.dispatchFinishTemporaryDetach(); 2590 2591 assertFalse(viewParent1.isTemporarilyDetached()); 2592 assertEquals(1, viewParent1.getDispatchStartTemporaryDetachCount()); 2593 assertEquals(1, viewParent1.getDispatchFinishTemporaryDetachCount()); 2594 assertEquals(1, viewParent1.getOnStartTemporaryDetachCount()); 2595 assertEquals(1, viewParent1.getOnFinishTemporaryDetachCount()); 2596 assertFalse(viewParent2.isTemporarilyDetached()); 2597 assertEquals(1, viewParent2.getDispatchStartTemporaryDetachCount()); 2598 assertEquals(1, viewParent2.getDispatchFinishTemporaryDetachCount()); 2599 assertEquals(1, viewParent2.getOnStartTemporaryDetachCount()); 2600 assertEquals(1, viewParent2.getOnFinishTemporaryDetachCount()); 2601 assertFalse(view1.isTemporarilyDetached()); 2602 assertEquals(2, view1.getDispatchStartTemporaryDetachCount()); 2603 assertEquals(2, view1.getDispatchFinishTemporaryDetachCount()); 2604 assertEquals(2, view1.getOnStartTemporaryDetachCount()); 2605 assertEquals(2, view1.getOnFinishTemporaryDetachCount()); 2606 assertFalse(view2.isTemporarilyDetached()); 2607 assertEquals(2, view2.getDispatchStartTemporaryDetachCount()); 2608 assertEquals(2, view2.getDispatchFinishTemporaryDetachCount()); 2609 assertEquals(2, view2.getOnStartTemporaryDetachCount()); 2610 assertEquals(2, view2.getOnFinishTemporaryDetachCount()); 2611 } 2612 2613 private static final ActionMode.Callback NO_OP_ACTION_MODE_CALLBACK = 2614 new ActionMode.Callback() { 2615 @Override 2616 public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 2617 return false; 2618 } 2619 2620 @Override 2621 public void onDestroyActionMode(ActionMode mode) {} 2622 2623 @Override 2624 public boolean onCreateActionMode(ActionMode mode, Menu menu) { 2625 return false; 2626 } 2627 2628 @Override 2629 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 2630 return false; 2631 } 2632 }; 2633 2634 private static final ActionMode NO_OP_ACTION_MODE = 2635 new ActionMode() { 2636 @Override 2637 public void setTitle(CharSequence title) {} 2638 2639 @Override 2640 public void setTitle(int resId) {} 2641 2642 @Override 2643 public void setSubtitle(CharSequence subtitle) {} 2644 2645 @Override 2646 public void setSubtitle(int resId) {} 2647 2648 @Override 2649 public void setCustomView(View view) {} 2650 2651 @Override 2652 public void invalidate() {} 2653 2654 @Override 2655 public void finish() {} 2656 2657 @Override 2658 public Menu getMenu() { 2659 return null; 2660 } 2661 2662 @Override 2663 public CharSequence getTitle() { 2664 return null; 2665 } 2666 2667 @Override 2668 public CharSequence getSubtitle() { 2669 return null; 2670 } 2671 2672 @Override 2673 public View getCustomView() { 2674 return null; 2675 } 2676 2677 @Override 2678 public MenuInflater getMenuInflater() { 2679 return null; 2680 } 2681 }; 2682 2683 private static class MockViewGroupSubclass extends ViewGroup { 2684 boolean isStartActionModeForChildTypedCalled = false; 2685 boolean isStartActionModeForChildTypelessCalled = false; 2686 boolean shouldReturnOwnTypelessActionMode = false; 2687 MockViewGroupSubclass(Context context)2688 public MockViewGroupSubclass(Context context) { 2689 super(context); 2690 } 2691 2692 @Override startActionModeForChild(View originalView, ActionMode.Callback callback)2693 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { 2694 isStartActionModeForChildTypelessCalled = true; 2695 if (shouldReturnOwnTypelessActionMode) { 2696 return NO_OP_ACTION_MODE; 2697 } 2698 return super.startActionModeForChild(originalView, callback); 2699 } 2700 2701 @Override startActionModeForChild( View originalView, ActionMode.Callback callback, int type)2702 public ActionMode startActionModeForChild( 2703 View originalView, ActionMode.Callback callback, int type) { 2704 isStartActionModeForChildTypedCalled = true; 2705 return super.startActionModeForChild(originalView, callback, type); 2706 } 2707 2708 @Override onLayout(boolean changed, int l, int t, int r, int b)2709 protected void onLayout(boolean changed, int l, int t, int r, int b) { 2710 // no-op 2711 } 2712 } 2713 2714 static public int resetRtlPropertiesCount; 2715 static public int resetResolvedLayoutDirectionCount; 2716 static public int resetResolvedTextDirectionCount; 2717 static public int resetResolvedTextAlignmentCount; 2718 static public int resetResolvedPaddingCount; 2719 static public int resetResolvedDrawablesCount; 2720 2721 clearRtlCounters()2722 private static void clearRtlCounters() { 2723 resetRtlPropertiesCount = 0; 2724 resetResolvedLayoutDirectionCount = 0; 2725 resetResolvedTextDirectionCount = 0; 2726 resetResolvedTextAlignmentCount = 0; 2727 resetResolvedPaddingCount = 0; 2728 resetResolvedDrawablesCount = 0; 2729 } 2730 2731 @UiThreadTest 2732 @Test testResetRtlProperties()2733 public void testResetRtlProperties() { 2734 clearRtlCounters(); 2735 2736 MockView2 v1 = new MockView2(mContext); 2737 MockView2 v2 = new MockView2(mContext); 2738 2739 MockViewGroup v3 = new MockViewGroup(mContext); 2740 MockView2 v4 = new MockView2(mContext); 2741 2742 v3.addView(v4); 2743 assertEquals(1, resetRtlPropertiesCount); 2744 assertEquals(1, resetResolvedLayoutDirectionCount); 2745 assertEquals(1, resetResolvedTextDirectionCount); 2746 assertEquals(1, resetResolvedTextAlignmentCount); 2747 assertEquals(1, resetResolvedPaddingCount); 2748 assertEquals(1, resetResolvedDrawablesCount); 2749 2750 clearRtlCounters(); 2751 mMockViewGroup.addView(v1); 2752 mMockViewGroup.addView(v2); 2753 mMockViewGroup.addView(v3); 2754 2755 assertEquals(3, resetRtlPropertiesCount); // for v1 / v2 / v3 only 2756 assertEquals(4, resetResolvedLayoutDirectionCount); // for v1 / v2 / v3 / v4 2757 assertEquals(4, resetResolvedTextDirectionCount); 2758 assertEquals(3, resetResolvedTextAlignmentCount); // for v1 / v2 / v3 only 2759 assertEquals(4, resetResolvedPaddingCount); 2760 assertEquals(4, resetResolvedDrawablesCount); 2761 2762 clearRtlCounters(); 2763 mMockViewGroup.resetRtlProperties(); 2764 assertEquals(1, resetRtlPropertiesCount); // for mMockViewGroup only 2765 assertEquals(5, resetResolvedLayoutDirectionCount); // for all 2766 assertEquals(5, resetResolvedTextDirectionCount); 2767 // for mMockViewGroup only as TextAlignment is not inherited (default is Gravity) 2768 assertEquals(1, resetResolvedTextAlignmentCount); 2769 assertEquals(5, resetResolvedPaddingCount); 2770 assertEquals(5, resetResolvedDrawablesCount); 2771 } 2772 2773 @UiThreadTest 2774 @Test testLayoutNotCalledWithSuppressLayoutTrue()2775 public void testLayoutNotCalledWithSuppressLayoutTrue() { 2776 mMockViewGroup.isRequestLayoutCalled = false; 2777 mMockViewGroup.suppressLayout(true); 2778 mMockViewGroup.layout(0, 0, 100, 100); 2779 2780 assertTrue(mMockViewGroup.isLayoutSuppressed()); 2781 assertFalse(mMockViewGroup.isOnLayoutCalled); 2782 assertFalse(mMockViewGroup.isRequestLayoutCalled); 2783 } 2784 2785 @UiThreadTest 2786 @Test testLayoutCalledAfterSettingBackSuppressLayoutToFalseTrue()2787 public void testLayoutCalledAfterSettingBackSuppressLayoutToFalseTrue() { 2788 mMockViewGroup.suppressLayout(true); 2789 mMockViewGroup.suppressLayout(false); 2790 mMockViewGroup.layout(0, 0, 100, 100); 2791 2792 assertFalse(mMockViewGroup.isLayoutSuppressed()); 2793 assertTrue(mMockViewGroup.isOnLayoutCalled); 2794 } 2795 2796 @UiThreadTest 2797 @Test testRequestLayoutCalledAfterSettingSuppressToFalseWhenItWasCalledWithTrue()2798 public void testRequestLayoutCalledAfterSettingSuppressToFalseWhenItWasCalledWithTrue() { 2799 mMockViewGroup.isRequestLayoutCalled = false; 2800 mMockViewGroup.suppressLayout(true); 2801 // now we call layout while in suppressed state 2802 mMockViewGroup.layout(0, 0, 100, 100); 2803 // then we undo suppressing. it should call requestLayout as we swallowed one layout call 2804 mMockViewGroup.suppressLayout(false); 2805 2806 assertTrue(mMockViewGroup.isRequestLayoutCalled); 2807 } 2808 2809 @UiThreadTest 2810 @Ignore("Turn on once ViewRootImpl.USE_NEW_INSETS is switched to true") 2811 @Test testDispatchInsets_affectsChildren()2812 public void testDispatchInsets_affectsChildren() { 2813 View v1 = new View(mContext); 2814 mMockViewGroup.addView(v1); 2815 2816 mMockViewGroup.setOnApplyWindowInsetsListener((v, insets) -> insets.inset(0, 0, 0, 10)); 2817 2818 OnApplyWindowInsetsListener listenerMock = mock(OnApplyWindowInsetsListener.class); 2819 v1.setOnApplyWindowInsetsListener(listenerMock); 2820 2821 WindowInsets insets = new WindowInsets.Builder().setSystemWindowInsets( 2822 Insets.of(10, 10, 10, 10)).build(); 2823 mMockViewGroup.dispatchApplyWindowInsets(insets); 2824 verify(listenerMock).onApplyWindowInsets(any(), 2825 eq(new WindowInsets.Builder() 2826 .setSystemWindowInsets(Insets.of(10, 10, 10, 0)).build())); 2827 } 2828 2829 @UiThreadTest 2830 @Ignore("Turn on once ViewRootImpl.USE_NEW_INSETS is switched to true") 2831 @Test testDispatchInsets_doesntAffectSiblings()2832 public void testDispatchInsets_doesntAffectSiblings() { 2833 View v1 = new View(mContext); 2834 View v2 = new View(mContext); 2835 mMockViewGroup.addView(v1); 2836 mMockViewGroup.addView(v2); 2837 2838 v1.setOnApplyWindowInsetsListener((v, insets) -> insets.inset(0, 0, 0, 10)); 2839 2840 OnApplyWindowInsetsListener listenerMock = mock(OnApplyWindowInsetsListener.class); 2841 v2.setOnApplyWindowInsetsListener(listenerMock); 2842 2843 WindowInsets insets = new WindowInsets.Builder().setSystemWindowInsets( 2844 Insets.of(10, 10, 10, 10)).build(); 2845 mMockViewGroup.dispatchApplyWindowInsets(insets); 2846 verify(listenerMock).onApplyWindowInsets(any(), 2847 eq(new WindowInsets.Builder() 2848 .setSystemWindowInsets(Insets.of(10, 10, 10, 10)).build())); 2849 } 2850 2851 @UiThreadTest 2852 @Ignore("Turn on once ViewRootImpl.USE_NEW_INSETS is switched to true") 2853 @Test testDispatchInsets_doesntAffectParentSiblings()2854 public void testDispatchInsets_doesntAffectParentSiblings() { 2855 ViewGroup v1 = new MockViewGroup(mContext); 2856 View v11 = new View(mContext); 2857 View v2 = new View(mContext); 2858 mMockViewGroup.addView(v1); 2859 v1.addView(v11); 2860 mMockViewGroup.addView(v2); 2861 2862 v11.setOnApplyWindowInsetsListener((v, insets) -> insets.inset(0, 0, 0, 10)); 2863 2864 OnApplyWindowInsetsListener listenerMock = mock(OnApplyWindowInsetsListener.class); 2865 v2.setOnApplyWindowInsetsListener(listenerMock); 2866 2867 WindowInsets insets = new WindowInsets.Builder().setSystemWindowInsets( 2868 Insets.of(10, 10, 10, 10)).build(); 2869 mMockViewGroup.dispatchApplyWindowInsets(insets); 2870 verify(listenerMock).onApplyWindowInsets(any(), 2871 eq(new WindowInsets.Builder() 2872 .setSystemWindowInsets(Insets.of(10, 10, 10, 10)).build())); 2873 } 2874 2875 @UiThreadTest 2876 @Test testDispatchInsets_consumeStopsDispatch()2877 public void testDispatchInsets_consumeStopsDispatch() { 2878 View v1 = new View(mContext); 2879 mMockViewGroup.addView(v1); 2880 2881 mMockViewGroup.setOnApplyWindowInsetsListener( 2882 (v, insets) -> insets.consumeSystemWindowInsets()); 2883 2884 OnApplyWindowInsetsListener listenerMock = mock(OnApplyWindowInsetsListener.class); 2885 v1.setOnApplyWindowInsetsListener(listenerMock); 2886 2887 WindowInsets insets = new WindowInsets.Builder().setSystemWindowInsets( 2888 Insets.of(10, 10, 10, 10)).build(); 2889 mMockViewGroup.dispatchApplyWindowInsets(insets); 2890 verify(listenerMock, never()).onApplyWindowInsets(any(), 2891 eq(new WindowInsets.Builder().build())); 2892 } 2893 2894 @UiThreadTest 2895 @Test testFindViewById_shouldBeDFS()2896 public void testFindViewById_shouldBeDFS() { 2897 View v1 = new View(mContext); 2898 View v2 = new View(mContext); 2899 View w1 = new View(mContext); 2900 View w2 = new View(mContext); 2901 v1.setId(2); 2902 v2.setId(2); 2903 w1.setId(3); 2904 w2.setId(3); 2905 ViewGroup vg1 = new MockViewGroup(mContext); 2906 mMockViewGroup.addView(vg1); 2907 vg1.addView(v1); 2908 mMockViewGroup.addView(v2); 2909 vg1.addView(w1); 2910 vg1.addView(w2); 2911 2912 assertSame(v1, mMockViewGroup.findViewById(2)); 2913 assertSame(w1, mMockViewGroup.findViewById(3)); 2914 } 2915 2916 static class MockTextView extends TextView { 2917 2918 public boolean isClearFocusCalled; 2919 public boolean isDispatchRestoreInstanceStateCalled; 2920 public int visibility; 2921 public boolean mIsRefreshDrawableStateCalled; 2922 public boolean isDrawCalled; 2923 MockTextView(Context context)2924 public MockTextView(Context context) { 2925 super(context); 2926 } 2927 2928 @Override draw(Canvas canvas)2929 public void draw(Canvas canvas) { 2930 super.draw(canvas); 2931 isDrawCalled = true; 2932 } 2933 2934 @Override clearFocus()2935 public void clearFocus() { 2936 isClearFocusCalled = true; 2937 super.clearFocus(); 2938 } 2939 2940 @Override dispatchKeyEvent(KeyEvent event)2941 public boolean dispatchKeyEvent(KeyEvent event) { 2942 return true; 2943 } 2944 2945 @Override dispatchRestoreInstanceState( SparseArray<Parcelable> container)2946 public void dispatchRestoreInstanceState( 2947 SparseArray<Parcelable> container) { 2948 isDispatchRestoreInstanceStateCalled = true; 2949 super.dispatchRestoreInstanceState(container); 2950 } 2951 2952 @Override onTrackballEvent(MotionEvent event)2953 public boolean onTrackballEvent(MotionEvent event) { 2954 return true; 2955 } 2956 2957 @Override dispatchUnhandledMove(View focused, int direction)2958 public boolean dispatchUnhandledMove(View focused, int direction) { 2959 return true; 2960 } 2961 2962 @Override onWindowVisibilityChanged(int visibility)2963 public void onWindowVisibilityChanged(int visibility) { 2964 this.visibility = visibility; 2965 super.onWindowVisibilityChanged(visibility); 2966 } 2967 2968 @Override refreshDrawableState()2969 public void refreshDrawableState() { 2970 mIsRefreshDrawableStateCalled = true; 2971 super.refreshDrawableState(); 2972 } 2973 2974 @Override dispatchTouchEvent(MotionEvent event)2975 public boolean dispatchTouchEvent(MotionEvent event) { 2976 super.dispatchTouchEvent(event); 2977 return true; 2978 } 2979 2980 @Override dispatchKeyEventPreIme(KeyEvent event)2981 public boolean dispatchKeyEventPreIme(KeyEvent event) { 2982 return true; 2983 } 2984 2985 @Override dispatchKeyShortcutEvent(KeyEvent event)2986 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 2987 return true; 2988 } 2989 } 2990 2991 static class MockViewGroup extends ViewGroup { 2992 2993 public boolean isRecomputeViewAttributesCalled; 2994 public boolean isShowContextMenuForChildCalled; 2995 public boolean isShowContextMenuForChildCalledWithXYCoords; 2996 public boolean isRefreshDrawableStateCalled; 2997 public boolean isOnRestoreInstanceStateCalled; 2998 public boolean isOnCreateDrawableStateCalled; 2999 public boolean isOnInterceptTouchEventCalled; 3000 public boolean isOnRequestFocusInDescendantsCalled; 3001 public boolean isOnViewAddedCalled; 3002 public boolean isOnViewRemovedCalled; 3003 public boolean isFocusableViewAvailable; 3004 public boolean isDispatchDrawCalled; 3005 public boolean isRequestDisallowInterceptTouchEventCalled; 3006 public boolean isRequestTransparentRegionCalled; 3007 public boolean isGetChildStaticTransformationCalled; 3008 public int[] location; 3009 public int measureChildCalledTime; 3010 public boolean isOnAnimationEndCalled; 3011 public boolean isOnAnimationStartCalled; 3012 public int debugDepth; 3013 public int drawChildCalledTime; 3014 public Canvas canvas; 3015 public boolean isDrawableStateChangedCalled; 3016 public boolean isRequestLayoutCalled; 3017 public boolean isOnLayoutCalled; 3018 public boolean isOnDescendantInvalidatedCalled; 3019 public int left; 3020 public int top; 3021 public int right; 3022 public int bottom; 3023 public boolean returnActualFocusSearchResult; 3024 MockViewGroup(Context context, AttributeSet attrs, int defStyle)3025 public MockViewGroup(Context context, AttributeSet attrs, int defStyle) { 3026 super(context, attrs, defStyle); 3027 } 3028 MockViewGroup(Context context, AttributeSet attrs)3029 public MockViewGroup(Context context, AttributeSet attrs) { 3030 super(context, attrs); 3031 } 3032 MockViewGroup(Context context)3033 public MockViewGroup(Context context) { 3034 super(context); 3035 } 3036 3037 @Override onLayout(boolean changed, int l, int t, int r, int b)3038 public void onLayout(boolean changed, int l, int t, int r, int b) { 3039 isOnLayoutCalled = true; 3040 left = l; 3041 top = t; 3042 right = r; 3043 bottom = b; 3044 } 3045 3046 @Override addViewInLayout(View child, int index, ViewGroup.LayoutParams params)3047 public boolean addViewInLayout(View child, int index, 3048 ViewGroup.LayoutParams params) { 3049 return super.addViewInLayout(child, index, params); 3050 } 3051 3052 @Override addViewInLayout(View child, int index, ViewGroup.LayoutParams params, boolean preventRequestLayout)3053 public boolean addViewInLayout(View child, int index, 3054 ViewGroup.LayoutParams params, boolean preventRequestLayout) { 3055 return super.addViewInLayout(child, index, params, preventRequestLayout); 3056 } 3057 3058 @Override attachLayoutAnimationParameters(View child, ViewGroup.LayoutParams params, int index, int count)3059 public void attachLayoutAnimationParameters(View child, 3060 ViewGroup.LayoutParams params, int index, int count) { 3061 super.attachLayoutAnimationParameters(child, params, index, count); 3062 } 3063 3064 @Override attachViewToParent(View child, int index, LayoutParams params)3065 public void attachViewToParent(View child, int index, 3066 LayoutParams params) { 3067 super.attachViewToParent(child, index, params); 3068 } 3069 3070 @Override canAnimate()3071 public boolean canAnimate() { 3072 return super.canAnimate(); 3073 } 3074 3075 @Override checkLayoutParams(LayoutParams p)3076 public boolean checkLayoutParams(LayoutParams p) { 3077 return super.checkLayoutParams(p); 3078 } 3079 3080 @Override refreshDrawableState()3081 public void refreshDrawableState() { 3082 isRefreshDrawableStateCalled = true; 3083 super.refreshDrawableState(); 3084 } 3085 3086 @Override cleanupLayoutState(View child)3087 public void cleanupLayoutState(View child) { 3088 super.cleanupLayoutState(child); 3089 } 3090 3091 @Override detachAllViewsFromParent()3092 public void detachAllViewsFromParent() { 3093 super.detachAllViewsFromParent(); 3094 } 3095 3096 @Override detachViewFromParent(int index)3097 public void detachViewFromParent(int index) { 3098 super.detachViewFromParent(index); 3099 } 3100 3101 @Override detachViewFromParent(View child)3102 public void detachViewFromParent(View child) { 3103 super.detachViewFromParent(child); 3104 } 3105 @Override 3106 detachViewsFromParent(int start, int count)3107 public void detachViewsFromParent(int start, int count) { 3108 super.detachViewsFromParent(start, count); 3109 } 3110 3111 @Override dispatchDraw(Canvas canvas)3112 public void dispatchDraw(Canvas canvas) { 3113 isDispatchDrawCalled = true; 3114 super.dispatchDraw(canvas); 3115 this.canvas = canvas; 3116 } 3117 3118 @Override dispatchFreezeSelfOnly(SparseArray<Parcelable> container)3119 public void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) { 3120 super.dispatchFreezeSelfOnly(container); 3121 } 3122 3123 @Override dispatchRestoreInstanceState( SparseArray<Parcelable> container)3124 public void dispatchRestoreInstanceState( 3125 SparseArray<Parcelable> container) { 3126 super.dispatchRestoreInstanceState(container); 3127 } 3128 3129 @Override dispatchSaveInstanceState( SparseArray<Parcelable> container)3130 public void dispatchSaveInstanceState( 3131 SparseArray<Parcelable> container) { 3132 super.dispatchSaveInstanceState(container); 3133 } 3134 3135 @Override dispatchSetPressed(boolean pressed)3136 public void dispatchSetPressed(boolean pressed) { 3137 super.dispatchSetPressed(pressed); 3138 } 3139 3140 @Override dispatchThawSelfOnly(SparseArray<Parcelable> container)3141 public void dispatchThawSelfOnly(SparseArray<Parcelable> container) { 3142 super.dispatchThawSelfOnly(container); 3143 } 3144 3145 @Override onRestoreInstanceState(Parcelable state)3146 public void onRestoreInstanceState(Parcelable state) { 3147 isOnRestoreInstanceStateCalled = true; 3148 super.onRestoreInstanceState(state); 3149 } 3150 3151 @Override drawableStateChanged()3152 public void drawableStateChanged() { 3153 isDrawableStateChangedCalled = true; 3154 super.drawableStateChanged(); 3155 } 3156 3157 @Override drawChild(Canvas canvas, View child, long drawingTime)3158 public boolean drawChild(Canvas canvas, View child, long drawingTime) { 3159 drawChildCalledTime++; 3160 return super.drawChild(canvas, child, drawingTime); 3161 } 3162 3163 @Override fitSystemWindows(Rect insets)3164 public boolean fitSystemWindows(Rect insets) { 3165 return super.fitSystemWindows(insets); 3166 } 3167 3168 @Override generateDefaultLayoutParams()3169 public LayoutParams generateDefaultLayoutParams() { 3170 return super.generateDefaultLayoutParams(); 3171 } 3172 3173 @Override generateLayoutParams(LayoutParams p)3174 public LayoutParams generateLayoutParams(LayoutParams p) { 3175 return super.generateLayoutParams(p); 3176 } 3177 3178 @Override getChildDrawingOrder(int childCount, int i)3179 public int getChildDrawingOrder(int childCount, int i) { 3180 return super.getChildDrawingOrder(childCount, i); 3181 } 3182 3183 @Override getChildStaticTransformation(View child, Transformation t)3184 public boolean getChildStaticTransformation(View child, 3185 Transformation t) { 3186 isGetChildStaticTransformationCalled = true; 3187 return super.getChildStaticTransformation(child, t); 3188 } 3189 3190 @Override measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)3191 public void measureChild(View child, int parentWidthMeasureSpec, 3192 int parentHeightMeasureSpec) { 3193 measureChildCalledTime++; 3194 super.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec); 3195 } 3196 3197 @Override measureChildren(int widthMeasureSpec, int heightMeasureSpec)3198 public void measureChildren(int widthMeasureSpec, 3199 int heightMeasureSpec) { 3200 super.measureChildren(widthMeasureSpec, heightMeasureSpec); 3201 } 3202 3203 @Override measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)3204 public void measureChildWithMargins(View child, 3205 int parentWidthMeasureSpec, int widthUsed, 3206 int parentHeightMeasureSpec, int heightUsed) { 3207 super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, 3208 parentHeightMeasureSpec, heightUsed); 3209 } 3210 3211 @Override onAnimationEnd()3212 public void onAnimationEnd() { 3213 isOnAnimationEndCalled = true; 3214 super.onAnimationEnd(); 3215 } 3216 3217 @Override onAnimationStart()3218 public void onAnimationStart() { 3219 super.onAnimationStart(); 3220 isOnAnimationStartCalled = true; 3221 } 3222 3223 @Override onCreateDrawableState(int extraSpace)3224 public int[] onCreateDrawableState(int extraSpace) { 3225 isOnCreateDrawableStateCalled = true; 3226 return super.onCreateDrawableState(extraSpace); 3227 } 3228 3229 @Override onInterceptTouchEvent(MotionEvent ev)3230 public boolean onInterceptTouchEvent(MotionEvent ev) { 3231 isOnInterceptTouchEventCalled = true; 3232 return super.onInterceptTouchEvent(ev); 3233 } 3234 3235 @Override onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)3236 public boolean onRequestFocusInDescendants(int direction, 3237 Rect previouslyFocusedRect) { 3238 isOnRequestFocusInDescendantsCalled = true; 3239 return super.onRequestFocusInDescendants(direction, previouslyFocusedRect); 3240 } 3241 3242 @Override onViewAdded(View child)3243 public void onViewAdded(View child) { 3244 isOnViewAddedCalled = true; 3245 super.onViewAdded(child); 3246 } 3247 3248 @Override onViewRemoved(View child)3249 public void onViewRemoved(View child) { 3250 isOnViewRemovedCalled = true; 3251 super.onViewRemoved(child); 3252 } 3253 3254 @Override recomputeViewAttributes(View child)3255 public void recomputeViewAttributes(View child) { 3256 isRecomputeViewAttributesCalled = true; 3257 super.recomputeViewAttributes(child); 3258 } 3259 3260 @Override removeDetachedView(View child, boolean animate)3261 public void removeDetachedView(View child, boolean animate) { 3262 super.removeDetachedView(child, animate); 3263 } 3264 3265 @Override showContextMenuForChild(View originalView)3266 public boolean showContextMenuForChild(View originalView) { 3267 isShowContextMenuForChildCalled = true; 3268 return super.showContextMenuForChild(originalView); 3269 } 3270 3271 @Override showContextMenuForChild(View originalView, float x, float y)3272 public boolean showContextMenuForChild(View originalView, float x, float y) { 3273 isShowContextMenuForChildCalledWithXYCoords = true; 3274 return super.showContextMenuForChild(originalView, x, y); 3275 } 3276 3277 @Override isInTouchMode()3278 public boolean isInTouchMode() { 3279 super.isInTouchMode(); 3280 return false; 3281 } 3282 3283 @Override focusableViewAvailable(View v)3284 public void focusableViewAvailable(View v) { 3285 isFocusableViewAvailable = true; 3286 super.focusableViewAvailable(v); 3287 } 3288 3289 @Override focusSearch(View focused, int direction)3290 public View focusSearch(View focused, int direction) { 3291 if (returnActualFocusSearchResult) { 3292 return super.focusSearch(focused, direction); 3293 } else { 3294 super.focusSearch(focused, direction); 3295 return focused; 3296 } 3297 } 3298 3299 @Override requestDisallowInterceptTouchEvent(boolean disallowIntercept)3300 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 3301 isRequestDisallowInterceptTouchEventCalled = true; 3302 super.requestDisallowInterceptTouchEvent(disallowIntercept); 3303 } 3304 3305 @Override requestTransparentRegion(View child)3306 public void requestTransparentRegion(View child) { 3307 isRequestTransparentRegionCalled = true; 3308 super.requestTransparentRegion(child); 3309 } 3310 3311 @Override debug(int depth)3312 public void debug(int depth) { 3313 debugDepth = depth; 3314 super.debug(depth); 3315 } 3316 3317 @Override requestLayout()3318 public void requestLayout() { 3319 isRequestLayoutCalled = true; 3320 super.requestLayout(); 3321 } 3322 3323 @Override setStaticTransformationsEnabled(boolean enabled)3324 public void setStaticTransformationsEnabled(boolean enabled) { 3325 super.setStaticTransformationsEnabled(enabled); 3326 } 3327 3328 @Override resetRtlProperties()3329 public void resetRtlProperties() { 3330 super.resetRtlProperties(); 3331 resetRtlPropertiesCount++; 3332 } 3333 3334 @Override resetResolvedLayoutDirection()3335 public void resetResolvedLayoutDirection() { 3336 super.resetResolvedLayoutDirection(); 3337 resetResolvedLayoutDirectionCount++; 3338 } 3339 3340 @Override resetResolvedTextDirection()3341 public void resetResolvedTextDirection() { 3342 super.resetResolvedTextDirection(); 3343 resetResolvedTextDirectionCount++; 3344 } 3345 3346 @Override resetResolvedTextAlignment()3347 public void resetResolvedTextAlignment() { 3348 super.resetResolvedTextAlignment(); 3349 resetResolvedTextAlignmentCount++; 3350 } 3351 3352 @Override resetResolvedPadding()3353 public void resetResolvedPadding() { 3354 super.resetResolvedPadding(); 3355 resetResolvedPaddingCount++; 3356 } 3357 3358 @Override resetResolvedDrawables()3359 protected void resetResolvedDrawables() { 3360 super.resetResolvedDrawables(); 3361 resetResolvedDrawablesCount++; 3362 } 3363 3364 @Override onDescendantInvalidated(@onNull View child, @NonNull View target)3365 public void onDescendantInvalidated(@NonNull View child, @NonNull View target) { 3366 isOnDescendantInvalidatedCalled = true; 3367 super.onDescendantInvalidated(child, target); 3368 } 3369 3370 @Override setChildrenDrawnWithCacheEnabled(boolean enabled)3371 public void setChildrenDrawnWithCacheEnabled(boolean enabled) { 3372 super.setChildrenDrawnWithCacheEnabled(enabled); 3373 } 3374 3375 @Override isChildrenDrawnWithCacheEnabled()3376 public boolean isChildrenDrawnWithCacheEnabled() { 3377 return super.isChildrenDrawnWithCacheEnabled(); 3378 } 3379 } 3380 3381 static class MockView2 extends View { 3382 MockView2(Context context)3383 public MockView2(Context context) { 3384 super(context); 3385 } 3386 MockView2(Context context, AttributeSet attrs)3387 public MockView2(Context context, AttributeSet attrs) { 3388 super(context, attrs); 3389 } 3390 MockView2(Context context, AttributeSet attrs, int defStyle)3391 public MockView2(Context context, AttributeSet attrs, int defStyle) { 3392 super(context, attrs, defStyle); 3393 } 3394 3395 @Override resetRtlProperties()3396 public void resetRtlProperties() { 3397 super.resetRtlProperties(); 3398 resetRtlPropertiesCount++; 3399 } 3400 3401 @Override resetResolvedLayoutDirection()3402 public void resetResolvedLayoutDirection() { 3403 super.resetResolvedLayoutDirection(); 3404 resetResolvedLayoutDirectionCount++; 3405 } 3406 3407 @Override resetResolvedTextDirection()3408 public void resetResolvedTextDirection() { 3409 super.resetResolvedTextDirection(); 3410 resetResolvedTextDirectionCount++; 3411 } 3412 3413 @Override resetResolvedTextAlignment()3414 public void resetResolvedTextAlignment() { 3415 super.resetResolvedTextAlignment(); 3416 resetResolvedTextAlignmentCount++; 3417 } 3418 3419 @Override resetResolvedPadding()3420 public void resetResolvedPadding() { 3421 super.resetResolvedPadding(); 3422 resetResolvedPaddingCount++; 3423 } 3424 3425 @Override resetResolvedDrawables()3426 protected void resetResolvedDrawables() { 3427 super.resetResolvedDrawables(); 3428 resetResolvedDrawablesCount++; 3429 } 3430 } 3431 3432 static final class TemporaryDetachingMockView extends View { 3433 private int mDispatchStartTemporaryDetachCount = 0; 3434 private int mDispatchFinishTemporaryDetachCount = 0; 3435 private int mOnStartTemporaryDetachCount = 0; 3436 private int mOnFinishTemporaryDetachCount = 0; 3437 TemporaryDetachingMockView(Context context)3438 public TemporaryDetachingMockView(Context context) { 3439 super(context); 3440 } 3441 3442 @Override dispatchStartTemporaryDetach()3443 public void dispatchStartTemporaryDetach() { 3444 super.dispatchStartTemporaryDetach(); 3445 mDispatchStartTemporaryDetachCount += 1; 3446 } 3447 3448 @Override dispatchFinishTemporaryDetach()3449 public void dispatchFinishTemporaryDetach() { 3450 super.dispatchFinishTemporaryDetach(); 3451 mDispatchFinishTemporaryDetachCount += 1; 3452 } 3453 3454 @Override onStartTemporaryDetach()3455 public void onStartTemporaryDetach() { 3456 super.onStartTemporaryDetach(); 3457 mOnStartTemporaryDetachCount += 1; 3458 } 3459 3460 @Override onFinishTemporaryDetach()3461 public void onFinishTemporaryDetach() { 3462 super.onFinishTemporaryDetach(); 3463 mOnFinishTemporaryDetachCount += 1; 3464 } 3465 getDispatchStartTemporaryDetachCount()3466 public int getDispatchStartTemporaryDetachCount() { 3467 return mDispatchStartTemporaryDetachCount; 3468 } 3469 getDispatchFinishTemporaryDetachCount()3470 public int getDispatchFinishTemporaryDetachCount() { 3471 return mDispatchFinishTemporaryDetachCount; 3472 } 3473 getOnStartTemporaryDetachCount()3474 public int getOnStartTemporaryDetachCount() { 3475 return mOnStartTemporaryDetachCount; 3476 } 3477 getOnFinishTemporaryDetachCount()3478 public int getOnFinishTemporaryDetachCount() { 3479 return mOnFinishTemporaryDetachCount; 3480 } 3481 } 3482 3483 public static class ScrollTestView extends ViewGroup { ScrollTestView(Context context)3484 public ScrollTestView(Context context) { 3485 super(context); 3486 } 3487 3488 @Override onLayout(boolean changed, int l, int t, int r, int b)3489 protected void onLayout(boolean changed, int l, int t, int r, int b) { 3490 3491 } 3492 3493 @Override awakenScrollBars()3494 public boolean awakenScrollBars() { 3495 return super.awakenScrollBars(); 3496 } 3497 3498 @Override computeHorizontalScrollRange()3499 public int computeHorizontalScrollRange() { 3500 return super.computeHorizontalScrollRange(); 3501 } 3502 3503 @Override computeHorizontalScrollExtent()3504 public int computeHorizontalScrollExtent() { 3505 return super.computeHorizontalScrollExtent(); 3506 } 3507 3508 @Override computeVerticalScrollRange()3509 public int computeVerticalScrollRange() { 3510 return super.computeVerticalScrollRange(); 3511 } 3512 3513 @Override computeVerticalScrollExtent()3514 public int computeVerticalScrollExtent() { 3515 return super.computeVerticalScrollExtent(); 3516 } 3517 3518 @Override getHorizontalScrollbarHeight()3519 protected int getHorizontalScrollbarHeight() { 3520 return super.getHorizontalScrollbarHeight(); 3521 } 3522 } 3523 3524 @Override setResult(int resultCode)3525 public void setResult(int resultCode) { 3526 synchronized (mSync) { 3527 mSync.mHasNotify = true; 3528 mSync.notify(); 3529 mResultCode = resultCode; 3530 } 3531 } 3532 } 3533