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