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