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_SET_FRAME_RATE_READ_ONLY; 20 import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertNotEquals; 25 import static org.junit.Assert.assertNotNull; 26 import static org.junit.Assert.assertNotSame; 27 import static org.junit.Assert.assertNull; 28 import static org.junit.Assert.assertSame; 29 import static org.junit.Assert.assertTrue; 30 import static org.junit.Assert.fail; 31 import static org.mockito.Matchers.anyInt; 32 import static org.mockito.Matchers.eq; 33 import static org.mockito.Mockito.any; 34 import static org.mockito.Mockito.doAnswer; 35 import static org.mockito.Mockito.doReturn; 36 import static org.mockito.Mockito.mock; 37 import static org.mockito.Mockito.never; 38 import static org.mockito.Mockito.reset; 39 import static org.mockito.Mockito.spy; 40 import static org.mockito.Mockito.times; 41 import static org.mockito.Mockito.verify; 42 import static org.mockito.Mockito.verifyZeroInteractions; 43 import static org.mockito.Mockito.when; 44 45 import android.Manifest; 46 import android.app.Instrumentation; 47 import android.content.ClipData; 48 import android.content.Context; 49 import android.content.res.ColorStateList; 50 import android.content.res.Resources; 51 import android.content.res.XmlResourceParser; 52 import android.graphics.Bitmap; 53 import android.graphics.BitmapFactory; 54 import android.graphics.Canvas; 55 import android.graphics.Color; 56 import android.graphics.ColorFilter; 57 import android.graphics.Insets; 58 import android.graphics.Matrix; 59 import android.graphics.Point; 60 import android.graphics.PorterDuff; 61 import android.graphics.Rect; 62 import android.graphics.drawable.BitmapDrawable; 63 import android.graphics.drawable.ColorDrawable; 64 import android.graphics.drawable.Drawable; 65 import android.graphics.drawable.StateListDrawable; 66 import android.os.Bundle; 67 import android.os.Parcelable; 68 import android.os.SystemClock; 69 import android.os.Vibrator; 70 import android.platform.test.annotations.AppModeSdkSandbox; 71 import android.platform.test.annotations.RequiresFlagsDisabled; 72 import android.platform.test.annotations.RequiresFlagsEnabled; 73 import android.platform.test.flag.junit.CheckFlagsRule; 74 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 75 import android.text.format.DateUtils; 76 import android.util.AttributeSet; 77 import android.util.Log; 78 import android.util.Pair; 79 import android.util.SparseArray; 80 import android.util.Xml; 81 import android.view.ActionMode; 82 import android.view.ContextMenu; 83 import android.view.Display; 84 import android.view.HapticFeedbackConstants; 85 import android.view.InputDevice; 86 import android.view.KeyEvent; 87 import android.view.LayoutInflater; 88 import android.view.Menu; 89 import android.view.MenuInflater; 90 import android.view.MotionEvent; 91 import android.view.PointerIcon; 92 import android.view.SoundEffectConstants; 93 import android.view.TouchDelegate; 94 import android.view.View; 95 import android.view.View.BaseSavedState; 96 import android.view.View.OnLongClickListener; 97 import android.view.View.OnUnhandledKeyEventListener; 98 import android.view.ViewConfiguration; 99 import android.view.ViewGroup; 100 import android.view.ViewParent; 101 import android.view.ViewTreeObserver; 102 import android.view.WindowInsets; 103 import android.view.WindowManager; 104 import android.view.WindowMetrics; 105 import android.view.accessibility.AccessibilityEvent; 106 import android.view.animation.AlphaAnimation; 107 import android.view.animation.Animation; 108 import android.view.cts.util.EventUtils; 109 import android.view.cts.util.ScrollBarUtils; 110 import android.view.inputmethod.EditorInfo; 111 import android.view.inputmethod.InputConnection; 112 import android.view.inputmethod.InputMethodManager; 113 import android.widget.Button; 114 import android.widget.EditText; 115 import android.widget.LinearLayout; 116 import android.widget.TextView; 117 118 import androidx.test.InstrumentationRegistry; 119 import androidx.test.annotation.UiThreadTest; 120 import androidx.test.ext.junit.runners.AndroidJUnit4; 121 import androidx.test.filters.MediumTest; 122 import androidx.test.rule.ActivityTestRule; 123 124 import com.android.compatibility.common.util.AdoptShellPermissionsRule; 125 import com.android.compatibility.common.util.CtsMouseUtil; 126 import com.android.compatibility.common.util.CtsTouchUtils; 127 import com.android.compatibility.common.util.PollingCheck; 128 import com.android.compatibility.common.util.WindowUtil; 129 130 import org.junit.Before; 131 import org.junit.Rule; 132 import org.junit.Test; 133 import org.junit.runner.RunWith; 134 import org.mockito.ArgumentCaptor; 135 136 import java.lang.reflect.Constructor; 137 import java.util.ArrayList; 138 import java.util.Arrays; 139 import java.util.Collections; 140 import java.util.HashSet; 141 import java.util.Set; 142 import java.util.concurrent.BlockingQueue; 143 import java.util.concurrent.CountDownLatch; 144 import java.util.concurrent.LinkedBlockingQueue; 145 import java.util.concurrent.TimeUnit; 146 import java.util.concurrent.atomic.AtomicBoolean; 147 148 /** 149 * Test {@link View}. 150 */ 151 @MediumTest 152 @RunWith(AndroidJUnit4.class) 153 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 154 public class ViewTest { 155 /** timeout delta when wait in case the system is sluggish */ 156 private static final long TIMEOUT_DELTA = 10000; 157 private static final long DEFAULT_TIMEOUT_MILLIS = 1000; 158 159 private static final String LOG_TAG = "ViewTest"; 160 161 private Instrumentation mInstrumentation; 162 private CtsTouchUtils mCtsTouchUtils; 163 private ViewTestCtsActivity mActivity; 164 private Resources mResources; 165 private MockViewParent mMockParent; 166 private Context mContext; 167 168 @Rule(order = 0) 169 public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( 170 androidx.test.platform.app.InstrumentationRegistry 171 .getInstrumentation().getUiAutomation(), 172 Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX); 173 174 @Rule(order = 1) 175 public ActivityTestRule<ViewTestCtsActivity> mActivityRule = 176 new ActivityTestRule<>(ViewTestCtsActivity.class); 177 178 @Rule(order = 1) 179 public ActivityTestRule<CtsActivity> mCtsActivityRule = 180 new ActivityTestRule<>(CtsActivity.class, false, false); 181 182 @Rule 183 public final CheckFlagsRule mCheckFlagsRule = 184 DeviceFlagsValueProvider.createCheckFlagsRule(); 185 186 @Before setup()187 public void setup() { 188 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 189 mContext = mInstrumentation.getTargetContext(); 190 mCtsTouchUtils = new CtsTouchUtils(mContext); 191 mActivity = mActivityRule.getActivity(); 192 WindowUtil.waitForFocus(mActivity); 193 mResources = mActivity.getResources(); 194 mMockParent = new MockViewParent(mActivity); 195 PollingCheck.waitFor(5 * DateUtils.SECOND_IN_MILLIS, mActivity::hasWindowFocus); 196 assertTrue(mActivity.hasWindowFocus()); 197 } 198 199 @Test testConstructor()200 public void testConstructor() { 201 new View(mActivity); 202 203 final XmlResourceParser parser = mResources.getLayout(R.layout.view_layout); 204 final AttributeSet attrs = Xml.asAttributeSet(parser); 205 new View(mActivity, attrs); 206 207 new View(mActivity, null); 208 209 new View(mActivity, attrs, 0); 210 211 new View(mActivity, null, 1); 212 } 213 214 @Test(expected=NullPointerException.class) testConstructorNullContext1()215 public void testConstructorNullContext1() { 216 final XmlResourceParser parser = mResources.getLayout(R.layout.view_layout); 217 final AttributeSet attrs = Xml.asAttributeSet(parser); 218 new View(null, attrs); 219 } 220 221 @Test(expected=NullPointerException.class) testConstructorNullContext2()222 public void testConstructorNullContext2() { 223 new View(null, null, 1); 224 } 225 226 // Test that validates that Views can be constructed on a thread that 227 // does not have a Looper. Necessary for async inflation 228 private Pair<Class<?>, Throwable> sCtorException = null; 229 230 @Test testConstructor2()231 public void testConstructor2() throws Exception { 232 final Object[] args = new Object[] { mActivity, null }; 233 final CountDownLatch latch = new CountDownLatch(1); 234 sCtorException = null; 235 new Thread() { 236 @Override 237 public void run() { 238 final Class<?>[] ctorSignature = new Class[] { 239 Context.class, AttributeSet.class}; 240 for (Class<?> clazz : ASYNC_INFLATE_VIEWS) { 241 try { 242 Constructor<?> constructor = clazz.getConstructor(ctorSignature); 243 constructor.setAccessible(true); 244 constructor.newInstance(args); 245 } catch (Throwable t) { 246 sCtorException = new Pair<>(clazz, t); 247 break; 248 } 249 } 250 latch.countDown(); 251 } 252 }.start(); 253 latch.await(); 254 if (sCtorException != null) { 255 throw new AssertionError("Failed to inflate " 256 + sCtorException.first.getName(), sCtorException.second); 257 } 258 } 259 260 @Test testGetContext()261 public void testGetContext() { 262 View view = new View(mActivity); 263 assertSame(mActivity, view.getContext()); 264 } 265 266 @Test testGetResources()267 public void testGetResources() { 268 View view = new View(mActivity); 269 assertSame(mResources, view.getResources()); 270 } 271 272 @Test testGetAnimation()273 public void testGetAnimation() { 274 Animation animation = new AlphaAnimation(0.0f, 1.0f); 275 View view = new View(mActivity); 276 assertNull(view.getAnimation()); 277 278 view.setAnimation(animation); 279 assertSame(animation, view.getAnimation()); 280 281 view.clearAnimation(); 282 assertNull(view.getAnimation()); 283 } 284 285 @Test testSetAnimation()286 public void testSetAnimation() { 287 Animation animation = new AlphaAnimation(0.0f, 1.0f); 288 View view = new View(mActivity); 289 assertNull(view.getAnimation()); 290 291 animation.initialize(100, 100, 100, 100); 292 assertTrue(animation.isInitialized()); 293 view.setAnimation(animation); 294 assertSame(animation, view.getAnimation()); 295 assertFalse(animation.isInitialized()); 296 297 view.setAnimation(null); 298 assertNull(view.getAnimation()); 299 } 300 301 @Test testClearAnimation()302 public void testClearAnimation() { 303 Animation animation = new AlphaAnimation(0.0f, 1.0f); 304 View view = new View(mActivity); 305 306 assertNull(view.getAnimation()); 307 view.clearAnimation(); 308 assertNull(view.getAnimation()); 309 310 view.setAnimation(animation); 311 assertNotNull(view.getAnimation()); 312 view.clearAnimation(); 313 assertNull(view.getAnimation()); 314 } 315 316 @Test(expected=NullPointerException.class) testStartAnimationNull()317 public void testStartAnimationNull() { 318 View view = new View(mActivity); 319 view.startAnimation(null); 320 } 321 322 @Test testStartAnimation()323 public void testStartAnimation() { 324 Animation animation = new AlphaAnimation(0.0f, 1.0f); 325 View view = new View(mActivity); 326 327 animation.setStartTime(1L); 328 assertEquals(1L, animation.getStartTime()); 329 view.startAnimation(animation); 330 assertEquals(Animation.START_ON_FIRST_FRAME, animation.getStartTime()); 331 } 332 333 @Test testOnAnimation()334 public void testOnAnimation() throws Throwable { 335 final Animation animation = new AlphaAnimation(0.0f, 1.0f); 336 long duration = 2000L; 337 animation.setDuration(duration); 338 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 339 340 // check whether it has started 341 mActivityRule.runOnUiThread(() -> view.startAnimation(animation)); 342 mInstrumentation.waitForIdleSync(); 343 344 PollingCheck.waitFor(view::hasCalledOnAnimationStart); 345 346 // check whether it has ended after duration, and alpha changed during this time. 347 PollingCheck.waitFor(duration + TIMEOUT_DELTA, 348 () -> view.hasCalledOnSetAlpha() && view.hasCalledOnAnimationEnd()); 349 } 350 351 @Test testGetParent()352 public void testGetParent() { 353 MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 354 ViewGroup parent = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 355 assertSame(parent, view.getParent()); 356 } 357 358 @Test testAccessScrollIndicators()359 public void testAccessScrollIndicators() { 360 View view = mActivity.findViewById(R.id.viewlayout_root); 361 362 assertEquals(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT, 363 view.getScrollIndicators()); 364 } 365 366 @Test testSetScrollIndicators()367 public void testSetScrollIndicators() { 368 View view = new View(mActivity); 369 370 view.setScrollIndicators(0); 371 assertEquals(0, view.getScrollIndicators()); 372 373 view.setScrollIndicators(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT); 374 assertEquals(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT, 375 view.getScrollIndicators()); 376 377 view.setScrollIndicators(View.SCROLL_INDICATOR_TOP, View.SCROLL_INDICATOR_TOP); 378 assertEquals(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT 379 | View.SCROLL_INDICATOR_TOP, view.getScrollIndicators()); 380 381 view.setScrollIndicators(0, view.getScrollIndicators()); 382 assertEquals(0, view.getScrollIndicators()); 383 } 384 385 @Test testFindViewById()386 public void testFindViewById() { 387 // verify view can find self 388 View parent = mActivity.findViewById(R.id.viewlayout_root); 389 assertSame(parent, parent.findViewById(R.id.viewlayout_root)); 390 391 // find expected view type 392 View view = parent.findViewById(R.id.mock_view); 393 assertTrue(view instanceof MockView); 394 } 395 396 @Test testRequireViewById()397 public void testRequireViewById() { 398 View parent = mActivity.findViewById(R.id.viewlayout_root); 399 400 View requiredView = parent.requireViewById(R.id.mock_view); 401 View foundView = parent.findViewById(R.id.mock_view); 402 assertSame(foundView, requiredView); 403 assertTrue(requiredView instanceof MockView); 404 } 405 406 @Test(expected = IllegalArgumentException.class) testRequireViewByIdNoId()407 public void testRequireViewByIdNoId() { 408 View parent = mActivity.findViewById(R.id.viewlayout_root); 409 parent.requireViewById(View.NO_ID); 410 } 411 412 413 @Test(expected = IllegalArgumentException.class) testRequireViewByIdInvalid()414 public void testRequireViewByIdInvalid() { 415 View parent = mActivity.findViewById(R.id.viewlayout_root); 416 parent.requireViewById(0); 417 } 418 419 @Test(expected = IllegalArgumentException.class) testRequireViewByIdNotFound()420 public void testRequireViewByIdNotFound() { 421 View parent = mActivity.findViewById(R.id.viewlayout_root); 422 parent.requireViewById(R.id.view); // id not present in view_layout 423 } 424 425 @Test testAccessTouchDelegate()426 public void testAccessTouchDelegate() throws Throwable { 427 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 428 Rect rect = new Rect(); 429 final Button button = new Button(mActivity); 430 final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT; 431 final int btnHeight = view.getHeight()/3; 432 mActivityRule.runOnUiThread(() -> mActivity.addContentView(button, 433 new LinearLayout.LayoutParams(WRAP_CONTENT, btnHeight))); 434 mInstrumentation.waitForIdleSync(); 435 button.getHitRect(rect); 436 TouchDelegate delegate = spy(new TouchDelegate(rect, button)); 437 438 assertNull(view.getTouchDelegate()); 439 440 view.setTouchDelegate(delegate); 441 assertSame(delegate, view.getTouchDelegate()); 442 verify(delegate, never()).onTouchEvent(any()); 443 mCtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, view); 444 assertTrue(view.hasCalledOnTouchEvent()); 445 verify(delegate, times(1)).onTouchEvent(any()); 446 CtsMouseUtil.emulateHoverOnView(mInstrumentation, view, view.getWidth() / 2, 447 view.getHeight() / 2); 448 assertTrue(view.hasCalledOnHoverEvent()); 449 verifyZeroInteractions(delegate); 450 451 view.setTouchDelegate(null); 452 assertNull(view.getTouchDelegate()); 453 } 454 455 @Test onHoverEvent_verticalCanScroll_awakenScrollBarsCalled()456 public void onHoverEvent_verticalCanScroll_awakenScrollBarsCalled() { 457 onHoverEvent_awakensScrollBars(true, true, true); 458 } 459 460 @Test onHoverEvent_verticalCantScroll_awakenScrollBarsNotCalled()461 public void onHoverEvent_verticalCantScroll_awakenScrollBarsNotCalled() { 462 onHoverEvent_awakensScrollBars(true, false, false); 463 } 464 465 @Test onHoverEvent_horizontalCanScroll_awakenScrollBarsCalled()466 public void onHoverEvent_horizontalCanScroll_awakenScrollBarsCalled() { 467 onHoverEvent_awakensScrollBars(false, true, true); 468 } 469 470 @Test onHoverEvent_horizontalCantScroll_awakenScrollBarsNotCalled()471 public void onHoverEvent_horizontalCantScroll_awakenScrollBarsNotCalled() { 472 onHoverEvent_awakensScrollBars(false, false, false); 473 } 474 onHoverEvent_awakensScrollBars(boolean vertical, boolean canScroll, boolean awakenScrollBarsCalled)475 private void onHoverEvent_awakensScrollBars(boolean vertical, boolean canScroll, 476 boolean awakenScrollBarsCalled) { 477 478 // Arrange 479 480 final ScrollTestView view = spy(new ScrollTestView(mContext)); 481 view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT); 482 view.setHorizontalScrollBarEnabled(true); 483 view.setVerticalScrollBarEnabled(true); 484 view.setScrollBarSize(10); 485 view.layout(0, 0, 100, 100); 486 487 when(view.computeVerticalScrollExtent()).thenReturn(100); 488 when(view.computeVerticalScrollRange()).thenReturn(canScroll ? 101 : 100); 489 when(view.computeHorizontalScrollExtent()).thenReturn(100); 490 when(view.computeHorizontalScrollRange()).thenReturn(canScroll ? 101 : 100); 491 492 int x = vertical ? 95 : 50; 493 int y = vertical ? 50 : 95; 494 495 MotionEvent event = EventUtils.generateMouseEvent(x, y, MotionEvent.ACTION_HOVER_ENTER, 0); 496 497 // Act 498 499 view.onHoverEvent(event); 500 event.recycle(); 501 502 // Assert 503 504 if (awakenScrollBarsCalled) { 505 verify(view).awakenScrollBars(); 506 } else { 507 verify(view, never()).awakenScrollBars(); 508 } 509 } 510 511 @Test testMouseEventCallsGetPointerIcon()512 public void testMouseEventCallsGetPointerIcon() { 513 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 514 515 final int[] xy = new int[2]; 516 view.getLocationOnScreen(xy); 517 int x = xy[0] + view.getWidth() / 2; 518 int y = xy[1] + view.getHeight() / 2; 519 520 final MotionEvent event = 521 EventUtils.generateMouseEvent(x, y, MotionEvent.ACTION_HOVER_MOVE, 0); 522 event.setDisplayId(mActivity.getDisplayId()); 523 mInstrumentation.sendPointerSync(event); 524 mInstrumentation.waitForIdleSync(); 525 526 assertTrue(view.hasCalledOnResolvePointerIcon()); 527 528 final MockView view2 = (MockView) mActivity.findViewById(R.id.scroll_view); 529 assertFalse(view2.hasCalledOnResolvePointerIcon()); 530 } 531 532 @Test testAccessPointerIcon()533 public void testAccessPointerIcon() { 534 View view = mActivity.findViewById(R.id.pointer_icon_layout); 535 final MotionEvent event = 536 EventUtils.generateMouseEvent(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0); 537 538 // First view has pointerIcon="help" 539 assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP), 540 view.onResolvePointerIcon(event, 0)); 541 542 // Second view inherits pointerIcon="crosshair" from the parent 543 event.setLocation(0, 21); 544 assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_CROSSHAIR), 545 view.onResolvePointerIcon(event, 0)); 546 547 // Third view has custom pointer icon defined in a resource. 548 event.setLocation(0, 41); 549 assertNotNull(view.onResolvePointerIcon(event, 0)); 550 551 // Parent view has pointerIcon="crosshair" 552 event.setLocation(0, 61); 553 assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_CROSSHAIR), 554 view.onResolvePointerIcon(event, 0)); 555 556 // Outside of the parent view, no pointer icon defined. 557 event.setLocation(0, 71); 558 assertNull(view.onResolvePointerIcon(event, 0)); 559 560 view.setPointerIcon(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT)); 561 assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT), 562 view.onResolvePointerIcon(event, 0)); 563 event.recycle(); 564 } 565 566 @Test testPointerIconOverlap()567 public void testPointerIconOverlap() throws Throwable { 568 View parent = mActivity.findViewById(R.id.pointer_icon_overlap); 569 View child1 = mActivity.findViewById(R.id.pointer_icon_overlap_child1); 570 View child2 = mActivity.findViewById(R.id.pointer_icon_overlap_child2); 571 View child3 = mActivity.findViewById(R.id.pointer_icon_overlap_child3); 572 573 PointerIcon iconParent = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HAND); 574 PointerIcon iconChild1 = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP); 575 PointerIcon iconChild2 = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT); 576 PointerIcon iconChild3 = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_GRAB); 577 578 parent.setPointerIcon(iconParent); 579 child1.setPointerIcon(iconChild1); 580 child2.setPointerIcon(iconChild2); 581 child3.setPointerIcon(iconChild3); 582 583 final MotionEvent event = 584 EventUtils.generateMouseEvent(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0); 585 586 assertEquals(iconChild3, parent.onResolvePointerIcon(event, 0)); 587 588 setVisibilityOnUiThread(child3, View.GONE); 589 assertEquals(iconChild2, parent.onResolvePointerIcon(event, 0)); 590 591 child2.setPointerIcon(null); 592 assertEquals(iconChild1, parent.onResolvePointerIcon(event, 0)); 593 594 setVisibilityOnUiThread(child1, View.GONE); 595 assertEquals(iconParent, parent.onResolvePointerIcon(event, 0)); 596 597 event.recycle(); 598 } 599 600 @Test onResolvePointerIcon_verticalCanScroll_pointerIsArrow()601 public void onResolvePointerIcon_verticalCanScroll_pointerIsArrow() { 602 onResolvePointerIcon_scrollabilityAffectsPointerIcon(true, true, true); 603 } 604 605 @Test onResolvePointerIcon_verticalCantScroll_pointerIsProperty()606 public void onResolvePointerIcon_verticalCantScroll_pointerIsProperty() { 607 onResolvePointerIcon_scrollabilityAffectsPointerIcon(true, false, false); 608 } 609 610 @Test onResolvePointerIcon_horizontalCanScroll_pointerIsArrow()611 public void onResolvePointerIcon_horizontalCanScroll_pointerIsArrow() { 612 onResolvePointerIcon_scrollabilityAffectsPointerIcon(false, true, true); 613 } 614 615 @Test onResolvePointerIcon_horizontalCantScroll_pointerIsProperty()616 public void onResolvePointerIcon_horizontalCantScroll_pointerIsProperty() { 617 onResolvePointerIcon_scrollabilityAffectsPointerIcon(false, false, false); 618 } 619 onResolvePointerIcon_scrollabilityAffectsPointerIcon(boolean vertical, boolean canScroll, boolean pointerIsDefaultIcon)620 private void onResolvePointerIcon_scrollabilityAffectsPointerIcon(boolean vertical, 621 boolean canScroll, boolean pointerIsDefaultIcon) { 622 623 // Arrange 624 625 final int range = canScroll ? 101 : 100; 626 final int thumbLength = ScrollBarUtils.getThumbLength(1, 10, 100, range); 627 628 final PointerIcon expectedPointerIcon = PointerIcon.getSystemIcon(mContext, 629 PointerIcon.TYPE_HAND); 630 631 final ScrollTestView view = spy(new ScrollTestView(mContext)); 632 view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT); 633 view.setHorizontalScrollBarEnabled(true); 634 view.setVerticalScrollBarEnabled(true); 635 view.setScrollBarSize(10); 636 view.setPointerIcon(expectedPointerIcon); 637 view.layout(0, 0, 100, 100); 638 639 when(view.computeVerticalScrollExtent()).thenReturn(100); 640 when(view.computeVerticalScrollRange()).thenReturn(range); 641 when(view.computeHorizontalScrollExtent()).thenReturn(100); 642 when(view.computeHorizontalScrollRange()).thenReturn(range); 643 644 final int touchX = vertical ? 95 : thumbLength / 2; 645 final int touchY = vertical ? thumbLength / 2 : 95; 646 final MotionEvent event = 647 EventUtils.generateMouseEvent(touchX, touchY, MotionEvent.ACTION_HOVER_ENTER, 0); 648 649 // Act 650 651 final PointerIcon actualResult = view.onResolvePointerIcon(event, 0); 652 event.recycle(); 653 654 // Assert 655 656 if (pointerIsDefaultIcon) { 657 // onResolvePointerIcon should return null to show the default pointer icon. 658 assertNull(actualResult); 659 } else { 660 assertEquals(expectedPointerIcon, actualResult); 661 } 662 } 663 664 @Test testCreatePointerIcons()665 public void testCreatePointerIcons() { 666 assertSystemPointerIcon(PointerIcon.TYPE_NULL); 667 assertSystemPointerIcon(PointerIcon.TYPE_DEFAULT); 668 assertSystemPointerIcon(PointerIcon.TYPE_ARROW); 669 assertSystemPointerIcon(PointerIcon.TYPE_CONTEXT_MENU); 670 assertSystemPointerIcon(PointerIcon.TYPE_HAND); 671 assertSystemPointerIcon(PointerIcon.TYPE_HELP); 672 assertSystemPointerIcon(PointerIcon.TYPE_WAIT); 673 assertSystemPointerIcon(PointerIcon.TYPE_CELL); 674 assertSystemPointerIcon(PointerIcon.TYPE_CROSSHAIR); 675 assertSystemPointerIcon(PointerIcon.TYPE_TEXT); 676 assertSystemPointerIcon(PointerIcon.TYPE_VERTICAL_TEXT); 677 assertSystemPointerIcon(PointerIcon.TYPE_ALIAS); 678 assertSystemPointerIcon(PointerIcon.TYPE_COPY); 679 assertSystemPointerIcon(PointerIcon.TYPE_NO_DROP); 680 assertSystemPointerIcon(PointerIcon.TYPE_ALL_SCROLL); 681 assertSystemPointerIcon(PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW); 682 assertSystemPointerIcon(PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW); 683 assertSystemPointerIcon(PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW); 684 assertSystemPointerIcon(PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW); 685 assertSystemPointerIcon(PointerIcon.TYPE_ZOOM_IN); 686 assertSystemPointerIcon(PointerIcon.TYPE_ZOOM_OUT); 687 assertSystemPointerIcon(PointerIcon.TYPE_GRAB); 688 689 assertNotNull(PointerIcon.load(mResources, R.drawable.custom_pointer_icon)); 690 691 Bitmap bitmap = BitmapFactory.decodeResource(mResources, R.drawable.icon_blue); 692 assertNotNull(PointerIcon.create(bitmap, 0, 0)); 693 assertNotNull(PointerIcon.create(bitmap, bitmap.getWidth() / 2, bitmap.getHeight() / 2)); 694 695 try { 696 PointerIcon.create(bitmap, -1, 0); 697 fail("Hotspot x can not be < 0"); 698 } catch (IllegalArgumentException ignore) { 699 } 700 701 try { 702 PointerIcon.create(bitmap, 0, -1); 703 fail("Hotspot y can not be < 0"); 704 } catch (IllegalArgumentException ignore) { 705 } 706 707 try { 708 PointerIcon.create(bitmap, bitmap.getWidth(), 0); 709 fail("Hotspot x cannot be >= width"); 710 } catch (IllegalArgumentException ignore) { 711 } 712 713 try { 714 PointerIcon.create(bitmap, 0, bitmap.getHeight()); 715 fail("Hotspot x cannot be >= height"); 716 } catch (IllegalArgumentException e) { 717 } 718 } 719 assertSystemPointerIcon(int style)720 private void assertSystemPointerIcon(int style) { 721 assertNotNull(PointerIcon.getSystemIcon(mActivity, style)); 722 } 723 724 @UiThreadTest 725 @Test testAccessTag()726 public void testAccessTag() { 727 ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 728 MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view); 729 MockView scrollView = (MockView) mActivity.findViewById(R.id.scroll_view); 730 731 ViewData viewData = new ViewData(); 732 viewData.childCount = 3; 733 viewData.tag = "linearLayout"; 734 viewData.firstChild = mockView; 735 viewGroup.setTag(viewData); 736 viewGroup.setFocusable(true); 737 assertSame(viewData, viewGroup.getTag()); 738 739 final String tag = "mock"; 740 assertNull(mockView.getTag()); 741 mockView.setTag(tag); 742 assertEquals(tag, mockView.getTag()); 743 744 scrollView.setTag(viewGroup); 745 assertSame(viewGroup, scrollView.getTag()); 746 747 assertSame(viewGroup, viewGroup.findViewWithTag(viewData)); 748 assertSame(mockView, viewGroup.findViewWithTag(tag)); 749 assertSame(scrollView, viewGroup.findViewWithTag(viewGroup)); 750 751 mockView.setTag(null); 752 assertNull(mockView.getTag()); 753 } 754 755 @Test testOnSizeChanged()756 public void testOnSizeChanged() throws Throwable { 757 final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 758 final MockView mockView = new MockView(mActivity); 759 assertEquals(-1, mockView.getOldWOnSizeChanged()); 760 assertEquals(-1, mockView.getOldHOnSizeChanged()); 761 mActivityRule.runOnUiThread(() -> viewGroup.addView(mockView)); 762 mInstrumentation.waitForIdleSync(); 763 assertTrue(mockView.hasCalledOnSizeChanged()); 764 assertEquals(0, mockView.getOldWOnSizeChanged()); 765 assertEquals(0, mockView.getOldHOnSizeChanged()); 766 767 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 768 assertTrue(view.hasCalledOnSizeChanged()); 769 view.reset(); 770 assertEquals(-1, view.getOldWOnSizeChanged()); 771 assertEquals(-1, view.getOldHOnSizeChanged()); 772 int oldw = view.getWidth(); 773 int oldh = view.getHeight(); 774 final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(200, 100); 775 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams)); 776 mInstrumentation.waitForIdleSync(); 777 assertTrue(view.hasCalledOnSizeChanged()); 778 assertEquals(oldw, view.getOldWOnSizeChanged()); 779 assertEquals(oldh, view.getOldHOnSizeChanged()); 780 } 781 782 783 @Test(expected=NullPointerException.class) testGetHitRectNull()784 public void testGetHitRectNull() { 785 MockView view = new MockView(mActivity); 786 view.getHitRect(null); 787 } 788 789 @Test testGetHitRect()790 public void testGetHitRect() { 791 Rect outRect = new Rect(); 792 View mockView = mActivity.findViewById(R.id.mock_view); 793 mockView.getHitRect(outRect); 794 assertEquals(0, outRect.left); 795 assertEquals(0, outRect.top); 796 assertEquals(mockView.getWidth(), outRect.right); 797 assertEquals(mockView.getHeight(), outRect.bottom); 798 } 799 800 @Test testForceLayout()801 public void testForceLayout() { 802 View view = new View(mActivity); 803 804 assertFalse(view.isLayoutRequested()); 805 view.forceLayout(); 806 assertTrue(view.isLayoutRequested()); 807 808 view.forceLayout(); 809 assertTrue(view.isLayoutRequested()); 810 } 811 812 @Test testIsLayoutRequested()813 public void testIsLayoutRequested() { 814 View view = new View(mActivity); 815 816 assertFalse(view.isLayoutRequested()); 817 view.forceLayout(); 818 assertTrue(view.isLayoutRequested()); 819 820 view.layout(0, 0, 0, 0); 821 assertFalse(view.isLayoutRequested()); 822 } 823 824 @Test testRequestLayout()825 public void testRequestLayout() { 826 MockView view = new MockView(mActivity); 827 assertFalse(view.isLayoutRequested()); 828 assertNull(view.getParent()); 829 830 view.requestLayout(); 831 assertTrue(view.isLayoutRequested()); 832 833 view.setParent(mMockParent); 834 assertTrue(mMockParent.hasRequestLayout()); 835 836 mMockParent.reset(); 837 view.requestLayout(); 838 assertTrue(view.isLayoutRequested()); 839 assertTrue(mMockParent.hasRequestLayout()); 840 } 841 842 @Test testLayout()843 public void testLayout() throws Throwable { 844 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 845 assertTrue(view.hasCalledOnLayout()); 846 847 view.reset(); 848 assertFalse(view.hasCalledOnLayout()); 849 mActivityRule.runOnUiThread(view::requestLayout); 850 mInstrumentation.waitForIdleSync(); 851 assertTrue(view.hasCalledOnLayout()); 852 } 853 854 @Test testGetBaseline()855 public void testGetBaseline() { 856 View view = new View(mActivity); 857 858 assertEquals(-1, view.getBaseline()); 859 } 860 861 @Test testAccessBackground()862 public void testAccessBackground() { 863 View view = new View(mActivity); 864 Drawable d1 = mResources.getDrawable(R.drawable.scenery); 865 Drawable d2 = mResources.getDrawable(R.drawable.pass); 866 867 assertNull(view.getBackground()); 868 869 view.setBackgroundDrawable(d1); 870 assertEquals(d1, view.getBackground()); 871 872 view.setBackgroundDrawable(d2); 873 assertEquals(d2, view.getBackground()); 874 875 view.setBackgroundDrawable(null); 876 assertNull(view.getBackground()); 877 } 878 879 @Test testSetBackgroundResource()880 public void testSetBackgroundResource() { 881 View view = new View(mActivity); 882 883 assertNull(view.getBackground()); 884 885 view.setBackgroundResource(R.drawable.pass); 886 assertNotNull(view.getBackground()); 887 888 view.setBackgroundResource(0); 889 assertNull(view.getBackground()); 890 } 891 892 @Test testAccessDrawingCacheBackgroundColor()893 public void testAccessDrawingCacheBackgroundColor() { 894 View view = new View(mActivity); 895 896 assertEquals(0, view.getDrawingCacheBackgroundColor()); 897 898 view.setDrawingCacheBackgroundColor(0xFF00FF00); 899 assertEquals(0xFF00FF00, view.getDrawingCacheBackgroundColor()); 900 901 view.setDrawingCacheBackgroundColor(-1); 902 assertEquals(-1, view.getDrawingCacheBackgroundColor()); 903 } 904 905 @Test testSetBackgroundColor()906 public void testSetBackgroundColor() { 907 View view = new View(mActivity); 908 ColorDrawable colorDrawable; 909 assertNull(view.getBackground()); 910 911 view.setBackgroundColor(0xFFFF0000); 912 colorDrawable = (ColorDrawable) view.getBackground(); 913 assertNotNull(colorDrawable); 914 assertEquals(0xFF, colorDrawable.getAlpha()); 915 916 view.setBackgroundColor(0); 917 colorDrawable = (ColorDrawable) view.getBackground(); 918 assertNotNull(colorDrawable); 919 assertEquals(0, colorDrawable.getAlpha()); 920 } 921 922 @Test testVerifyDrawable()923 public void testVerifyDrawable() { 924 MockView view = new MockView(mActivity); 925 Drawable d1 = mResources.getDrawable(R.drawable.scenery); 926 Drawable d2 = mResources.getDrawable(R.drawable.pass); 927 928 assertNull(view.getBackground()); 929 assertTrue(view.verifyDrawable(null)); 930 assertFalse(view.verifyDrawable(d1)); 931 932 view.setBackgroundDrawable(d1); 933 assertTrue(view.verifyDrawable(d1)); 934 assertFalse(view.verifyDrawable(d2)); 935 } 936 937 @Test testGetDrawingRect()938 public void testGetDrawingRect() { 939 MockView view = new MockView(mActivity); 940 Rect outRect = new Rect(); 941 942 view.getDrawingRect(outRect); 943 assertEquals(0, outRect.left); 944 assertEquals(0, outRect.top); 945 assertEquals(0, outRect.right); 946 assertEquals(0, outRect.bottom); 947 948 view.scrollTo(10, 100); 949 view.getDrawingRect(outRect); 950 assertEquals(10, outRect.left); 951 assertEquals(100, outRect.top); 952 assertEquals(10, outRect.right); 953 assertEquals(100, outRect.bottom); 954 955 View mockView = mActivity.findViewById(R.id.mock_view); 956 mockView.getDrawingRect(outRect); 957 assertEquals(0, outRect.left); 958 assertEquals(0, outRect.top); 959 assertEquals(mockView.getWidth(), outRect.right); 960 assertEquals(mockView.getHeight(), outRect.bottom); 961 } 962 963 @Test testGetFocusedRect()964 public void testGetFocusedRect() { 965 MockView view = new MockView(mActivity); 966 Rect outRect = new Rect(); 967 968 view.getFocusedRect(outRect); 969 assertEquals(0, outRect.left); 970 assertEquals(0, outRect.top); 971 assertEquals(0, outRect.right); 972 assertEquals(0, outRect.bottom); 973 974 view.scrollTo(10, 100); 975 view.getFocusedRect(outRect); 976 assertEquals(10, outRect.left); 977 assertEquals(100, outRect.top); 978 assertEquals(10, outRect.right); 979 assertEquals(100, outRect.bottom); 980 } 981 982 @Test testGetGlobalVisibleRectPoint()983 public void testGetGlobalVisibleRectPoint() throws Throwable { 984 final View view = mActivity.findViewById(R.id.mock_view); 985 final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 986 Rect rect = new Rect(); 987 Point point = new Point(); 988 989 assertTrue(view.getGlobalVisibleRect(rect, point)); 990 Rect rcParent = new Rect(); 991 Point ptParent = new Point(); 992 viewGroup.getGlobalVisibleRect(rcParent, ptParent); 993 assertEquals(rcParent.left, rect.left); 994 assertEquals(rcParent.top, rect.top); 995 assertEquals(rect.left + view.getWidth(), rect.right); 996 assertEquals(rect.top + view.getHeight(), rect.bottom); 997 assertEquals(ptParent.x, point.x); 998 assertEquals(ptParent.y, point.y); 999 1000 // width is 0 1001 final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300); 1002 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams1)); 1003 mInstrumentation.waitForIdleSync(); 1004 assertFalse(view.getGlobalVisibleRect(rect, point)); 1005 1006 // height is -10 1007 final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10); 1008 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams2)); 1009 mInstrumentation.waitForIdleSync(); 1010 assertFalse(view.getGlobalVisibleRect(rect, point)); 1011 1012 Display display = mActivity.getWindowManager().getDefaultDisplay(); 1013 int halfWidth = display.getWidth() / 2; 1014 int halfHeight = display.getHeight() /2; 1015 1016 final LinearLayout.LayoutParams layoutParams3 = 1017 new LinearLayout.LayoutParams(halfWidth, halfHeight); 1018 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams3)); 1019 mInstrumentation.waitForIdleSync(); 1020 assertTrue(view.getGlobalVisibleRect(rect, point)); 1021 assertEquals(rcParent.left, rect.left); 1022 assertEquals(rcParent.top, rect.top); 1023 assertEquals(rect.left + halfWidth, rect.right); 1024 assertEquals(rect.top + halfHeight, rect.bottom); 1025 assertEquals(ptParent.x, point.x); 1026 assertEquals(ptParent.y, point.y); 1027 } 1028 1029 @Test testGetGlobalVisibleRect()1030 public void testGetGlobalVisibleRect() throws Throwable { 1031 final View view = mActivity.findViewById(R.id.mock_view); 1032 final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 1033 Rect rect = new Rect(); 1034 1035 assertTrue(view.getGlobalVisibleRect(rect)); 1036 Rect rcParent = new Rect(); 1037 viewGroup.getGlobalVisibleRect(rcParent); 1038 assertEquals(rcParent.left, rect.left); 1039 assertEquals(rcParent.top, rect.top); 1040 assertEquals(rect.left + view.getWidth(), rect.right); 1041 assertEquals(rect.top + view.getHeight(), rect.bottom); 1042 1043 // width is 0 1044 final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300); 1045 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams1)); 1046 mInstrumentation.waitForIdleSync(); 1047 assertFalse(view.getGlobalVisibleRect(rect)); 1048 1049 // height is -10 1050 final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10); 1051 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams2)); 1052 mInstrumentation.waitForIdleSync(); 1053 assertFalse(view.getGlobalVisibleRect(rect)); 1054 1055 Display display = mActivity.getWindowManager().getDefaultDisplay(); 1056 int halfWidth = display.getWidth() / 2; 1057 int halfHeight = display.getHeight() /2; 1058 1059 final LinearLayout.LayoutParams layoutParams3 = 1060 new LinearLayout.LayoutParams(halfWidth, halfHeight); 1061 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams3)); 1062 mInstrumentation.waitForIdleSync(); 1063 assertTrue(view.getGlobalVisibleRect(rect)); 1064 assertEquals(rcParent.left, rect.left); 1065 assertEquals(rcParent.top, rect.top); 1066 assertEquals(rect.left + halfWidth, rect.right); 1067 assertEquals(rect.top + halfHeight, rect.bottom); 1068 } 1069 1070 @Test testComputeHorizontalScroll()1071 public void testComputeHorizontalScroll() throws Throwable { 1072 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 1073 1074 assertEquals(0, view.computeHorizontalScrollOffset()); 1075 assertEquals(view.getWidth(), view.computeHorizontalScrollRange()); 1076 assertEquals(view.getWidth(), view.computeHorizontalScrollExtent()); 1077 1078 mActivityRule.runOnUiThread(() -> view.scrollTo(12, 0)); 1079 mInstrumentation.waitForIdleSync(); 1080 assertEquals(12, view.computeHorizontalScrollOffset()); 1081 assertEquals(view.getWidth(), view.computeHorizontalScrollRange()); 1082 assertEquals(view.getWidth(), view.computeHorizontalScrollExtent()); 1083 1084 mActivityRule.runOnUiThread(() -> view.scrollBy(12, 0)); 1085 mInstrumentation.waitForIdleSync(); 1086 assertEquals(24, view.computeHorizontalScrollOffset()); 1087 assertEquals(view.getWidth(), view.computeHorizontalScrollRange()); 1088 assertEquals(view.getWidth(), view.computeHorizontalScrollExtent()); 1089 1090 int newWidth = 200; 1091 final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(newWidth, 100); 1092 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams)); 1093 mInstrumentation.waitForIdleSync(); 1094 assertEquals(24, view.computeHorizontalScrollOffset()); 1095 assertEquals(newWidth, view.getWidth()); 1096 assertEquals(view.getWidth(), view.computeHorizontalScrollRange()); 1097 assertEquals(view.getWidth(), view.computeHorizontalScrollExtent()); 1098 } 1099 1100 @Test testComputeVerticalScroll()1101 public void testComputeVerticalScroll() throws Throwable { 1102 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 1103 1104 assertEquals(0, view.computeVerticalScrollOffset()); 1105 assertEquals(view.getHeight(), view.computeVerticalScrollRange()); 1106 assertEquals(view.getHeight(), view.computeVerticalScrollExtent()); 1107 1108 final int scrollToY = 34; 1109 mActivityRule.runOnUiThread(() -> view.scrollTo(0, scrollToY)); 1110 mInstrumentation.waitForIdleSync(); 1111 assertEquals(scrollToY, view.computeVerticalScrollOffset()); 1112 assertEquals(view.getHeight(), view.computeVerticalScrollRange()); 1113 assertEquals(view.getHeight(), view.computeVerticalScrollExtent()); 1114 1115 final int scrollByY = 200; 1116 mActivityRule.runOnUiThread(() -> view.scrollBy(0, scrollByY)); 1117 mInstrumentation.waitForIdleSync(); 1118 assertEquals(scrollToY + scrollByY, view.computeVerticalScrollOffset()); 1119 assertEquals(view.getHeight(), view.computeVerticalScrollRange()); 1120 assertEquals(view.getHeight(), view.computeVerticalScrollExtent()); 1121 1122 int newHeight = 333; 1123 final LinearLayout.LayoutParams layoutParams = 1124 new LinearLayout.LayoutParams(200, newHeight); 1125 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams)); 1126 mInstrumentation.waitForIdleSync(); 1127 assertEquals(scrollToY + scrollByY, view.computeVerticalScrollOffset()); 1128 assertEquals(newHeight, view.getHeight()); 1129 assertEquals(view.getHeight(), view.computeVerticalScrollRange()); 1130 assertEquals(view.getHeight(), view.computeVerticalScrollExtent()); 1131 } 1132 1133 @Test testGetFadingEdgeStrength()1134 public void testGetFadingEdgeStrength() throws Throwable { 1135 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 1136 1137 assertEquals(0f, view.getLeftFadingEdgeStrength(), 0.0f); 1138 assertEquals(0f, view.getRightFadingEdgeStrength(), 0.0f); 1139 assertEquals(0f, view.getTopFadingEdgeStrength(), 0.0f); 1140 assertEquals(0f, view.getBottomFadingEdgeStrength(), 0.0f); 1141 1142 mActivityRule.runOnUiThread(() -> view.scrollTo(10, 10)); 1143 mInstrumentation.waitForIdleSync(); 1144 assertEquals(1f, view.getLeftFadingEdgeStrength(), 0.0f); 1145 assertEquals(0f, view.getRightFadingEdgeStrength(), 0.0f); 1146 assertEquals(1f, view.getTopFadingEdgeStrength(), 0.0f); 1147 assertEquals(0f, view.getBottomFadingEdgeStrength(), 0.0f); 1148 1149 mActivityRule.runOnUiThread(() -> view.scrollTo(-10, -10)); 1150 mInstrumentation.waitForIdleSync(); 1151 assertEquals(0f, view.getLeftFadingEdgeStrength(), 0.0f); 1152 assertEquals(1f, view.getRightFadingEdgeStrength(), 0.0f); 1153 assertEquals(0f, view.getTopFadingEdgeStrength(), 0.0f); 1154 assertEquals(1f, view.getBottomFadingEdgeStrength(), 0.0f); 1155 } 1156 1157 @Test testGetLeftFadingEdgeStrength()1158 public void testGetLeftFadingEdgeStrength() { 1159 MockView view = new MockView(mActivity); 1160 1161 assertEquals(0.0f, view.getLeftFadingEdgeStrength(), 0.0f); 1162 1163 view.scrollTo(1, 0); 1164 assertEquals(1.0f, view.getLeftFadingEdgeStrength(), 0.0f); 1165 } 1166 1167 @Test testGetRightFadingEdgeStrength()1168 public void testGetRightFadingEdgeStrength() { 1169 MockView view = new MockView(mActivity); 1170 1171 assertEquals(0.0f, view.getRightFadingEdgeStrength(), 0.0f); 1172 1173 view.scrollTo(-1, 0); 1174 assertEquals(1.0f, view.getRightFadingEdgeStrength(), 0.0f); 1175 } 1176 1177 @Test testGetBottomFadingEdgeStrength()1178 public void testGetBottomFadingEdgeStrength() { 1179 MockView view = new MockView(mActivity); 1180 1181 assertEquals(0.0f, view.getBottomFadingEdgeStrength(), 0.0f); 1182 1183 view.scrollTo(0, -2); 1184 assertEquals(1.0f, view.getBottomFadingEdgeStrength(), 0.0f); 1185 } 1186 1187 @Test testGetTopFadingEdgeStrength()1188 public void testGetTopFadingEdgeStrength() { 1189 MockView view = new MockView(mActivity); 1190 1191 assertEquals(0.0f, view.getTopFadingEdgeStrength(), 0.0f); 1192 1193 view.scrollTo(0, 2); 1194 assertEquals(1.0f, view.getTopFadingEdgeStrength(), 0.0f); 1195 } 1196 1197 @Test testResolveSize()1198 public void testResolveSize() { 1199 assertEquals(50, View.resolveSize(50, View.MeasureSpec.UNSPECIFIED)); 1200 1201 assertEquals(40, View.resolveSize(50, 40 | View.MeasureSpec.EXACTLY)); 1202 1203 assertEquals(30, View.resolveSize(50, 30 | View.MeasureSpec.AT_MOST)); 1204 1205 assertEquals(20, View.resolveSize(20, 30 | View.MeasureSpec.AT_MOST)); 1206 } 1207 1208 @Test testGetDefaultSize()1209 public void testGetDefaultSize() { 1210 assertEquals(50, View.getDefaultSize(50, View.MeasureSpec.UNSPECIFIED)); 1211 1212 assertEquals(40, View.getDefaultSize(50, 40 | View.MeasureSpec.EXACTLY)); 1213 1214 assertEquals(30, View.getDefaultSize(50, 30 | View.MeasureSpec.AT_MOST)); 1215 1216 assertEquals(30, View.getDefaultSize(20, 30 | View.MeasureSpec.AT_MOST)); 1217 } 1218 1219 @Test testAccessId()1220 public void testAccessId() { 1221 View view = new View(mActivity); 1222 1223 assertEquals(View.NO_ID, view.getId()); 1224 1225 view.setId(10); 1226 assertEquals(10, view.getId()); 1227 1228 view.setId(0xFFFFFFFF); 1229 assertEquals(0xFFFFFFFF, view.getId()); 1230 } 1231 1232 @Test testAccessLongClickable()1233 public void testAccessLongClickable() { 1234 View view = new View(mActivity); 1235 1236 assertFalse(view.isLongClickable()); 1237 1238 view.setLongClickable(true); 1239 assertTrue(view.isLongClickable()); 1240 1241 view.setLongClickable(false); 1242 assertFalse(view.isLongClickable()); 1243 } 1244 1245 @Test testAccessClickable()1246 public void testAccessClickable() { 1247 View view = new View(mActivity); 1248 1249 assertFalse(view.isClickable()); 1250 1251 view.setClickable(true); 1252 assertTrue(view.isClickable()); 1253 1254 view.setClickable(false); 1255 assertFalse(view.isClickable()); 1256 } 1257 1258 @Test testAccessContextClickable()1259 public void testAccessContextClickable() { 1260 View view = new View(mActivity); 1261 1262 assertFalse(view.isContextClickable()); 1263 1264 view.setContextClickable(true); 1265 assertTrue(view.isContextClickable()); 1266 1267 view.setContextClickable(false); 1268 assertFalse(view.isContextClickable()); 1269 } 1270 1271 @Test testGetContextMenuInfo()1272 public void testGetContextMenuInfo() { 1273 MockView view = new MockView(mActivity); 1274 1275 assertNull(view.getContextMenuInfo()); 1276 } 1277 1278 @Test testSetOnCreateContextMenuListener()1279 public void testSetOnCreateContextMenuListener() { 1280 View view = new View(mActivity); 1281 assertFalse(view.isLongClickable()); 1282 1283 view.setOnCreateContextMenuListener(null); 1284 assertTrue(view.isLongClickable()); 1285 1286 view.setOnCreateContextMenuListener(mock(View.OnCreateContextMenuListener.class)); 1287 assertTrue(view.isLongClickable()); 1288 } 1289 1290 @Test testCreateContextMenu()1291 public void testCreateContextMenu() throws Throwable { 1292 mActivityRule.runOnUiThread(() -> { 1293 View.OnCreateContextMenuListener listener = 1294 mock(View.OnCreateContextMenuListener.class); 1295 MockView view = new MockView(mActivity); 1296 mActivity.setContentView(view); 1297 mActivity.registerForContextMenu(view); 1298 view.setOnCreateContextMenuListener(listener); 1299 assertFalse(view.hasCalledOnCreateContextMenu()); 1300 verifyZeroInteractions(listener); 1301 1302 view.showContextMenu(); 1303 assertTrue(view.hasCalledOnCreateContextMenu()); 1304 verify(listener, times(1)).onCreateContextMenu( 1305 any(), eq(view), any()); 1306 }); 1307 } 1308 1309 @Test(expected=NullPointerException.class) testCreateContextMenuNull()1310 public void testCreateContextMenuNull() { 1311 MockView view = new MockView(mActivity); 1312 view.createContextMenu(null); 1313 } 1314 1315 @Test 1316 @UiThreadTest testAddFocusables()1317 public void testAddFocusables() { 1318 View view = new View(mActivity); 1319 mActivity.setContentView(view); 1320 1321 ArrayList<View> viewList = new ArrayList<>(); 1322 1323 // view is not focusable 1324 assertFalse(view.isFocusable()); 1325 assertEquals(0, viewList.size()); 1326 view.addFocusables(viewList, 0); 1327 assertEquals(0, viewList.size()); 1328 1329 // view is focusable 1330 view.setFocusable(true); 1331 view.addFocusables(viewList, 0); 1332 assertEquals(1, viewList.size()); 1333 assertEquals(view, viewList.get(0)); 1334 1335 // null array should be ignored 1336 view.addFocusables(null, 0); 1337 } 1338 1339 @Test 1340 @UiThreadTest testGetFocusables()1341 public void testGetFocusables() { 1342 View view = new View(mActivity); 1343 mActivity.setContentView(view); 1344 1345 ArrayList<View> viewList; 1346 1347 // view is not focusable 1348 assertFalse(view.isFocusable()); 1349 viewList = view.getFocusables(0); 1350 assertEquals(0, viewList.size()); 1351 1352 // view is focusable 1353 view.setFocusable(true); 1354 viewList = view.getFocusables(0); 1355 assertEquals(1, viewList.size()); 1356 assertEquals(view, viewList.get(0)); 1357 1358 viewList = view.getFocusables(-1); 1359 assertEquals(1, viewList.size()); 1360 assertEquals(view, viewList.get(0)); 1361 } 1362 1363 @Test 1364 @UiThreadTest testAddFocusablesWithoutTouchMode()1365 public void testAddFocusablesWithoutTouchMode() { 1366 View view = new View(mActivity); 1367 mActivity.setContentView(view); 1368 1369 assertFalse("test sanity", view.isInTouchMode()); 1370 focusableInTouchModeTest(view, false); 1371 } 1372 1373 @Test testAddFocusablesInTouchMode()1374 public void testAddFocusablesInTouchMode() { 1375 View view = spy(new View(mActivity)); 1376 when(view.isInTouchMode()).thenReturn(true); 1377 focusableInTouchModeTest(view, true); 1378 } 1379 focusableInTouchModeTest(View view, boolean inTouchMode)1380 private void focusableInTouchModeTest(View view, boolean inTouchMode) { 1381 ArrayList<View> views = new ArrayList<>(); 1382 1383 view.setFocusableInTouchMode(false); 1384 view.setFocusable(true); 1385 1386 view.addFocusables(views, View.FOCUS_FORWARD); 1387 if (inTouchMode) { 1388 assertEquals(Collections.emptyList(), views); 1389 } else { 1390 assertEquals(Collections.singletonList(view), views); 1391 } 1392 1393 views.clear(); 1394 view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_ALL); 1395 assertEquals(Collections.singletonList(view), views); 1396 1397 views.clear(); 1398 view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_TOUCH_MODE); 1399 assertEquals(Collections.emptyList(), views); 1400 1401 view.setFocusableInTouchMode(true); 1402 1403 views.clear(); 1404 view.addFocusables(views, View.FOCUS_FORWARD); 1405 assertEquals(Collections.singletonList(view), views); 1406 1407 views.clear(); 1408 view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_ALL); 1409 assertEquals(Collections.singletonList(view), views); 1410 1411 views.clear(); 1412 view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_TOUCH_MODE); 1413 assertEquals(Collections.singletonList(view), views); 1414 1415 view.setFocusable(false); 1416 1417 views.clear(); 1418 view.addFocusables(views, View.FOCUS_FORWARD); 1419 assertEquals(Collections.emptyList(), views); 1420 1421 views.clear(); 1422 view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_ALL); 1423 assertEquals(Collections.emptyList(), views); 1424 1425 views.clear(); 1426 view.addFocusables(views, View.FOCUS_FORWARD, View.FOCUSABLES_TOUCH_MODE); 1427 assertEquals(Collections.emptyList(), views); 1428 } 1429 1430 @Test testAddKeyboardNavigationClusters()1431 public void testAddKeyboardNavigationClusters() { 1432 View view = new View(mActivity); 1433 ArrayList<View> viewList = new ArrayList<>(); 1434 1435 // View is not a keyboard navigation cluster 1436 assertFalse(view.isKeyboardNavigationCluster()); 1437 view.addKeyboardNavigationClusters(viewList, 0); 1438 assertEquals(0, viewList.size()); 1439 1440 // View is a cluster (but not focusable, so technically empty) 1441 view.setKeyboardNavigationCluster(true); 1442 view.addKeyboardNavigationClusters(viewList, 0); 1443 assertEquals(0, viewList.size()); 1444 viewList.clear(); 1445 // a focusable cluster is not-empty 1446 view.setFocusableInTouchMode(true); 1447 view.addKeyboardNavigationClusters(viewList, 0); 1448 assertEquals(1, viewList.size()); 1449 assertEquals(view, viewList.get(0)); 1450 } 1451 1452 @Test testKeyboardNavigationClusterSearch()1453 public void testKeyboardNavigationClusterSearch() throws Throwable { 1454 mActivityRule.runOnUiThread(() -> { 1455 ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView(); 1456 decorView.removeAllViews(); 1457 View v1 = new MockView(mActivity); 1458 v1.setFocusableInTouchMode(true); 1459 View v2 = new MockView(mActivity); 1460 v2.setFocusableInTouchMode(true); 1461 decorView.addView(v1); 1462 decorView.addView(v2); 1463 1464 // Searching for clusters. 1465 v1.setKeyboardNavigationCluster(true); 1466 v2.setKeyboardNavigationCluster(true); 1467 assertEquals(v2, decorView.keyboardNavigationClusterSearch(v1, View.FOCUS_FORWARD)); 1468 assertEquals(v1, decorView.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD)); 1469 assertEquals(v2, decorView.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD)); 1470 assertEquals(v2, v1.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD)); 1471 assertEquals(decorView, v1.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD)); 1472 assertEquals(decorView, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD)); 1473 assertEquals(v1, v2.keyboardNavigationClusterSearch(null, View.FOCUS_BACKWARD)); 1474 1475 // Clusters in 3-level hierarchy. 1476 decorView.removeAllViews(); 1477 LinearLayout middle = new LinearLayout(mActivity); 1478 middle.addView(v1); 1479 middle.addView(v2); 1480 decorView.addView(middle); 1481 assertEquals(decorView, v2.keyboardNavigationClusterSearch(null, View.FOCUS_FORWARD)); 1482 }); 1483 } 1484 1485 @Test testGetRootView()1486 public void testGetRootView() { 1487 MockView view = new MockView(mActivity); 1488 1489 assertNull(view.getParent()); 1490 assertEquals(view, view.getRootView()); 1491 1492 view.setParent(mMockParent); 1493 assertEquals(mMockParent, view.getRootView()); 1494 } 1495 1496 @Test testGetSolidColor()1497 public void testGetSolidColor() { 1498 View view = new View(mActivity); 1499 1500 assertEquals(0, view.getSolidColor()); 1501 } 1502 1503 @Test testSetMinimumWidth()1504 public void testSetMinimumWidth() { 1505 MockView view = new MockView(mActivity); 1506 assertEquals(0, view.getSuggestedMinimumWidth()); 1507 1508 view.setMinimumWidth(100); 1509 assertEquals(100, view.getSuggestedMinimumWidth()); 1510 1511 view.setMinimumWidth(-100); 1512 assertEquals(-100, view.getSuggestedMinimumWidth()); 1513 } 1514 1515 @Test testGetSuggestedMinimumWidth()1516 public void testGetSuggestedMinimumWidth() { 1517 MockView view = new MockView(mActivity); 1518 Drawable d = mResources.getDrawable(R.drawable.scenery); 1519 int drawableMinimumWidth = d.getMinimumWidth(); 1520 1521 // drawable is null 1522 view.setMinimumWidth(100); 1523 assertNull(view.getBackground()); 1524 assertEquals(100, view.getSuggestedMinimumWidth()); 1525 1526 // drawable minimum width is larger than mMinWidth 1527 view.setBackgroundDrawable(d); 1528 view.setMinimumWidth(drawableMinimumWidth - 10); 1529 assertEquals(drawableMinimumWidth, view.getSuggestedMinimumWidth()); 1530 1531 // drawable minimum width is smaller than mMinWidth 1532 view.setMinimumWidth(drawableMinimumWidth + 10); 1533 assertEquals(drawableMinimumWidth + 10, view.getSuggestedMinimumWidth()); 1534 } 1535 1536 @Test testSetMinimumHeight()1537 public void testSetMinimumHeight() { 1538 MockView view = new MockView(mActivity); 1539 assertEquals(0, view.getSuggestedMinimumHeight()); 1540 1541 view.setMinimumHeight(100); 1542 assertEquals(100, view.getSuggestedMinimumHeight()); 1543 1544 view.setMinimumHeight(-100); 1545 assertEquals(-100, view.getSuggestedMinimumHeight()); 1546 } 1547 1548 @Test testGetSuggestedMinimumHeight()1549 public void testGetSuggestedMinimumHeight() { 1550 MockView view = new MockView(mActivity); 1551 Drawable d = mResources.getDrawable(R.drawable.scenery); 1552 int drawableMinimumHeight = d.getMinimumHeight(); 1553 1554 // drawable is null 1555 view.setMinimumHeight(100); 1556 assertNull(view.getBackground()); 1557 assertEquals(100, view.getSuggestedMinimumHeight()); 1558 1559 // drawable minimum height is larger than mMinHeight 1560 view.setBackgroundDrawable(d); 1561 view.setMinimumHeight(drawableMinimumHeight - 10); 1562 assertEquals(drawableMinimumHeight, view.getSuggestedMinimumHeight()); 1563 1564 // drawable minimum height is smaller than mMinHeight 1565 view.setMinimumHeight(drawableMinimumHeight + 10); 1566 assertEquals(drawableMinimumHeight + 10, view.getSuggestedMinimumHeight()); 1567 } 1568 1569 @Test testAccessWillNotCacheDrawing()1570 public void testAccessWillNotCacheDrawing() { 1571 View view = new View(mActivity); 1572 1573 assertFalse(view.willNotCacheDrawing()); 1574 1575 view.setWillNotCacheDrawing(true); 1576 assertTrue(view.willNotCacheDrawing()); 1577 } 1578 1579 @Test testAccessDrawingCacheEnabled()1580 public void testAccessDrawingCacheEnabled() { 1581 View view = new View(mActivity); 1582 1583 assertFalse(view.isDrawingCacheEnabled()); 1584 1585 view.setDrawingCacheEnabled(true); 1586 assertTrue(view.isDrawingCacheEnabled()); 1587 } 1588 1589 @Test testGetDrawingCache()1590 public void testGetDrawingCache() { 1591 MockView view = new MockView(mActivity); 1592 1593 // should not call buildDrawingCache when getDrawingCache 1594 assertNull(view.getDrawingCache()); 1595 1596 // should call buildDrawingCache when getDrawingCache 1597 view = (MockView) mActivity.findViewById(R.id.mock_view); 1598 view.setDrawingCacheEnabled(true); 1599 Bitmap bitmap1 = view.getDrawingCache(); 1600 assertNotNull(bitmap1); 1601 assertEquals(view.getWidth(), bitmap1.getWidth()); 1602 assertEquals(view.getHeight(), bitmap1.getHeight()); 1603 1604 view.setWillNotCacheDrawing(true); 1605 assertNull(view.getDrawingCache()); 1606 1607 view.setWillNotCacheDrawing(false); 1608 // build a new drawingcache 1609 Bitmap bitmap2 = view.getDrawingCache(); 1610 assertNotSame(bitmap1, bitmap2); 1611 } 1612 1613 @Test testBuildAndDestroyDrawingCache()1614 public void testBuildAndDestroyDrawingCache() { 1615 MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 1616 1617 assertNull(view.getDrawingCache()); 1618 1619 view.buildDrawingCache(); 1620 Bitmap bitmap = view.getDrawingCache(); 1621 assertNotNull(bitmap); 1622 assertEquals(view.getWidth(), bitmap.getWidth()); 1623 assertEquals(view.getHeight(), bitmap.getHeight()); 1624 1625 view.destroyDrawingCache(); 1626 assertNull(view.getDrawingCache()); 1627 } 1628 1629 @Test testAccessWillNotDraw()1630 public void testAccessWillNotDraw() { 1631 View view = new View(mActivity); 1632 1633 assertFalse(view.willNotDraw()); 1634 1635 view.setWillNotDraw(true); 1636 assertTrue(view.willNotDraw()); 1637 } 1638 1639 @Test testAccessDrawingCacheQuality()1640 public void testAccessDrawingCacheQuality() { 1641 View view = new View(mActivity); 1642 1643 assertEquals(0, view.getDrawingCacheQuality()); 1644 1645 view.setDrawingCacheQuality(1); 1646 assertEquals(0, view.getDrawingCacheQuality()); 1647 1648 view.setDrawingCacheQuality(0x00100000); 1649 assertEquals(0x00100000, view.getDrawingCacheQuality()); 1650 1651 view.setDrawingCacheQuality(0x00080000); 1652 assertEquals(0x00080000, view.getDrawingCacheQuality()); 1653 1654 view.setDrawingCacheQuality(0xffffffff); 1655 // 0x00180000 is View.DRAWING_CACHE_QUALITY_MASK 1656 assertEquals(0x00180000, view.getDrawingCacheQuality()); 1657 } 1658 1659 @Test testDispatchSetSelected()1660 public void testDispatchSetSelected() { 1661 MockView mockView1 = new MockView(mActivity); 1662 MockView mockView2 = new MockView(mActivity); 1663 mockView1.setParent(mMockParent); 1664 mockView2.setParent(mMockParent); 1665 1666 mMockParent.dispatchSetSelected(true); 1667 assertTrue(mockView1.isSelected()); 1668 assertTrue(mockView2.isSelected()); 1669 1670 mMockParent.dispatchSetSelected(false); 1671 assertFalse(mockView1.isSelected()); 1672 assertFalse(mockView2.isSelected()); 1673 } 1674 1675 @Test testAccessSelected()1676 public void testAccessSelected() { 1677 View view = new View(mActivity); 1678 1679 assertFalse(view.isSelected()); 1680 1681 view.setSelected(true); 1682 assertTrue(view.isSelected()); 1683 } 1684 1685 @Test testDispatchSetPressed()1686 public void testDispatchSetPressed() { 1687 MockView mockView1 = new MockView(mActivity); 1688 MockView mockView2 = new MockView(mActivity); 1689 mockView1.setParent(mMockParent); 1690 mockView2.setParent(mMockParent); 1691 1692 mMockParent.dispatchSetPressed(true); 1693 assertTrue(mockView1.isPressed()); 1694 assertTrue(mockView2.isPressed()); 1695 1696 mMockParent.dispatchSetPressed(false); 1697 assertFalse(mockView1.isPressed()); 1698 assertFalse(mockView2.isPressed()); 1699 } 1700 1701 @Test testAccessPressed()1702 public void testAccessPressed() { 1703 View view = new View(mActivity); 1704 1705 assertFalse(view.isPressed()); 1706 1707 view.setPressed(true); 1708 assertTrue(view.isPressed()); 1709 } 1710 1711 @Test testAccessSoundEffectsEnabled()1712 public void testAccessSoundEffectsEnabled() { 1713 View view = new View(mActivity); 1714 1715 assertTrue(view.isSoundEffectsEnabled()); 1716 1717 view.setSoundEffectsEnabled(false); 1718 assertFalse(view.isSoundEffectsEnabled()); 1719 } 1720 1721 @Test testAccessKeepScreenOn()1722 public void testAccessKeepScreenOn() { 1723 View view = new View(mActivity); 1724 1725 assertFalse(view.getKeepScreenOn()); 1726 1727 view.setKeepScreenOn(true); 1728 assertTrue(view.getKeepScreenOn()); 1729 } 1730 1731 @Test testAccessDuplicateParentStateEnabled()1732 public void testAccessDuplicateParentStateEnabled() { 1733 View view = new View(mActivity); 1734 1735 assertFalse(view.isDuplicateParentStateEnabled()); 1736 1737 view.setDuplicateParentStateEnabled(true); 1738 assertTrue(view.isDuplicateParentStateEnabled()); 1739 } 1740 1741 @Test testAccessEnabled()1742 public void testAccessEnabled() { 1743 View view = new View(mActivity); 1744 1745 assertTrue(view.isEnabled()); 1746 1747 view.setEnabled(false); 1748 assertFalse(view.isEnabled()); 1749 } 1750 1751 1752 @Test testSetEnabled_receiveEvent()1753 public void testSetEnabled_receiveEvent() throws Throwable { 1754 final View mockView = mActivity.findViewById(R.id.mock_view); 1755 mInstrumentation.getUiAutomation().waitForIdle(2000, 4000); 1756 mInstrumentation.getUiAutomation().executeAndWaitForEvent( 1757 () -> mInstrumentation.runOnMainSync(() -> { 1758 mockView.setEnabled(!mockView.isEnabled()); 1759 }), 1760 event -> isExpectedChangeType(event, 1761 AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED), 1762 DEFAULT_TIMEOUT_MILLIS); 1763 } 1764 isExpectedChangeType(AccessibilityEvent event, int changeType)1765 private static boolean isExpectedChangeType(AccessibilityEvent event, int changeType) { 1766 return (event.getContentChangeTypes() & changeType) == changeType; 1767 } 1768 1769 @Test testAccessSaveEnabled()1770 public void testAccessSaveEnabled() { 1771 View view = new View(mActivity); 1772 1773 assertTrue(view.isSaveEnabled()); 1774 1775 view.setSaveEnabled(false); 1776 assertFalse(view.isSaveEnabled()); 1777 } 1778 1779 @Test(expected=NullPointerException.class) testShowContextMenuNullParent()1780 public void testShowContextMenuNullParent() { 1781 MockView view = new MockView(mActivity); 1782 1783 assertNull(view.getParent()); 1784 view.showContextMenu(); 1785 } 1786 1787 @Test testShowContextMenu()1788 public void testShowContextMenu() { 1789 MockView view = new MockView(mActivity); 1790 view.setParent(mMockParent); 1791 assertFalse(mMockParent.hasShowContextMenuForChild()); 1792 1793 assertFalse(view.showContextMenu()); 1794 assertTrue(mMockParent.hasShowContextMenuForChild()); 1795 } 1796 1797 @Test(expected=NullPointerException.class) testShowContextMenuXYNullParent()1798 public void testShowContextMenuXYNullParent() { 1799 MockView view = new MockView(mActivity); 1800 1801 assertNull(view.getParent()); 1802 view.showContextMenu(0, 0); 1803 } 1804 1805 @Test testShowContextMenuXY()1806 public void testShowContextMenuXY() { 1807 MockViewParent parent = new MockViewParent(mActivity); 1808 MockView view = new MockView(mActivity); 1809 1810 view.setParent(parent); 1811 assertFalse(parent.hasShowContextMenuForChildXY()); 1812 1813 assertFalse(view.showContextMenu(0, 0)); 1814 assertTrue(parent.hasShowContextMenuForChildXY()); 1815 } 1816 1817 @Test testShowContextMenu_withDefaultHapticFeedbackDisabled_performHapticFeedback()1818 public void testShowContextMenu_withDefaultHapticFeedbackDisabled_performHapticFeedback() { 1819 MockView view = new MockView(mActivity); 1820 View.OnLongClickListener listener = new OnLongClickListener() { 1821 @Override 1822 public boolean onLongClick(View v) { 1823 return false; 1824 } 1825 1826 @Override 1827 public boolean onLongClickUseDefaultHapticFeedback(View v) { 1828 return false; 1829 } 1830 }; 1831 view.setParent(mMockParent); 1832 view.setOnLongClickListener(listener); 1833 mMockParent.setShouldShowContextMenu(true); 1834 1835 assertTrue(view.performLongClick(0, 0)); 1836 assertTrue(mMockParent.hasShowContextMenuForChildXY()); 1837 assertTrue(view.hasCalledPerformHapticFeedback()); 1838 mMockParent.reset(); 1839 } 1840 1841 @Test testFitSystemWindows()1842 public void testFitSystemWindows() { 1843 final XmlResourceParser parser = mResources.getLayout(R.layout.view_layout); 1844 final AttributeSet attrs = Xml.asAttributeSet(parser); 1845 Rect insets = new Rect(10, 20, 30, 50); 1846 1847 MockView view = new MockView(mActivity); 1848 assertFalse(view.fitSystemWindows(insets)); 1849 assertFalse(view.fitSystemWindows(null)); 1850 1851 view = new MockView(mActivity, attrs, android.R.attr.fitsSystemWindows); 1852 assertFalse(view.fitSystemWindows(insets)); 1853 assertFalse(view.fitSystemWindows(null)); 1854 } 1855 1856 @Test testPerformClick()1857 public void testPerformClick() { 1858 View view = new View(mActivity); 1859 View.OnClickListener listener = mock(View.OnClickListener.class); 1860 1861 assertFalse(view.performClick()); 1862 1863 verifyZeroInteractions(listener); 1864 view.setOnClickListener(listener); 1865 1866 assertTrue(view.performClick()); 1867 verify(listener,times(1)).onClick(view); 1868 1869 view.setOnClickListener(null); 1870 assertFalse(view.performClick()); 1871 } 1872 1873 @Test testSetOnClickListener()1874 public void testSetOnClickListener() { 1875 View view = new View(mActivity); 1876 assertFalse(view.performClick()); 1877 assertFalse(view.isClickable()); 1878 1879 view.setOnClickListener(null); 1880 assertFalse(view.performClick()); 1881 assertTrue(view.isClickable()); 1882 1883 view.setOnClickListener(mock(View.OnClickListener.class)); 1884 assertTrue(view.performClick()); 1885 assertTrue(view.isClickable()); 1886 } 1887 1888 @Test testSetOnGenericMotionListener()1889 public void testSetOnGenericMotionListener() { 1890 View view = new View(mActivity); 1891 MotionEvent event = 1892 EventUtils.generateMouseEvent(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0); 1893 1894 assertFalse(view.dispatchGenericMotionEvent(event)); 1895 event.recycle(); 1896 1897 View.OnGenericMotionListener listener = mock(View.OnGenericMotionListener.class); 1898 doReturn(true).when(listener).onGenericMotion(any(), any()); 1899 view.setOnGenericMotionListener(listener); 1900 1901 MotionEvent event2 = 1902 EventUtils.generateMouseEvent(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0); 1903 1904 assertTrue(view.dispatchGenericMotionEvent(event2)); 1905 event2.recycle(); 1906 1907 view.setOnGenericMotionListener(null); 1908 MotionEvent event3 = 1909 EventUtils.generateMouseEvent(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0); 1910 1911 assertFalse(view.dispatchGenericMotionEvent(event3)); 1912 event3.recycle(); 1913 } 1914 1915 @Test(expected=NullPointerException.class) testPerformLongClickNullParent()1916 public void testPerformLongClickNullParent() { 1917 MockView view = new MockView(mActivity); 1918 view.performLongClick(); 1919 } 1920 1921 @Test testPerformLongClick()1922 public void testPerformLongClick() { 1923 MockView view = new MockView(mActivity); 1924 View.OnLongClickListener listener = mock(View.OnLongClickListener.class); 1925 doReturn(true).when(listener).onLongClick(any()); 1926 1927 view.setParent(mMockParent); 1928 assertFalse(mMockParent.hasShowContextMenuForChild()); 1929 assertFalse(view.performLongClick()); 1930 assertTrue(mMockParent.hasShowContextMenuForChild()); 1931 1932 view.setOnLongClickListener(listener); 1933 mMockParent.reset(); 1934 assertFalse(mMockParent.hasShowContextMenuForChild()); 1935 verifyZeroInteractions(listener); 1936 assertTrue(view.performLongClick()); 1937 assertFalse(mMockParent.hasShowContextMenuForChild()); 1938 verify(listener, times(1)).onLongClick(view); 1939 } 1940 1941 @Test testPerformLongClick_withDefaultHapticFeedbackEnabled_performHapticFeedback()1942 public void testPerformLongClick_withDefaultHapticFeedbackEnabled_performHapticFeedback() { 1943 MockView view = new MockView(mActivity); 1944 View.OnLongClickListener listener = v -> true; 1945 1946 view.setParent(mMockParent); 1947 view.setOnLongClickListener(listener); 1948 view.reset(); 1949 1950 assertTrue(view.performLongClick()); 1951 assertTrue(view.hasCalledPerformHapticFeedback()); 1952 } 1953 1954 @Test testPerformLongClick_withDefaultHapticFeedbackDisabled_skipHapticFeedback()1955 public void testPerformLongClick_withDefaultHapticFeedbackDisabled_skipHapticFeedback() { 1956 MockView view = new MockView(mActivity); 1957 View.OnLongClickListener listener = new OnLongClickListener() { 1958 @Override 1959 public boolean onLongClick(View v) { 1960 return true; 1961 } 1962 1963 @Override 1964 public boolean onLongClickUseDefaultHapticFeedback(View v) { 1965 return false; 1966 } 1967 }; 1968 1969 view.setParent(mMockParent); 1970 view.setOnLongClickListener(listener); 1971 view.reset(); 1972 1973 assertTrue(view.performLongClick()); 1974 assertFalse(view.hasCalledPerformHapticFeedback()); 1975 } 1976 1977 @Test testPerformLongClick_withListenerRemovedOnLongClick_upholdDefaultHapticOverride()1978 public void testPerformLongClick_withListenerRemovedOnLongClick_upholdDefaultHapticOverride() { 1979 final MockView view = new MockView(mActivity); 1980 View.OnLongClickListener listener = new OnLongClickListener() { 1981 @Override 1982 public boolean onLongClick(View v) { 1983 view.setOnLongClickListener(null); 1984 return true; 1985 } 1986 1987 @Override 1988 public boolean onLongClickUseDefaultHapticFeedback(View v) { 1989 return false; 1990 } 1991 }; 1992 1993 view.setParent(mMockParent); 1994 view.setOnLongClickListener(listener); 1995 view.reset(); 1996 1997 assertTrue(view.performLongClick()); 1998 assertFalse(view.hasCalledPerformHapticFeedback()); 1999 } 2000 2001 @Test(expected=NullPointerException.class) testPerformLongClickXYNullParent()2002 public void testPerformLongClickXYNullParent() { 2003 MockView view = new MockView(mActivity); 2004 view.performLongClick(0, 0); 2005 } 2006 2007 @Test testPerformLongClickXY()2008 public void testPerformLongClickXY() { 2009 MockViewParent parent = new MockViewParent(mActivity); 2010 MockView view = new MockView(mActivity); 2011 2012 parent.addView(view); 2013 assertFalse(parent.hasShowContextMenuForChildXY()); 2014 2015 // Verify default context menu behavior. 2016 assertFalse(view.performLongClick(0, 0)); 2017 assertTrue(parent.hasShowContextMenuForChildXY()); 2018 } 2019 2020 @Test testPerformLongClickXY_WithListener()2021 public void testPerformLongClickXY_WithListener() { 2022 OnLongClickListener listener = mock(OnLongClickListener.class); 2023 when(listener.onLongClick(any(View.class))).thenReturn(true); 2024 2025 MockViewParent parent = new MockViewParent(mActivity); 2026 MockView view = new MockView(mActivity); 2027 2028 view.setOnLongClickListener(listener); 2029 verify(listener, never()).onLongClick(any(View.class)); 2030 2031 parent.addView(view); 2032 assertFalse(parent.hasShowContextMenuForChildXY()); 2033 2034 // Verify listener is preferred over default context menu. 2035 assertTrue(view.performLongClick(0, 0)); 2036 assertFalse(parent.hasShowContextMenuForChildXY()); 2037 verify(listener).onLongClick(view); 2038 } 2039 2040 @Test testSetOnLongClickListener()2041 public void testSetOnLongClickListener() { 2042 MockView view = new MockView(mActivity); 2043 view.setParent(mMockParent); 2044 assertFalse(view.performLongClick()); 2045 assertFalse(view.isLongClickable()); 2046 2047 view.setOnLongClickListener(null); 2048 assertFalse(view.performLongClick()); 2049 assertTrue(view.isLongClickable()); 2050 2051 View.OnLongClickListener listener = mock(View.OnLongClickListener.class); 2052 doReturn(true).when(listener).onLongClick(any()); 2053 view.setOnLongClickListener(listener); 2054 assertTrue(view.performLongClick()); 2055 assertTrue(view.isLongClickable()); 2056 } 2057 2058 @Test testPerformContextClick()2059 public void testPerformContextClick() { 2060 MockView view = new MockView(mActivity); 2061 view.setParent(mMockParent); 2062 View.OnContextClickListener listener = mock(View.OnContextClickListener.class); 2063 doReturn(true).when(listener).onContextClick(any()); 2064 2065 view.setOnContextClickListener(listener); 2066 verifyZeroInteractions(listener); 2067 2068 assertTrue(view.performContextClick()); 2069 verify(listener, times(1)).onContextClick(view); 2070 } 2071 2072 @Test testSetOnContextClickListener()2073 public void testSetOnContextClickListener() { 2074 MockView view = new MockView(mActivity); 2075 view.setParent(mMockParent); 2076 2077 assertFalse(view.performContextClick()); 2078 assertFalse(view.isContextClickable()); 2079 2080 View.OnContextClickListener listener = mock(View.OnContextClickListener.class); 2081 doReturn(true).when(listener).onContextClick(any()); 2082 view.setOnContextClickListener(listener); 2083 assertTrue(view.performContextClick()); 2084 assertTrue(view.isContextClickable()); 2085 } 2086 2087 @Test testAccessOnFocusChangeListener()2088 public void testAccessOnFocusChangeListener() { 2089 View view = new View(mActivity); 2090 View.OnFocusChangeListener listener = mock(View.OnFocusChangeListener.class); 2091 2092 assertNull(view.getOnFocusChangeListener()); 2093 2094 view.setOnFocusChangeListener(listener); 2095 assertSame(listener, view.getOnFocusChangeListener()); 2096 } 2097 2098 @Test testAccessNextFocusUpId()2099 public void testAccessNextFocusUpId() { 2100 View view = new View(mActivity); 2101 2102 assertEquals(View.NO_ID, view.getNextFocusUpId()); 2103 2104 view.setNextFocusUpId(1); 2105 assertEquals(1, view.getNextFocusUpId()); 2106 2107 view.setNextFocusUpId(Integer.MAX_VALUE); 2108 assertEquals(Integer.MAX_VALUE, view.getNextFocusUpId()); 2109 2110 view.setNextFocusUpId(Integer.MIN_VALUE); 2111 assertEquals(Integer.MIN_VALUE, view.getNextFocusUpId()); 2112 } 2113 2114 @Test testAccessNextFocusDownId()2115 public void testAccessNextFocusDownId() { 2116 View view = new View(mActivity); 2117 2118 assertEquals(View.NO_ID, view.getNextFocusDownId()); 2119 2120 view.setNextFocusDownId(1); 2121 assertEquals(1, view.getNextFocusDownId()); 2122 2123 view.setNextFocusDownId(Integer.MAX_VALUE); 2124 assertEquals(Integer.MAX_VALUE, view.getNextFocusDownId()); 2125 2126 view.setNextFocusDownId(Integer.MIN_VALUE); 2127 assertEquals(Integer.MIN_VALUE, view.getNextFocusDownId()); 2128 } 2129 2130 @Test testAccessNextFocusLeftId()2131 public void testAccessNextFocusLeftId() { 2132 View view = new View(mActivity); 2133 2134 assertEquals(View.NO_ID, view.getNextFocusLeftId()); 2135 2136 view.setNextFocusLeftId(1); 2137 assertEquals(1, view.getNextFocusLeftId()); 2138 2139 view.setNextFocusLeftId(Integer.MAX_VALUE); 2140 assertEquals(Integer.MAX_VALUE, view.getNextFocusLeftId()); 2141 2142 view.setNextFocusLeftId(Integer.MIN_VALUE); 2143 assertEquals(Integer.MIN_VALUE, view.getNextFocusLeftId()); 2144 } 2145 2146 @Test testAccessNextFocusRightId()2147 public void testAccessNextFocusRightId() { 2148 View view = new View(mActivity); 2149 2150 assertEquals(View.NO_ID, view.getNextFocusRightId()); 2151 2152 view.setNextFocusRightId(1); 2153 assertEquals(1, view.getNextFocusRightId()); 2154 2155 view.setNextFocusRightId(Integer.MAX_VALUE); 2156 assertEquals(Integer.MAX_VALUE, view.getNextFocusRightId()); 2157 2158 view.setNextFocusRightId(Integer.MIN_VALUE); 2159 assertEquals(Integer.MIN_VALUE, view.getNextFocusRightId()); 2160 } 2161 2162 @Test testAccessMeasuredDimension()2163 public void testAccessMeasuredDimension() { 2164 MockView view = new MockView(mActivity); 2165 assertEquals(0, view.getMeasuredWidth()); 2166 assertEquals(0, view.getMeasuredHeight()); 2167 2168 view.setMeasuredDimensionWrapper(20, 30); 2169 assertEquals(20, view.getMeasuredWidth()); 2170 assertEquals(30, view.getMeasuredHeight()); 2171 } 2172 2173 @Test testMeasure()2174 public void testMeasure() throws Throwable { 2175 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 2176 2177 float density = view.getContext().getResources().getDisplayMetrics().density; 2178 int size1 = (int) (75 * density + 0.5); 2179 int size2 = (int) (100 * density + 0.5); 2180 2181 assertTrue(view.hasCalledOnMeasure()); 2182 assertEquals(size1, view.getMeasuredWidth()); 2183 assertEquals(size2, view.getMeasuredHeight()); 2184 2185 view.reset(); 2186 mActivityRule.runOnUiThread(view::requestLayout); 2187 mInstrumentation.waitForIdleSync(); 2188 assertTrue(view.hasCalledOnMeasure()); 2189 assertEquals(size1, view.getMeasuredWidth()); 2190 assertEquals(size2, view.getMeasuredHeight()); 2191 2192 view.reset(); 2193 final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(size2, size1); 2194 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams)); 2195 mInstrumentation.waitForIdleSync(); 2196 assertTrue(view.hasCalledOnMeasure()); 2197 assertEquals(size2, view.getMeasuredWidth()); 2198 assertEquals(size1, view.getMeasuredHeight()); 2199 } 2200 2201 @Test(expected=NullPointerException.class) setSetLayoutParamsNull()2202 public void setSetLayoutParamsNull() { 2203 View view = new View(mActivity); 2204 assertNull(view.getLayoutParams()); 2205 2206 view.setLayoutParams(null); 2207 } 2208 2209 @Test testAccessLayoutParams()2210 public void testAccessLayoutParams() { 2211 View view = new View(mActivity); 2212 ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(10, 20); 2213 2214 assertFalse(view.isLayoutRequested()); 2215 view.setLayoutParams(params); 2216 assertSame(params, view.getLayoutParams()); 2217 assertTrue(view.isLayoutRequested()); 2218 } 2219 2220 @Test testIsShown()2221 public void testIsShown() { 2222 MockView view = new MockView(mActivity); 2223 2224 view.setVisibility(View.INVISIBLE); 2225 assertFalse(view.isShown()); 2226 2227 view.setVisibility(View.VISIBLE); 2228 assertNull(view.getParent()); 2229 assertFalse(view.isShown()); 2230 2231 view.setParent(mMockParent); 2232 // mMockParent is not a instance of ViewRoot 2233 assertFalse(view.isShown()); 2234 } 2235 2236 @Test testGetDrawingTime()2237 public void testGetDrawingTime() { 2238 View view = new View(mActivity); 2239 // mAttachInfo is null 2240 assertEquals(0, view.getDrawingTime()); 2241 2242 // mAttachInfo is not null 2243 view = mActivity.findViewById(R.id.fit_windows); 2244 assertEquals(SystemClock.uptimeMillis(), view.getDrawingTime(), 1000); 2245 } 2246 2247 @Test testScheduleDrawable()2248 public void testScheduleDrawable() { 2249 View view = new View(mActivity); 2250 Drawable drawable = new StateListDrawable(); 2251 // Does nothing. 2252 Runnable what = () -> {}; 2253 // mAttachInfo is null 2254 view.scheduleDrawable(drawable, what, 1000); 2255 2256 view.setBackgroundDrawable(drawable); 2257 view.scheduleDrawable(drawable, what, 1000); 2258 2259 view.scheduleDrawable(null, null, -1000); 2260 2261 // mAttachInfo is not null 2262 view = mActivity.findViewById(R.id.fit_windows); 2263 view.scheduleDrawable(drawable, what, 1000); 2264 2265 view.scheduleDrawable(view.getBackground(), what, 1000); 2266 view.unscheduleDrawable(view.getBackground(), what); 2267 2268 view.scheduleDrawable(null, null, -1000); 2269 } 2270 2271 @Test testUnscheduleDrawable()2272 public void testUnscheduleDrawable() { 2273 View view = new View(mActivity); 2274 Drawable drawable = new StateListDrawable(); 2275 Runnable what = () -> { 2276 // do nothing 2277 }; 2278 2279 // mAttachInfo is null 2280 view.unscheduleDrawable(drawable, what); 2281 2282 view.setBackgroundDrawable(drawable); 2283 view.unscheduleDrawable(drawable); 2284 2285 view.unscheduleDrawable(null, null); 2286 view.unscheduleDrawable(null); 2287 2288 // mAttachInfo is not null 2289 view = mActivity.findViewById(R.id.fit_windows); 2290 view.unscheduleDrawable(drawable); 2291 2292 view.scheduleDrawable(view.getBackground(), what, 1000); 2293 view.unscheduleDrawable(view.getBackground(), what); 2294 2295 view.unscheduleDrawable(null); 2296 view.unscheduleDrawable(null, null); 2297 } 2298 2299 @Test testGetWindowVisibility()2300 public void testGetWindowVisibility() { 2301 View view = new View(mActivity); 2302 // mAttachInfo is null 2303 assertEquals(View.GONE, view.getWindowVisibility()); 2304 2305 // mAttachInfo is not null 2306 view = mActivity.findViewById(R.id.fit_windows); 2307 assertEquals(View.VISIBLE, view.getWindowVisibility()); 2308 } 2309 2310 @Test testGetWindowToken()2311 public void testGetWindowToken() { 2312 View view = new View(mActivity); 2313 // mAttachInfo is null 2314 assertNull(view.getWindowToken()); 2315 2316 // mAttachInfo is not null 2317 view = mActivity.findViewById(R.id.fit_windows); 2318 assertNotNull(view.getWindowToken()); 2319 } 2320 2321 @Test testHasWindowFocus()2322 public void testHasWindowFocus() { 2323 View view = new View(mActivity); 2324 // mAttachInfo is null 2325 assertFalse(view.hasWindowFocus()); 2326 2327 // mAttachInfo is not null 2328 final View view2 = mActivity.findViewById(R.id.fit_windows); 2329 // Wait until the window has been focused. 2330 PollingCheck.waitFor(TIMEOUT_DELTA, view2::hasWindowFocus); 2331 } 2332 2333 @Test testGetHandler()2334 public void testGetHandler() { 2335 MockView view = new MockView(mActivity); 2336 // mAttachInfo is null 2337 assertNull(view.getHandler()); 2338 } 2339 2340 @Test testRemoveCallbacks()2341 public void testRemoveCallbacks() throws InterruptedException { 2342 final long delay = 500L; 2343 View view = mActivity.findViewById(R.id.mock_view); 2344 Runnable runner = mock(Runnable.class); 2345 assertTrue(view.postDelayed(runner, delay)); 2346 assertTrue(view.removeCallbacks(runner)); 2347 assertTrue(view.removeCallbacks(null)); 2348 assertTrue(view.removeCallbacks(mock(Runnable.class))); 2349 Thread.sleep(delay * 2); 2350 verifyZeroInteractions(runner); 2351 // check that the runner actually works 2352 runner = mock(Runnable.class); 2353 assertTrue(view.postDelayed(runner, delay)); 2354 Thread.sleep(delay * 2); 2355 verify(runner, times(1)).run(); 2356 } 2357 2358 @Test testCancelLongPress()2359 public void testCancelLongPress() { 2360 View view = new View(mActivity); 2361 // mAttachInfo is null 2362 view.cancelLongPress(); 2363 2364 // mAttachInfo is not null 2365 view = mActivity.findViewById(R.id.fit_windows); 2366 view.cancelLongPress(); 2367 } 2368 2369 @Test testGetViewTreeObserver()2370 public void testGetViewTreeObserver() { 2371 View view = new View(mActivity); 2372 // mAttachInfo is null 2373 assertNotNull(view.getViewTreeObserver()); 2374 2375 // mAttachInfo is not null 2376 view = mActivity.findViewById(R.id.fit_windows); 2377 assertNotNull(view.getViewTreeObserver()); 2378 } 2379 2380 @Test testGetWindowAttachCount()2381 public void testGetWindowAttachCount() { 2382 MockView view = new MockView(mActivity); 2383 // mAttachInfo is null 2384 assertEquals(0, view.getWindowAttachCount()); 2385 } 2386 2387 @UiThreadTest 2388 @Test testOnAttachedToAndDetachedFromWindow()2389 public void testOnAttachedToAndDetachedFromWindow() { 2390 MockView mockView = new MockView(mActivity); 2391 ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 2392 2393 viewGroup.addView(mockView); 2394 assertTrue(mockView.hasCalledOnAttachedToWindow()); 2395 2396 viewGroup.removeView(mockView); 2397 assertTrue(mockView.hasCalledOnDetachedFromWindow()); 2398 2399 mockView.reset(); 2400 mActivity.setContentView(mockView); 2401 assertTrue(mockView.hasCalledOnAttachedToWindow()); 2402 2403 mActivity.setContentView(R.layout.view_layout); 2404 assertTrue(mockView.hasCalledOnDetachedFromWindow()); 2405 } 2406 2407 @Test testGetLocationInWindow()2408 public void testGetLocationInWindow() { 2409 final int[] location = new int[]{-1, -1}; 2410 2411 final View layout = mActivity.findViewById(R.id.viewlayout_root); 2412 int[] layoutLocation = new int[]{-1, -1}; 2413 layout.getLocationInWindow(layoutLocation); 2414 2415 final View mockView = mActivity.findViewById(R.id.mock_view); 2416 mockView.getLocationInWindow(location); 2417 assertEquals(layoutLocation[0], location[0]); 2418 assertEquals(layoutLocation[1], location[1]); 2419 2420 final View scrollView = mActivity.findViewById(R.id.scroll_view); 2421 scrollView.getLocationInWindow(location); 2422 assertEquals(layoutLocation[0], location[0]); 2423 assertEquals(layoutLocation[1] + mockView.getHeight(), location[1]); 2424 } 2425 2426 @Test(expected=IllegalArgumentException.class) testGetLocationInWindowNullArray()2427 public void testGetLocationInWindowNullArray() { 2428 final View layout = mActivity.findViewById(R.id.viewlayout_root); 2429 final View mockView = mActivity.findViewById(R.id.mock_view); 2430 2431 mockView.getLocationInWindow(null); 2432 } 2433 2434 @Test(expected=IllegalArgumentException.class) testGetLocationInWindowSmallArray()2435 public void testGetLocationInWindowSmallArray() { 2436 final View layout = mActivity.findViewById(R.id.viewlayout_root); 2437 final View mockView = mActivity.findViewById(R.id.mock_view); 2438 2439 mockView.getLocationInWindow(new int[] { 0 }); 2440 } 2441 2442 @Test testGetLocationOnScreen()2443 public void testGetLocationOnScreen() { 2444 final int[] location = new int[]{-1, -1}; 2445 2446 // mAttachInfo is not null 2447 final View layout = mActivity.findViewById(R.id.viewlayout_root); 2448 final int[] layoutLocation = new int[]{-1, -1}; 2449 layout.getLocationOnScreen(layoutLocation); 2450 2451 final View mockView = mActivity.findViewById(R.id.mock_view); 2452 mockView.getLocationOnScreen(location); 2453 assertEquals(layoutLocation[0], location[0]); 2454 assertEquals(layoutLocation[1], location[1]); 2455 2456 final View scrollView = mActivity.findViewById(R.id.scroll_view); 2457 scrollView.getLocationOnScreen(location); 2458 assertEquals(layoutLocation[0], location[0]); 2459 assertEquals(layoutLocation[1] + mockView.getHeight(), location[1]); 2460 } 2461 2462 @Test(expected=IllegalArgumentException.class) testGetLocationOnScreenNullArray()2463 public void testGetLocationOnScreenNullArray() { 2464 final View scrollView = mActivity.findViewById(R.id.scroll_view); 2465 2466 scrollView.getLocationOnScreen(null); 2467 } 2468 2469 @Test(expected=IllegalArgumentException.class) testGetLocationOnScreenSmallArray()2470 public void testGetLocationOnScreenSmallArray() { 2471 final View scrollView = mActivity.findViewById(R.id.scroll_view); 2472 2473 scrollView.getLocationOnScreen(new int[] { 0 }); 2474 } 2475 2476 @Test testSetAllowClickWhenDisabled()2477 public void testSetAllowClickWhenDisabled() throws Throwable { 2478 MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view); 2479 2480 mActivityRule.runOnUiThread(() -> { 2481 mockView.setClickable(true); 2482 mockView.setEnabled(false); 2483 }); 2484 2485 View.OnClickListener listener = mock(View.OnClickListener.class); 2486 mockView.setOnClickListener(listener); 2487 2488 int[] xy = new int[2]; 2489 mockView.getLocationOnScreen(xy); 2490 2491 final int viewWidth = mockView.getWidth(); 2492 final int viewHeight = mockView.getHeight(); 2493 final float x = xy[0] + viewWidth / 2.0f; 2494 final float y = xy[1] + viewHeight / 2.0f; 2495 2496 long downTime = SystemClock.uptimeMillis(); 2497 long eventTime = SystemClock.uptimeMillis(); 2498 MotionEvent downEvent = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, 2499 x, y, 0); 2500 downTime = SystemClock.uptimeMillis(); 2501 eventTime = SystemClock.uptimeMillis(); 2502 MotionEvent upEvent = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, 2503 x, y, 0); 2504 2505 assertFalse(mockView.hasCalledOnTouchEvent()); 2506 mockView.dispatchTouchEvent(downEvent); 2507 mockView.dispatchTouchEvent(upEvent); 2508 2509 mInstrumentation.waitForIdleSync(); 2510 assertTrue(mockView.hasCalledOnTouchEvent()); 2511 2512 verifyZeroInteractions(listener); 2513 2514 mActivityRule.runOnUiThread(() -> { 2515 mockView.setAllowClickWhenDisabled(true); 2516 }); 2517 2518 downTime = SystemClock.uptimeMillis(); 2519 eventTime = SystemClock.uptimeMillis(); 2520 downEvent = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, 2521 x, y, 0); 2522 downTime = SystemClock.uptimeMillis(); 2523 eventTime = SystemClock.uptimeMillis(); 2524 upEvent = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, 2525 x, y, 0); 2526 2527 mockView.dispatchTouchEvent(downEvent); 2528 mockView.dispatchTouchEvent(upEvent); 2529 2530 mInstrumentation.waitForIdleSync(); 2531 2532 verify(listener, times(1)).onClick(mockView); 2533 } 2534 2535 @Test testAddTouchables()2536 public void testAddTouchables() { 2537 View view = new View(mActivity); 2538 ArrayList<View> result = new ArrayList<>(); 2539 assertEquals(0, result.size()); 2540 2541 view.addTouchables(result); 2542 assertEquals(0, result.size()); 2543 2544 view.setClickable(true); 2545 view.addTouchables(result); 2546 assertEquals(1, result.size()); 2547 assertSame(view, result.get(0)); 2548 2549 try { 2550 view.addTouchables(null); 2551 fail("should throw NullPointerException"); 2552 } catch (NullPointerException e) { 2553 } 2554 2555 result.clear(); 2556 view.setEnabled(false); 2557 assertTrue(view.isClickable()); 2558 view.addTouchables(result); 2559 assertEquals(0, result.size()); 2560 } 2561 2562 @Test testGetTouchables()2563 public void testGetTouchables() { 2564 View view = new View(mActivity); 2565 ArrayList<View> result; 2566 2567 result = view.getTouchables(); 2568 assertEquals(0, result.size()); 2569 2570 view.setClickable(true); 2571 result = view.getTouchables(); 2572 assertEquals(1, result.size()); 2573 assertSame(view, result.get(0)); 2574 2575 result.clear(); 2576 view.setEnabled(false); 2577 assertTrue(view.isClickable()); 2578 result = view.getTouchables(); 2579 assertEquals(0, result.size()); 2580 } 2581 2582 @Test testInflate()2583 public void testInflate() { 2584 View view = View.inflate(mActivity, R.layout.view_layout, null); 2585 assertNotNull(view); 2586 assertTrue(view instanceof LinearLayout); 2587 2588 MockView mockView = (MockView) view.findViewById(R.id.mock_view); 2589 assertNotNull(mockView); 2590 assertTrue(mockView.hasCalledOnFinishInflate()); 2591 } 2592 2593 @Test 2594 @UiThreadTest testIsInTouchMode()2595 public void testIsInTouchMode() { 2596 View detachedView = new View(mActivity); 2597 2598 // mAttachInfo is null, therefore it should return the touch mode default value 2599 Resources resources = mActivity.getResources(); 2600 boolean defaultInTouchMode = resources.getBoolean(resources.getIdentifier( 2601 "config_defaultInTouchMode", "bool", "android")); 2602 assertEquals(defaultInTouchMode, detachedView.isInTouchMode()); 2603 2604 // mAttachInfo is not null 2605 View attachedView = mActivity.findViewById(R.id.fit_windows); 2606 assertFalse(attachedView.isInTouchMode()); 2607 } 2608 2609 @Test testIsInEditMode()2610 public void testIsInEditMode() { 2611 View view = new View(mActivity); 2612 assertFalse(view.isInEditMode()); 2613 } 2614 2615 @Test testPostInvalidate1()2616 public void testPostInvalidate1() { 2617 View view = new View(mActivity); 2618 // mAttachInfo is null 2619 view.postInvalidate(); 2620 2621 // mAttachInfo is not null 2622 view = mActivity.findViewById(R.id.fit_windows); 2623 view.postInvalidate(); 2624 } 2625 2626 @Test testPostInvalidate2()2627 public void testPostInvalidate2() { 2628 View view = new View(mActivity); 2629 // mAttachInfo is null 2630 view.postInvalidate(0, 1, 2, 3); 2631 2632 // mAttachInfo is not null 2633 view = mActivity.findViewById(R.id.fit_windows); 2634 view.postInvalidate(10, 20, 30, 40); 2635 view.postInvalidate(0, -20, -30, -40); 2636 } 2637 2638 @Test testPostInvalidateDelayed()2639 public void testPostInvalidateDelayed() { 2640 View view = new View(mActivity); 2641 // mAttachInfo is null 2642 view.postInvalidateDelayed(1000); 2643 view.postInvalidateDelayed(500, 0, 0, 100, 200); 2644 2645 // mAttachInfo is not null 2646 view = mActivity.findViewById(R.id.fit_windows); 2647 view.postInvalidateDelayed(1000); 2648 view.postInvalidateDelayed(500, 0, 0, 100, 200); 2649 view.postInvalidateDelayed(-1); 2650 } 2651 2652 @Test testPost()2653 public void testPost() { 2654 View view = new View(mActivity); 2655 Runnable action = mock(Runnable.class); 2656 2657 // mAttachInfo is null 2658 assertTrue(view.post(action)); 2659 assertTrue(view.post(null)); 2660 2661 // mAttachInfo is not null 2662 view = mActivity.findViewById(R.id.fit_windows); 2663 assertTrue(view.post(action)); 2664 assertTrue(view.post(null)); 2665 } 2666 2667 @Test testPostDelayed()2668 public void testPostDelayed() { 2669 View view = new View(mActivity); 2670 Runnable action = mock(Runnable.class); 2671 2672 // mAttachInfo is null 2673 assertTrue(view.postDelayed(action, 1000)); 2674 assertTrue(view.postDelayed(null, -1)); 2675 2676 // mAttachInfo is not null 2677 view = mActivity.findViewById(R.id.fit_windows); 2678 assertTrue(view.postDelayed(action, 1000)); 2679 assertTrue(view.postDelayed(null, 0)); 2680 } 2681 2682 @UiThreadTest 2683 @Test testPlaySoundEffect()2684 public void testPlaySoundEffect() { 2685 MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 2686 // sound effect enabled 2687 view.playSoundEffect(SoundEffectConstants.CLICK); 2688 2689 // sound effect disabled 2690 view.setSoundEffectsEnabled(false); 2691 view.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); 2692 2693 // no way to assert the soundConstant be really played. 2694 } 2695 2696 @Test testOnKeyShortcut()2697 public void testOnKeyShortcut() throws Throwable { 2698 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 2699 mActivityRule.runOnUiThread(() -> { 2700 view.setFocusable(true); 2701 view.requestFocus(); 2702 }); 2703 mInstrumentation.waitForIdleSync(); 2704 assertTrue(view.isFocused()); 2705 2706 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU); 2707 mInstrumentation.sendKeySync(event); 2708 event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0); 2709 mInstrumentation.sendKeySync(event); 2710 assertTrue(view.hasCalledOnKeyShortcut()); 2711 } 2712 2713 @Test testOnKeyMultiple()2714 public void testOnKeyMultiple() throws Throwable { 2715 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 2716 mActivityRule.runOnUiThread(() -> view.setFocusable(true)); 2717 2718 assertFalse(view.hasCalledOnKeyMultiple()); 2719 view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_ENTER)); 2720 assertTrue(view.hasCalledOnKeyMultiple()); 2721 } 2722 2723 @UiThreadTest 2724 @Test testDispatchKeyShortcutEvent()2725 public void testDispatchKeyShortcutEvent() { 2726 MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 2727 view.setFocusable(true); 2728 2729 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0); 2730 view.dispatchKeyShortcutEvent(event); 2731 assertTrue(view.hasCalledOnKeyShortcut()); 2732 } 2733 2734 @UiThreadTest 2735 @Test(expected=NullPointerException.class) testDispatchKeyShortcutEventNull()2736 public void testDispatchKeyShortcutEventNull() { 2737 MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 2738 view.setFocusable(true); 2739 2740 view.dispatchKeyShortcutEvent(null); 2741 } 2742 2743 @Test testOnTrackballEvent()2744 public void testOnTrackballEvent() throws Throwable { 2745 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 2746 mActivityRule.runOnUiThread(() -> { 2747 view.setEnabled(true); 2748 view.setFocusable(true); 2749 view.requestFocus(); 2750 }); 2751 mInstrumentation.waitForIdleSync(); 2752 2753 long downTime = SystemClock.uptimeMillis(); 2754 long eventTime = downTime; 2755 MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 2756 1, 2, 0); 2757 event.setDisplayId(mActivity.getDisplayId()); 2758 mInstrumentation.sendTrackballEventSync(event); 2759 mInstrumentation.waitForIdleSync(); 2760 assertTrue(view.hasCalledOnTrackballEvent()); 2761 } 2762 2763 @UiThreadTest 2764 @Test testDispatchTrackballMoveEvent()2765 public void testDispatchTrackballMoveEvent() { 2766 ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 2767 MockView mockView1 = new MockView(mActivity); 2768 MockView mockView2 = new MockView(mActivity); 2769 viewGroup.addView(mockView1); 2770 viewGroup.addView(mockView2); 2771 mockView1.setFocusable(true); 2772 mockView2.setFocusable(true); 2773 mockView2.requestFocus(); 2774 2775 long downTime = SystemClock.uptimeMillis(); 2776 long eventTime = downTime; 2777 MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 2778 1, 2, 0); 2779 mockView1.dispatchTrackballEvent(event); 2780 // issue 1695243 2781 // It passes a trackball motion event down to itself even if it is not the focused view. 2782 assertTrue(mockView1.hasCalledOnTrackballEvent()); 2783 assertFalse(mockView2.hasCalledOnTrackballEvent()); 2784 2785 mockView1.reset(); 2786 mockView2.reset(); 2787 downTime = SystemClock.uptimeMillis(); 2788 eventTime = downTime; 2789 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 1, 2, 0); 2790 mockView2.dispatchTrackballEvent(event); 2791 assertFalse(mockView1.hasCalledOnTrackballEvent()); 2792 assertTrue(mockView2.hasCalledOnTrackballEvent()); 2793 } 2794 2795 @Test testDispatchUnhandledMove()2796 public void testDispatchUnhandledMove() throws Throwable { 2797 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 2798 mActivityRule.runOnUiThread(() -> { 2799 view.setFocusable(true); 2800 view.requestFocus(); 2801 }); 2802 mInstrumentation.waitForIdleSync(); 2803 2804 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT); 2805 mInstrumentation.sendKeySync(event); 2806 2807 assertTrue(view.hasCalledDispatchUnhandledMove()); 2808 } 2809 2810 @Test testUnhandledKeys()2811 public void testUnhandledKeys() throws Throwable { 2812 MockUnhandledKeyListener listener = new MockUnhandledKeyListener(); 2813 ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 2814 // Attaching a fallback handler 2815 TextView mockView1 = new TextView(mActivity); 2816 mockView1.addOnUnhandledKeyEventListener(listener); 2817 2818 // Before the view is attached, it shouldn't respond to anything 2819 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2820 assertFalse(listener.fired()); 2821 2822 // Once attached, it should start receiving fallback events 2823 mActivityRule.runOnUiThread(() -> viewGroup.addView(mockView1)); 2824 mInstrumentation.waitForIdleSync(); 2825 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2826 assertTrue(listener.fired()); 2827 listener.reset(); 2828 2829 // If multiple on one view, last added should receive event first 2830 MockUnhandledKeyListener listener2 = new MockUnhandledKeyListener(); 2831 listener2.mReturnVal = true; 2832 mActivityRule.runOnUiThread(() -> mockView1.addOnUnhandledKeyEventListener(listener2)); 2833 mInstrumentation.waitForIdleSync(); 2834 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2835 assertTrue(listener2.fired()); 2836 assertFalse(listener.fired()); 2837 listener2.reset(); 2838 2839 // If removed, it should not receive fallbacks anymore 2840 mActivityRule.runOnUiThread(() -> { 2841 mockView1.removeOnUnhandledKeyEventListener(listener); 2842 mockView1.removeOnUnhandledKeyEventListener(listener2); 2843 }); 2844 mInstrumentation.waitForIdleSync(); 2845 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2846 assertFalse(listener.fired()); 2847 2848 mActivityRule.runOnUiThread(() -> mActivity.setContentView(R.layout.key_fallback_layout)); 2849 mInstrumentation.waitForIdleSync(); 2850 View higherInNormal = mActivity.findViewById(R.id.higher_in_normal); 2851 View higherGroup = mActivity.findViewById(R.id.higher_group); 2852 View lowerInHigher = mActivity.findViewById(R.id.lower_in_higher); 2853 View lastButton = mActivity.findViewById(R.id.last_button); 2854 View lastInHigher = mActivity.findViewById(R.id.last_in_higher); 2855 View lastInNormal = mActivity.findViewById(R.id.last_in_normal); 2856 2857 View[] allViews = new View[]{higherInNormal, higherGroup, lowerInHigher, lastButton, 2858 lastInHigher, lastInNormal}; 2859 2860 // Test ordering by depth 2861 listener.mReturnVal = true; 2862 mActivityRule.runOnUiThread(() -> { 2863 for (View v : allViews) { 2864 v.addOnUnhandledKeyEventListener(listener); 2865 } 2866 }); 2867 mInstrumentation.waitForIdleSync(); 2868 2869 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2870 assertEquals(lastInHigher, listener.mLastView); 2871 listener.reset(); 2872 2873 mActivityRule.runOnUiThread( 2874 () -> lastInHigher.removeOnUnhandledKeyEventListener(listener)); 2875 mInstrumentation.waitForIdleSync(); 2876 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2877 assertEquals(lowerInHigher, listener.mLastView); 2878 listener.reset(); 2879 2880 mActivityRule.runOnUiThread( 2881 () -> lowerInHigher.removeOnUnhandledKeyEventListener(listener)); 2882 mInstrumentation.waitForIdleSync(); 2883 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2884 assertEquals(higherGroup, listener.mLastView); 2885 listener.reset(); 2886 2887 mActivityRule.runOnUiThread(() -> higherGroup.removeOnUnhandledKeyEventListener(listener)); 2888 mInstrumentation.waitForIdleSync(); 2889 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2890 assertEquals(lastButton, listener.mLastView); 2891 listener.reset(); 2892 2893 mActivityRule.runOnUiThread(() -> lastButton.removeOnUnhandledKeyEventListener(listener)); 2894 mInstrumentation.waitForIdleSync(); 2895 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2896 assertEquals(higherInNormal, listener.mLastView); 2897 listener.reset(); 2898 2899 mActivityRule.runOnUiThread( 2900 () -> higherInNormal.removeOnUnhandledKeyEventListener(listener)); 2901 mInstrumentation.waitForIdleSync(); 2902 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2903 assertEquals(lastInNormal, listener.mLastView); 2904 listener.reset(); 2905 2906 // Test "capture" 2907 mActivityRule.runOnUiThread(() -> lastInNormal.requestFocus()); 2908 mInstrumentation.waitForIdleSync(); 2909 lastInNormal.setOnKeyListener((v, keyCode, event) 2910 -> (keyCode == KeyEvent.KEYCODE_B && event.getAction() == KeyEvent.ACTION_UP)); 2911 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_B); 2912 assertTrue(listener.fired()); // checks that both up and down were received 2913 listener.reset(); 2914 } 2915 2916 @Test testWindowVisibilityChanged()2917 public void testWindowVisibilityChanged() throws Throwable { 2918 final MockView mockView = new MockView(mActivity); 2919 final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 2920 2921 mActivityRule.runOnUiThread(() -> viewGroup.addView(mockView)); 2922 mInstrumentation.waitForIdleSync(); 2923 assertTrue(mockView.hasCalledOnWindowVisibilityChanged()); 2924 2925 mockView.reset(); 2926 mActivityRule.runOnUiThread(() -> mActivity.setVisible(false)); 2927 mInstrumentation.waitForIdleSync(); 2928 assertTrue(mockView.hasCalledDispatchWindowVisibilityChanged()); 2929 assertTrue(mockView.hasCalledOnWindowVisibilityChanged()); 2930 2931 mockView.reset(); 2932 mActivityRule.runOnUiThread(() -> mActivity.setVisible(true)); 2933 mInstrumentation.waitForIdleSync(); 2934 assertTrue(mockView.hasCalledDispatchWindowVisibilityChanged()); 2935 assertTrue(mockView.hasCalledOnWindowVisibilityChanged()); 2936 2937 mockView.reset(); 2938 mActivityRule.runOnUiThread(() -> viewGroup.removeView(mockView)); 2939 mInstrumentation.waitForIdleSync(); 2940 assertTrue(mockView.hasCalledOnWindowVisibilityChanged()); 2941 } 2942 2943 @Test testGetLocalVisibleRect()2944 public void testGetLocalVisibleRect() throws Throwable { 2945 final View view = mActivity.findViewById(R.id.mock_view); 2946 Rect rect = new Rect(); 2947 2948 float density = view.getContext().getResources().getDisplayMetrics().density; 2949 int size1 = (int) (75 * density + 0.5); 2950 int size2 = (int) (100 * density + 0.5); 2951 2952 assertTrue(view.getLocalVisibleRect(rect)); 2953 assertEquals(0, rect.left); 2954 assertEquals(0, rect.top); 2955 assertEquals(size1, rect.right); 2956 assertEquals(size2, rect.bottom); 2957 2958 final LinearLayout.LayoutParams layoutParams1 = new LinearLayout.LayoutParams(0, 300); 2959 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams1)); 2960 mInstrumentation.waitForIdleSync(); 2961 assertFalse(view.getLocalVisibleRect(rect)); 2962 2963 final LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(200, -10); 2964 mActivityRule.runOnUiThread(() -> view.setLayoutParams(layoutParams2)); 2965 mInstrumentation.waitForIdleSync(); 2966 assertFalse(view.getLocalVisibleRect(rect)); 2967 2968 Display display = mActivity.getWindowManager().getDefaultDisplay(); 2969 int halfWidth = display.getWidth() / 2; 2970 int halfHeight = display.getHeight() /2; 2971 2972 final LinearLayout.LayoutParams layoutParams3 = 2973 new LinearLayout.LayoutParams(halfWidth, halfHeight); 2974 mActivityRule.runOnUiThread(() -> { 2975 view.setLayoutParams(layoutParams3); 2976 view.scrollTo(20, -30); 2977 }); 2978 mInstrumentation.waitForIdleSync(); 2979 assertTrue(view.getLocalVisibleRect(rect)); 2980 assertEquals(20, rect.left); 2981 assertEquals(-30, rect.top); 2982 assertEquals(halfWidth + 20, rect.right); 2983 assertEquals(halfHeight - 30, rect.bottom); 2984 2985 try { 2986 view.getLocalVisibleRect(null); 2987 fail("should throw NullPointerException"); 2988 } catch (NullPointerException e) { 2989 } 2990 } 2991 2992 @Test testMergeDrawableStates()2993 public void testMergeDrawableStates() { 2994 MockView view = new MockView(mActivity); 2995 2996 int[] states = view.mergeDrawableStatesWrapper(new int[] { 0, 1, 2, 0, 0 }, 2997 new int[] { 3 }); 2998 assertNotNull(states); 2999 assertEquals(5, states.length); 3000 assertEquals(0, states[0]); 3001 assertEquals(1, states[1]); 3002 assertEquals(2, states[2]); 3003 assertEquals(3, states[3]); 3004 assertEquals(0, states[4]); 3005 3006 try { 3007 view.mergeDrawableStatesWrapper(new int[] { 1, 2 }, new int[] { 3 }); 3008 fail("should throw IndexOutOfBoundsException"); 3009 } catch (IndexOutOfBoundsException e) { 3010 } 3011 3012 try { 3013 view.mergeDrawableStatesWrapper(null, new int[] { 0 }); 3014 fail("should throw NullPointerException"); 3015 } catch (NullPointerException e) { 3016 } 3017 3018 try { 3019 view.mergeDrawableStatesWrapper(new int [] { 0 }, null); 3020 fail("should throw NullPointerException"); 3021 } catch (NullPointerException e) { 3022 } 3023 } 3024 3025 @Test testSaveAndRestoreHierarchyState()3026 public void testSaveAndRestoreHierarchyState() { 3027 int viewId = R.id.mock_view; 3028 MockView view = (MockView) mActivity.findViewById(viewId); 3029 SparseArray<Parcelable> container = new SparseArray<>(); 3030 view.saveHierarchyState(container); 3031 assertTrue(view.hasCalledDispatchSaveInstanceState()); 3032 assertTrue(view.hasCalledOnSaveInstanceState()); 3033 assertEquals(viewId, container.keyAt(0)); 3034 3035 view.reset(); 3036 container.put(R.id.mock_view, BaseSavedState.EMPTY_STATE); 3037 view.restoreHierarchyState(container); 3038 assertTrue(view.hasCalledDispatchRestoreInstanceState()); 3039 assertTrue(view.hasCalledOnRestoreInstanceState()); 3040 container.clear(); 3041 view.saveHierarchyState(container); 3042 assertTrue(view.hasCalledDispatchSaveInstanceState()); 3043 assertTrue(view.hasCalledOnSaveInstanceState()); 3044 assertEquals(viewId, container.keyAt(0)); 3045 3046 container.clear(); 3047 container.put(viewId, new android.graphics.Rect()); 3048 try { 3049 view.restoreHierarchyState(container); 3050 fail("Parcelable state must be an AbsSaveState, should throw IllegalArgumentException"); 3051 } catch (IllegalArgumentException e) { 3052 // expected 3053 } 3054 3055 try { 3056 view.restoreHierarchyState(null); 3057 fail("Cannot pass null to restoreHierarchyState(), should throw NullPointerException"); 3058 } catch (NullPointerException e) { 3059 // expected 3060 } 3061 3062 try { 3063 view.saveHierarchyState(null); 3064 fail("Cannot pass null to saveHierarchyState(), should throw NullPointerException"); 3065 } catch (NullPointerException e) { 3066 // expected 3067 } 3068 } 3069 3070 @Test testOnKeyDownOrUp()3071 public void testOnKeyDownOrUp() throws Throwable { 3072 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 3073 mActivityRule.runOnUiThread(() -> { 3074 view.setFocusable(true); 3075 view.requestFocus(); 3076 }); 3077 mInstrumentation.waitForIdleSync(); 3078 assertTrue(view.isFocused()); 3079 3080 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0); 3081 mInstrumentation.sendKeySync(event); 3082 assertTrue(view.hasCalledOnKeyDown()); 3083 3084 event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0); 3085 mInstrumentation.sendKeySync(event); 3086 assertTrue(view.hasCalledOnKeyUp()); 3087 3088 view.reset(); 3089 assertTrue(view.isEnabled()); 3090 assertFalse(view.isClickable()); 3091 assertFalse(view.isPressed()); 3092 event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER); 3093 mInstrumentation.sendKeySync(event); 3094 assertFalse(view.isPressed()); 3095 assertTrue(view.hasCalledOnKeyDown()); 3096 3097 mActivityRule.runOnUiThread(() -> { 3098 view.setEnabled(true); 3099 view.setClickable(true); 3100 }); 3101 view.reset(); 3102 View.OnClickListener listener = mock(View.OnClickListener.class); 3103 view.setOnClickListener(listener); 3104 3105 assertFalse(view.isPressed()); 3106 event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER); 3107 mInstrumentation.sendKeySync(event); 3108 assertTrue(view.isPressed()); 3109 assertTrue(view.hasCalledOnKeyDown()); 3110 event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER); 3111 mInstrumentation.sendKeySync(event); 3112 assertFalse(view.isPressed()); 3113 assertTrue(view.hasCalledOnKeyUp()); 3114 verify(listener, times(1)).onClick(view); 3115 3116 view.setPressed(false); 3117 reset(listener); 3118 view.reset(); 3119 3120 assertFalse(view.isPressed()); 3121 event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER); 3122 mInstrumentation.sendKeySync(event); 3123 assertTrue(view.isPressed()); 3124 assertTrue(view.hasCalledOnKeyDown()); 3125 event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER); 3126 mInstrumentation.sendKeySync(event); 3127 assertFalse(view.isPressed()); 3128 assertTrue(view.hasCalledOnKeyUp()); 3129 verify(listener, times(1)).onClick(view); 3130 } 3131 checkBounds(final ViewGroup viewGroup, final View view, final CountDownLatch countDownLatch, final int left, final int top, final int width, final int height)3132 private void checkBounds(final ViewGroup viewGroup, final View view, 3133 final CountDownLatch countDownLatch, final int left, final int top, 3134 final int width, final int height) { 3135 viewGroup.getViewTreeObserver().addOnPreDrawListener( 3136 new ViewTreeObserver.OnPreDrawListener() { 3137 @Override 3138 public boolean onPreDraw() { 3139 assertEquals(left, view.getLeft()); 3140 assertEquals(top, view.getTop()); 3141 assertEquals(width, view.getWidth()); 3142 assertEquals(height, view.getHeight()); 3143 countDownLatch.countDown(); 3144 viewGroup.getViewTreeObserver().removeOnPreDrawListener(this); 3145 return true; 3146 } 3147 }); 3148 } 3149 3150 @Test testAddRemoveAffectsWrapContentLayout()3151 public void testAddRemoveAffectsWrapContentLayout() throws Throwable { 3152 final int childWidth = 100; 3153 final int childHeight = 200; 3154 final int parentHeight = 400; 3155 final LinearLayout parent = new LinearLayout(mActivity); 3156 ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams( 3157 ViewGroup.LayoutParams.WRAP_CONTENT, parentHeight); 3158 parent.setLayoutParams(parentParams); 3159 final MockView child = new MockView(mActivity); 3160 child.setBackgroundColor(Color.GREEN); 3161 ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight); 3162 child.setLayoutParams(childParams); 3163 final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 3164 3165 // Idea: 3166 // Add the wrap_content parent view to the hierarchy (removing other views as they 3167 // are not needed), test that parent is 0xparentHeight 3168 // Add the child view to the parent, test that parent has same width as child 3169 // Remove the child view from the parent, test that parent is 0xparentHeight 3170 final CountDownLatch countDownLatch1 = new CountDownLatch(1); 3171 mActivityRule.runOnUiThread(() -> { 3172 viewGroup.removeAllViews(); 3173 viewGroup.addView(parent); 3174 checkBounds(viewGroup, parent, countDownLatch1, 0, 0, 0, parentHeight); 3175 }); 3176 countDownLatch1.await(500, TimeUnit.MILLISECONDS); 3177 3178 final CountDownLatch countDownLatch2 = new CountDownLatch(1); 3179 mActivityRule.runOnUiThread(() -> { 3180 parent.addView(child); 3181 checkBounds(viewGroup, parent, countDownLatch2, 0, 0, childWidth, parentHeight); 3182 }); 3183 countDownLatch2.await(500, TimeUnit.MILLISECONDS); 3184 3185 final CountDownLatch countDownLatch3 = new CountDownLatch(1); 3186 mActivityRule.runOnUiThread(() -> { 3187 parent.removeView(child); 3188 checkBounds(viewGroup, parent, countDownLatch3, 0, 0, 0, parentHeight); 3189 }); 3190 countDownLatch3.await(500, TimeUnit.MILLISECONDS); 3191 } 3192 3193 @UiThreadTest 3194 @Test testDispatchKeyEvent()3195 public void testDispatchKeyEvent() { 3196 MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 3197 MockView mockView1 = new MockView(mActivity); 3198 MockView mockView2 = new MockView(mActivity); 3199 ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 3200 viewGroup.addView(mockView1); 3201 viewGroup.addView(mockView2); 3202 view.setFocusable(true); 3203 mockView1.setFocusable(true); 3204 mockView2.setFocusable(true); 3205 3206 assertFalse(view.hasCalledOnKeyDown()); 3207 assertFalse(mockView1.hasCalledOnKeyDown()); 3208 assertFalse(mockView2.hasCalledOnKeyDown()); 3209 KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0); 3210 assertFalse(view.dispatchKeyEvent(event)); 3211 assertTrue(view.hasCalledOnKeyDown()); 3212 assertFalse(mockView1.hasCalledOnKeyDown()); 3213 assertFalse(mockView2.hasCalledOnKeyDown()); 3214 3215 view.reset(); 3216 mockView1.reset(); 3217 mockView2.reset(); 3218 assertFalse(view.hasCalledOnKeyDown()); 3219 assertFalse(mockView1.hasCalledOnKeyDown()); 3220 assertFalse(mockView2.hasCalledOnKeyDown()); 3221 event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0); 3222 assertFalse(mockView1.dispatchKeyEvent(event)); 3223 assertFalse(view.hasCalledOnKeyDown()); 3224 // issue 1695243 3225 // When the view has NOT focus, it dispatches to itself, which disobey the javadoc. 3226 assertTrue(mockView1.hasCalledOnKeyDown()); 3227 assertFalse(mockView2.hasCalledOnKeyDown()); 3228 3229 assertFalse(view.hasCalledOnKeyUp()); 3230 event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0); 3231 assertFalse(view.dispatchKeyEvent(event)); 3232 assertTrue(view.hasCalledOnKeyUp()); 3233 3234 assertFalse(view.hasCalledOnKeyMultiple()); 3235 event = new KeyEvent(1, 2, KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_0, 2); 3236 assertFalse(view.dispatchKeyEvent(event)); 3237 assertTrue(view.hasCalledOnKeyMultiple()); 3238 3239 try { 3240 view.dispatchKeyEvent(null); 3241 fail("should throw NullPointerException"); 3242 } catch (NullPointerException e) { 3243 // expected 3244 } 3245 3246 view.reset(); 3247 event = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_0); 3248 View.OnKeyListener listener = mock(View.OnKeyListener.class); 3249 doReturn(true).when(listener).onKey(any(), anyInt(), any()); 3250 view.setOnKeyListener(listener); 3251 verifyZeroInteractions(listener); 3252 assertTrue(view.dispatchKeyEvent(event)); 3253 ArgumentCaptor<KeyEvent> keyEventCaptor = ArgumentCaptor.forClass(KeyEvent.class); 3254 verify(listener, times(1)).onKey(eq(view), eq(KeyEvent.KEYCODE_0), 3255 keyEventCaptor.capture()); 3256 assertEquals(KeyEvent.ACTION_UP, keyEventCaptor.getValue().getAction()); 3257 assertEquals(KeyEvent.KEYCODE_0, keyEventCaptor.getValue().getKeyCode()); 3258 assertFalse(view.hasCalledOnKeyUp()); 3259 } 3260 3261 @UiThreadTest 3262 @Test testDispatchTouchEvent()3263 public void testDispatchTouchEvent() { 3264 ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 3265 MockView mockView1 = new MockView(mActivity); 3266 MockView mockView2 = new MockView(mActivity); 3267 viewGroup.addView(mockView1); 3268 viewGroup.addView(mockView2); 3269 3270 int[] xy = new int[2]; 3271 mockView1.getLocationOnScreen(xy); 3272 3273 final int viewWidth = mockView1.getWidth(); 3274 final int viewHeight = mockView1.getHeight(); 3275 final float x = xy[0] + viewWidth / 2.0f; 3276 final float y = xy[1] + viewHeight / 2.0f; 3277 3278 long downTime = SystemClock.uptimeMillis(); 3279 long eventTime = SystemClock.uptimeMillis(); 3280 MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, 3281 x, y, 0); 3282 3283 assertFalse(mockView1.hasCalledOnTouchEvent()); 3284 assertFalse(mockView1.dispatchTouchEvent(event)); 3285 assertTrue(mockView1.hasCalledOnTouchEvent()); 3286 3287 assertFalse(mockView2.hasCalledOnTouchEvent()); 3288 assertFalse(mockView2.dispatchTouchEvent(event)); 3289 // issue 1695243 3290 // it passes the touch screen motion event down to itself even if it is not the target view. 3291 assertTrue(mockView2.hasCalledOnTouchEvent()); 3292 3293 mockView1.reset(); 3294 View.OnTouchListener listener = mock(View.OnTouchListener.class); 3295 doReturn(true).when(listener).onTouch(any(), any()); 3296 mockView1.setOnTouchListener(listener); 3297 verifyZeroInteractions(listener); 3298 assertTrue(mockView1.dispatchTouchEvent(event)); 3299 verify(listener, times(1)).onTouch(mockView1, event); 3300 assertFalse(mockView1.hasCalledOnTouchEvent()); 3301 } 3302 3303 /** 3304 * Ensure two MotionEvents are equal, for the purposes of this test only. 3305 * Only compare actions, source, and times. 3306 * Do not compare coordinates, because the injected event has coordinates relative to 3307 * the screen, while the event received by view will be adjusted relative to the parent. 3308 * 3309 * Due to event batching, if two or more input events are injected / occur between two 3310 * consecutive vsync's, they might end up getting combined into a single MotionEvent. 3311 * It is caller's responsibility to ensure that the events were injected with a gap that's 3312 * larger than time between two vsyncs, in order for this function to behave predictably. 3313 * 3314 * Recycle both MotionEvents. 3315 */ compareAndRecycleMotionEvents(MotionEvent event1, MotionEvent event2)3316 private static void compareAndRecycleMotionEvents(MotionEvent event1, MotionEvent event2) { 3317 if (event1 == null && event2 == null) { 3318 return; 3319 } 3320 3321 if (event1 == null) { 3322 event2.recycle(); 3323 fail("Expected non-null event in first position"); 3324 } 3325 if (event2 == null) { 3326 event1.recycle(); 3327 fail("Expected non-null event in second position"); 3328 } 3329 3330 assertEquals(event1.getAction(), event2.getAction()); 3331 assertEquals(event1.getPointerCount(), event2.getPointerCount()); 3332 assertEquals(event1.getSource(), event2.getSource()); 3333 assertEquals(event1.getDownTime(), event2.getDownTime()); 3334 // If resampling occurs, the "real" (injected) events will become historical data, 3335 // and resampled events will be inserted into MotionEvent and returned by the standard api. 3336 // Since the injected event should contain no history, but the event received by 3337 // the view might, we could distinguish them. But for simplicity, only require that 3338 // the events are close in time if historical data is present. 3339 if (event1.getHistorySize() == 0 && event2.getHistorySize() == 0) { 3340 assertEquals(event1.getEventTime(), event2.getEventTime()); 3341 } else { 3342 assertEquals(event1.getEventTime(), event2.getEventTime(), 20 /*delta*/); 3343 } 3344 3345 event1.recycle(); 3346 event2.recycle(); 3347 } 3348 3349 @Test testOnTouchListener()3350 public void testOnTouchListener() { 3351 BlockingQueue<MotionEvent> events = new LinkedBlockingQueue<>(); 3352 class TestTouchListener implements View.OnTouchListener { 3353 @Override 3354 public boolean onTouch(View v, MotionEvent event) { 3355 events.add(MotionEvent.obtain(event)); 3356 return true; 3357 } 3358 } 3359 3360 // Inject some touch events 3361 TestTouchListener listener = new TestTouchListener(); 3362 View view = mActivity.findViewById(R.id.mock_view); 3363 view.setOnTouchListener(listener); 3364 3365 int[] xy = new int[2]; 3366 view.getLocationOnScreen(xy); 3367 3368 final int viewWidth = view.getWidth(); 3369 final int viewHeight = view.getHeight(); 3370 final float x = xy[0] + viewWidth / 2.0f; 3371 final float y = xy[1] + viewHeight / 2.0f; 3372 3373 final long downTime = SystemClock.uptimeMillis(); 3374 MotionEvent downEvent = 3375 MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0); 3376 downEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); 3377 downEvent.setDisplayId(mActivity.getDisplayId()); 3378 mInstrumentation.sendPointerSync(downEvent); 3379 final long eventTime = SystemClock.uptimeMillis(); 3380 MotionEvent upEvent = 3381 MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 3382 upEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); 3383 upEvent.setDisplayId(mActivity.getDisplayId()); 3384 mInstrumentation.sendPointerSync(upEvent); 3385 3386 compareAndRecycleMotionEvents(downEvent, events.poll()); 3387 compareAndRecycleMotionEvents(upEvent, events.poll()); 3388 assertTrue(events.isEmpty()); 3389 } 3390 3391 @Test testInvalidate1()3392 public void testInvalidate1() throws Throwable { 3393 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 3394 assertTrue(view.hasCalledOnDraw()); 3395 3396 view.reset(); 3397 mActivityRule.runOnUiThread(view::invalidate); 3398 mInstrumentation.waitForIdleSync(); 3399 PollingCheck.waitFor(view::hasCalledOnDraw); 3400 3401 view.reset(); 3402 mActivityRule.runOnUiThread(() -> { 3403 view.setVisibility(View.INVISIBLE); 3404 view.invalidate(); 3405 }); 3406 mInstrumentation.waitForIdleSync(); 3407 assertFalse(view.hasCalledOnDraw()); 3408 } 3409 3410 @Test testInvalidate2()3411 public void testInvalidate2() throws Throwable { 3412 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 3413 assertTrue(view.hasCalledOnDraw()); 3414 3415 try { 3416 view.invalidate(null); 3417 fail("should throw NullPointerException"); 3418 } catch (NullPointerException e) { 3419 } 3420 3421 view.reset(); 3422 final Rect dirty = new Rect(view.getLeft() + 1, view.getTop() + 1, 3423 view.getLeft() + view.getWidth() / 2, view.getTop() + view.getHeight() / 2); 3424 mActivityRule.runOnUiThread(() -> view.invalidate(dirty)); 3425 mInstrumentation.waitForIdleSync(); 3426 PollingCheck.waitFor(view::hasCalledOnDraw); 3427 3428 view.reset(); 3429 mActivityRule.runOnUiThread(() -> { 3430 view.setVisibility(View.INVISIBLE); 3431 view.invalidate(dirty); 3432 }); 3433 mInstrumentation.waitForIdleSync(); 3434 assertFalse(view.hasCalledOnDraw()); 3435 } 3436 3437 @Test testInvalidate3()3438 public void testInvalidate3() throws Throwable { 3439 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 3440 assertTrue(view.hasCalledOnDraw()); 3441 3442 view.reset(); 3443 final Rect dirty = new Rect(view.getLeft() + 1, view.getTop() + 1, 3444 view.getLeft() + view.getWidth() / 2, view.getTop() + view.getHeight() / 2); 3445 mActivityRule.runOnUiThread( 3446 () -> view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom)); 3447 mInstrumentation.waitForIdleSync(); 3448 PollingCheck.waitFor(view::hasCalledOnDraw); 3449 3450 view.reset(); 3451 mActivityRule.runOnUiThread(() -> { 3452 view.setVisibility(View.INVISIBLE); 3453 view.invalidate(dirty.left, dirty.top, dirty.right, dirty.bottom); 3454 }); 3455 mInstrumentation.waitForIdleSync(); 3456 assertFalse(view.hasCalledOnDraw()); 3457 } 3458 3459 @Test testInvalidateDrawable()3460 public void testInvalidateDrawable() throws Throwable { 3461 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 3462 final Drawable d1 = mResources.getDrawable(R.drawable.scenery); 3463 final Drawable d2 = mResources.getDrawable(R.drawable.pass); 3464 3465 view.reset(); 3466 mActivityRule.runOnUiThread(() -> { 3467 view.setBackgroundDrawable(d1); 3468 view.invalidateDrawable(d1); 3469 }); 3470 mInstrumentation.waitForIdleSync(); 3471 PollingCheck.waitFor(view::hasCalledOnDraw); 3472 3473 view.reset(); 3474 mActivityRule.runOnUiThread(() -> view.invalidateDrawable(d2)); 3475 mInstrumentation.waitForIdleSync(); 3476 assertFalse(view.hasCalledOnDraw()); 3477 3478 MockView viewTestNull = new MockView(mActivity); 3479 try { 3480 viewTestNull.invalidateDrawable(null); 3481 fail("should throw NullPointerException"); 3482 } catch (NullPointerException e) { 3483 } 3484 } 3485 3486 @UiThreadTest 3487 @Test testOnFocusChanged()3488 public void testOnFocusChanged() { 3489 MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 3490 3491 mActivity.findViewById(R.id.fit_windows).setFocusable(true); 3492 view.setFocusable(true); 3493 assertFalse(view.hasCalledOnFocusChanged()); 3494 3495 view.requestFocus(); 3496 assertTrue(view.hasCalledOnFocusChanged()); 3497 3498 view.reset(); 3499 view.clearFocus(); 3500 assertTrue(view.hasCalledOnFocusChanged()); 3501 } 3502 3503 @UiThreadTest 3504 @Test testRestoreDefaultFocus()3505 public void testRestoreDefaultFocus() { 3506 MockView view = new MockView(mActivity); 3507 view.restoreDefaultFocus(); 3508 assertTrue(view.hasCalledRequestFocus()); 3509 } 3510 3511 @Test testDrawableState()3512 public void testDrawableState() { 3513 MockView view = new MockView(mActivity); 3514 view.setParent(mMockParent); 3515 3516 assertFalse(view.hasCalledOnCreateDrawableState()); 3517 assertTrue(Arrays.equals(MockView.getEnabledStateSet(), view.getDrawableState())); 3518 assertTrue(view.hasCalledOnCreateDrawableState()); 3519 3520 view.reset(); 3521 assertFalse(view.hasCalledOnCreateDrawableState()); 3522 assertTrue(Arrays.equals(MockView.getEnabledStateSet(), view.getDrawableState())); 3523 assertFalse(view.hasCalledOnCreateDrawableState()); 3524 3525 view.reset(); 3526 assertFalse(view.hasCalledDrawableStateChanged()); 3527 view.setPressed(true); 3528 assertTrue(view.hasCalledDrawableStateChanged()); 3529 assertTrue(Arrays.equals(MockView.getPressedEnabledStateSet(), view.getDrawableState())); 3530 assertTrue(view.hasCalledOnCreateDrawableState()); 3531 3532 view.reset(); 3533 mMockParent.reset(); 3534 assertFalse(view.hasCalledDrawableStateChanged()); 3535 assertFalse(mMockParent.hasChildDrawableStateChanged()); 3536 view.refreshDrawableState(); 3537 assertTrue(view.hasCalledDrawableStateChanged()); 3538 assertTrue(mMockParent.hasChildDrawableStateChanged()); 3539 assertTrue(Arrays.equals(MockView.getPressedEnabledStateSet(), view.getDrawableState())); 3540 assertTrue(view.hasCalledOnCreateDrawableState()); 3541 } 3542 3543 @Test testWindowFocusChanged()3544 public void testWindowFocusChanged() { 3545 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 3546 3547 // Wait until the window has been focused. 3548 PollingCheck.waitFor(TIMEOUT_DELTA, view::hasWindowFocus); 3549 3550 PollingCheck.waitFor(view::hasCalledOnWindowFocusChanged); 3551 3552 assertTrue(view.hasCalledOnWindowFocusChanged()); 3553 assertTrue(view.hasCalledDispatchWindowFocusChanged()); 3554 3555 view.reset(); 3556 assertFalse(view.hasCalledOnWindowFocusChanged()); 3557 assertFalse(view.hasCalledDispatchWindowFocusChanged()); 3558 3559 CtsActivity activity = mCtsActivityRule.launchActivity(null); 3560 3561 // Wait until the window lost focus. 3562 PollingCheck.waitFor(TIMEOUT_DELTA, () -> !view.hasWindowFocus()); 3563 3564 assertTrue(view.hasCalledOnWindowFocusChanged()); 3565 assertTrue(view.hasCalledDispatchWindowFocusChanged()); 3566 3567 activity.finish(); 3568 } 3569 3570 @Test testDraw()3571 public void testDraw() throws Throwable { 3572 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 3573 mActivityRule.runOnUiThread(view::requestLayout); 3574 mInstrumentation.waitForIdleSync(); 3575 3576 assertTrue(view.hasCalledOnDraw()); 3577 assertTrue(view.hasCalledDispatchDraw()); 3578 } 3579 3580 @Test 3581 @UiThreadTest testRequestFocusFromTouch()3582 public void testRequestFocusFromTouch() { 3583 View view = new View(mActivity); 3584 mActivity.setContentView(view); 3585 3586 view.setFocusable(true); 3587 assertFalse(view.isFocused()); 3588 3589 view.requestFocusFromTouch(); 3590 assertTrue(view.isFocused()); 3591 3592 view.requestFocusFromTouch(); 3593 assertTrue(view.isFocused()); 3594 } 3595 3596 @Test testRequestRectangleOnScreen1()3597 public void testRequestRectangleOnScreen1() { 3598 MockView view = new MockView(mActivity); 3599 Rect rectangle = new Rect(10, 10, 20, 30); 3600 MockViewGroupParent parent = new MockViewGroupParent(mActivity); 3601 3602 // parent is null 3603 assertFalse(view.requestRectangleOnScreen(rectangle, true)); 3604 assertFalse(view.requestRectangleOnScreen(rectangle, false)); 3605 assertFalse(view.requestRectangleOnScreen(null, true)); 3606 3607 view.setParent(parent); 3608 view.scrollTo(1, 2); 3609 assertFalse(parent.hasRequestChildRectangleOnScreen()); 3610 3611 assertFalse(view.requestRectangleOnScreen(rectangle, true)); 3612 assertTrue(parent.hasRequestChildRectangleOnScreen()); 3613 3614 parent.reset(); 3615 view.scrollTo(11, 22); 3616 assertFalse(parent.hasRequestChildRectangleOnScreen()); 3617 3618 assertFalse(view.requestRectangleOnScreen(rectangle, true)); 3619 assertTrue(parent.hasRequestChildRectangleOnScreen()); 3620 3621 try { 3622 view.requestRectangleOnScreen(null, true); 3623 fail("should throw NullPointerException"); 3624 } catch (NullPointerException e) { 3625 } 3626 } 3627 3628 @Test testRequestRectangleOnScreen2()3629 public void testRequestRectangleOnScreen2() { 3630 MockView view = new MockView(mActivity); 3631 Rect rectangle = new Rect(); 3632 MockViewGroupParent parent = new MockViewGroupParent(mActivity); 3633 3634 MockViewGroupParent grandparent = new MockViewGroupParent(mActivity); 3635 3636 // parent is null 3637 assertFalse(view.requestRectangleOnScreen(rectangle)); 3638 assertFalse(view.requestRectangleOnScreen(null)); 3639 assertEquals(0, rectangle.left); 3640 assertEquals(0, rectangle.top); 3641 assertEquals(0, rectangle.right); 3642 assertEquals(0, rectangle.bottom); 3643 3644 parent.addView(view); 3645 parent.scrollTo(1, 2); 3646 grandparent.addView(parent); 3647 3648 assertFalse(parent.hasRequestChildRectangleOnScreen()); 3649 assertFalse(grandparent.hasRequestChildRectangleOnScreen()); 3650 3651 assertFalse(view.requestRectangleOnScreen(rectangle)); 3652 3653 assertTrue(parent.hasRequestChildRectangleOnScreen()); 3654 assertTrue(grandparent.hasRequestChildRectangleOnScreen()); 3655 3656 // it is grand parent's responsibility to check parent's scroll offset 3657 final Rect requestedRect = grandparent.getLastRequestedChildRectOnScreen(); 3658 assertEquals(0, requestedRect.left); 3659 assertEquals(0, requestedRect.top); 3660 assertEquals(0, requestedRect.right); 3661 assertEquals(0, requestedRect.bottom); 3662 3663 try { 3664 view.requestRectangleOnScreen(null); 3665 fail("should throw NullPointerException"); 3666 } catch (NullPointerException e) { 3667 } 3668 } 3669 3670 @Test testRequestRectangleOnScreen3()3671 public void testRequestRectangleOnScreen3() { 3672 requestRectangleOnScreenTest(false); 3673 } 3674 3675 @Test testRequestRectangleOnScreen4()3676 public void testRequestRectangleOnScreen4() { 3677 requestRectangleOnScreenTest(true); 3678 } 3679 3680 @Test testRequestRectangleOnScreen5()3681 public void testRequestRectangleOnScreen5() { 3682 MockView child = new MockView(mActivity); 3683 3684 MockViewGroupParent parent = new MockViewGroupParent(mActivity); 3685 MockViewGroupParent grandParent = new MockViewGroupParent(mActivity); 3686 parent.addView(child); 3687 grandParent.addView(parent); 3688 3689 child.layout(5, 6, 7, 9); 3690 child.requestRectangleOnScreen(new Rect(10, 10, 12, 13)); 3691 assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen()); 3692 assertEquals(new Rect(15, 16, 17, 19), grandParent.getLastRequestedChildRectOnScreen()); 3693 3694 child.scrollBy(1, 2); 3695 child.requestRectangleOnScreen(new Rect(10, 10, 12, 13)); 3696 assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen()); 3697 assertEquals(new Rect(14, 14, 16, 17), grandParent.getLastRequestedChildRectOnScreen()); 3698 } 3699 requestRectangleOnScreenTest(boolean scrollParent)3700 private void requestRectangleOnScreenTest(boolean scrollParent) { 3701 MockView child = new MockView(mActivity); 3702 3703 MockViewGroupParent parent = new MockViewGroupParent(mActivity); 3704 MockViewGroupParent grandParent = new MockViewGroupParent(mActivity); 3705 parent.addView(child); 3706 grandParent.addView(parent); 3707 3708 child.requestRectangleOnScreen(new Rect(10, 10, 12, 13)); 3709 assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen()); 3710 assertEquals(new Rect(10, 10, 12, 13), grandParent.getLastRequestedChildRectOnScreen()); 3711 3712 child.scrollBy(1, 2); 3713 if (scrollParent) { 3714 // should not affect anything 3715 parent.scrollBy(25, 30); 3716 parent.layout(3, 5, 7, 9); 3717 } 3718 child.requestRectangleOnScreen(new Rect(10, 10, 12, 13)); 3719 assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen()); 3720 assertEquals(new Rect(9, 8, 11, 11), grandParent.getLastRequestedChildRectOnScreen()); 3721 } 3722 3723 @Test testRequestRectangleOnScreenWithScale()3724 public void testRequestRectangleOnScreenWithScale() { 3725 // scale should not affect the rectangle 3726 MockView child = new MockView(mActivity); 3727 child.setScaleX(2); 3728 child.setScaleX(3); 3729 MockViewGroupParent parent = new MockViewGroupParent(mActivity); 3730 MockViewGroupParent grandParent = new MockViewGroupParent(mActivity); 3731 parent.addView(child); 3732 grandParent.addView(parent); 3733 child.requestRectangleOnScreen(new Rect(10, 10, 12, 13)); 3734 assertEquals(new Rect(10, 10, 12, 13), parent.getLastRequestedChildRectOnScreen()); 3735 assertEquals(new Rect(10, 10, 12, 13), grandParent.getLastRequestedChildRectOnScreen()); 3736 } 3737 3738 /** 3739 * For the duration of the tap timeout we are in a 'prepressed' state 3740 * to differentiate between taps and touch scrolls. 3741 * Wait at least this long before testing if the view is pressed 3742 * by calling this function. 3743 */ waitPrepressedTimeout()3744 private void waitPrepressedTimeout() { 3745 try { 3746 Thread.sleep(ViewConfiguration.getTapTimeout() + 10); 3747 } catch (InterruptedException e) { 3748 Log.e(LOG_TAG, "waitPrepressedTimeout() interrupted! Test may fail!", e); 3749 } 3750 mInstrumentation.waitForIdleSync(); 3751 } 3752 3753 @Test testOnTouchEventTap()3754 public void testOnTouchEventTap() { 3755 final MockView view = mActivity.findViewById(R.id.mock_view); 3756 3757 assertTrue(view.isEnabled()); 3758 assertFalse(view.isClickable()); 3759 assertFalse(view.isLongClickable()); 3760 3761 mCtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, view); 3762 assertTrue(view.hasCalledOnTouchEvent()); 3763 } 3764 3765 3766 @Test testOnTouchEventScroll()3767 public void testOnTouchEventScroll() throws Throwable { 3768 final MockView view = mActivity.findViewById(R.id.mock_view); 3769 3770 mActivityRule.runOnUiThread(() -> { 3771 view.setEnabled(true); 3772 view.setClickable(true); 3773 view.setLongClickable(true); 3774 }); 3775 mInstrumentation.waitForIdleSync(); 3776 assertTrue(view.isEnabled()); 3777 assertTrue(view.isClickable()); 3778 assertTrue(view.isLongClickable()); 3779 3780 // MotionEvent.ACTION_DOWN 3781 int[] xy = new int[2]; 3782 view.getLocationOnScreen(xy); 3783 3784 final int viewWidth = view.getWidth(); 3785 final int viewHeight = view.getHeight(); 3786 float x = xy[0] + viewWidth / 2.0f; 3787 float y = xy[1] + viewHeight / 2.0f; 3788 3789 final int displayId = mActivity.getDisplayId(); 3790 long downTime = SystemClock.uptimeMillis(); 3791 MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, 3792 x, y, 0); 3793 event.setDisplayId(displayId); 3794 assertFalse(view.isPressed()); 3795 mInstrumentation.sendPointerSync(event); 3796 waitPrepressedTimeout(); 3797 compareAndRecycleMotionEvents(event, view.pollTouchEvent()); 3798 assertTrue(view.isPressed()); 3799 3800 // MotionEvent.ACTION_MOVE 3801 // move out of the bound. 3802 view.reset(); 3803 long eventTime = SystemClock.uptimeMillis(); 3804 final int slop = ViewConfiguration.get(mActivity).getScaledTouchSlop(); 3805 x = xy[0] + viewWidth + slop; 3806 y = xy[1] + viewHeight + slop; 3807 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0); 3808 event.setDisplayId(displayId); 3809 mInstrumentation.sendPointerSync(event); 3810 compareAndRecycleMotionEvents(event, view.pollTouchEvent()); 3811 assertFalse(view.isPressed()); 3812 3813 // move into view 3814 view.reset(); 3815 eventTime = SystemClock.uptimeMillis(); 3816 x = xy[0] + viewWidth - 1; 3817 y = xy[1] + viewHeight - 1; 3818 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0); 3819 event.setDisplayId(displayId); 3820 SystemClock.sleep(20); // prevent event batching 3821 mInstrumentation.sendPointerSync(event); 3822 waitPrepressedTimeout(); 3823 compareAndRecycleMotionEvents(event, view.pollTouchEvent()); 3824 assertFalse(view.isPressed()); 3825 3826 // MotionEvent.ACTION_UP 3827 View.OnClickListener listener = mock(View.OnClickListener.class); 3828 view.setOnClickListener(listener); 3829 view.reset(); 3830 eventTime = SystemClock.uptimeMillis(); 3831 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); 3832 event.setDisplayId(displayId); 3833 mInstrumentation.sendPointerSync(event); 3834 compareAndRecycleMotionEvents(event, view.pollTouchEvent()); 3835 verifyZeroInteractions(listener); 3836 3837 view.reset(); 3838 x = xy[0] + viewWidth / 2.0f; 3839 y = xy[1] + viewHeight / 2.0f; 3840 downTime = SystemClock.uptimeMillis(); 3841 event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0); 3842 event.setDisplayId(displayId); 3843 mInstrumentation.sendPointerSync(event); 3844 compareAndRecycleMotionEvents(event, view.pollTouchEvent()); 3845 3846 // MotionEvent.ACTION_CANCEL 3847 view.reset(); 3848 reset(listener); 3849 eventTime = SystemClock.uptimeMillis(); 3850 event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_CANCEL, x, y, 0); 3851 event.setDisplayId(displayId); 3852 mInstrumentation.sendPointerSync(event); 3853 compareAndRecycleMotionEvents(event, view.pollTouchEvent()); 3854 assertFalse(view.isPressed()); 3855 verifyZeroInteractions(listener); 3856 } 3857 3858 @Test testBringToFront()3859 public void testBringToFront() { 3860 MockView view = new MockView(mActivity); 3861 view.setParent(mMockParent); 3862 3863 assertFalse(mMockParent.hasBroughtChildToFront()); 3864 view.bringToFront(); 3865 assertTrue(mMockParent.hasBroughtChildToFront()); 3866 } 3867 3868 @Test testGetApplicationWindowToken()3869 public void testGetApplicationWindowToken() { 3870 View view = new View(mActivity); 3871 // mAttachInfo is null 3872 assertNull(view.getApplicationWindowToken()); 3873 3874 // mAttachInfo is not null 3875 view = mActivity.findViewById(R.id.fit_windows); 3876 assertNotNull(view.getApplicationWindowToken()); 3877 } 3878 3879 @Test testGetBottomPaddingOffset()3880 public void testGetBottomPaddingOffset() { 3881 MockView view = new MockView(mActivity); 3882 assertEquals(0, view.getBottomPaddingOffset()); 3883 } 3884 3885 @Test testGetLeftPaddingOffset()3886 public void testGetLeftPaddingOffset() { 3887 MockView view = new MockView(mActivity); 3888 assertEquals(0, view.getLeftPaddingOffset()); 3889 } 3890 3891 @Test testGetRightPaddingOffset()3892 public void testGetRightPaddingOffset() { 3893 MockView view = new MockView(mActivity); 3894 assertEquals(0, view.getRightPaddingOffset()); 3895 } 3896 3897 @Test testGetTopPaddingOffset()3898 public void testGetTopPaddingOffset() { 3899 MockView view = new MockView(mActivity); 3900 assertEquals(0, view.getTopPaddingOffset()); 3901 } 3902 3903 @Test testIsPaddingOffsetRequired()3904 public void testIsPaddingOffsetRequired() { 3905 MockView view = new MockView(mActivity); 3906 assertFalse(view.isPaddingOffsetRequired()); 3907 } 3908 3909 @UiThreadTest 3910 @Test testPadding()3911 public void testPadding() { 3912 MockView view = (MockView) mActivity.findViewById(R.id.mock_view_padding_full); 3913 Drawable background = view.getBackground(); 3914 Rect backgroundPadding = new Rect(); 3915 background.getPadding(backgroundPadding); 3916 3917 // There is some background with a non null padding 3918 assertNotNull(background); 3919 assertTrue(backgroundPadding.left != 0); 3920 assertTrue(backgroundPadding.right != 0); 3921 assertTrue(backgroundPadding.top != 0); 3922 assertTrue(backgroundPadding.bottom != 0); 3923 3924 // The XML defines android:padding="0dp" and that should be the resulting padding 3925 assertEquals(0, view.getPaddingLeft()); 3926 assertEquals(0, view.getPaddingTop()); 3927 assertEquals(0, view.getPaddingRight()); 3928 assertEquals(0, view.getPaddingBottom()); 3929 3930 // LEFT case 3931 view = (MockView) mActivity.findViewById(R.id.mock_view_padding_left); 3932 background = view.getBackground(); 3933 backgroundPadding = new Rect(); 3934 background.getPadding(backgroundPadding); 3935 3936 // There is some background with a non null padding 3937 assertNotNull(background); 3938 assertTrue(backgroundPadding.left != 0); 3939 assertTrue(backgroundPadding.right != 0); 3940 assertTrue(backgroundPadding.top != 0); 3941 assertTrue(backgroundPadding.bottom != 0); 3942 3943 // The XML defines android:paddingLeft="0dp" and that should be the resulting padding 3944 assertEquals(0, view.getPaddingLeft()); 3945 assertEquals(backgroundPadding.top, view.getPaddingTop()); 3946 assertEquals(backgroundPadding.right, view.getPaddingRight()); 3947 assertEquals(backgroundPadding.bottom, view.getPaddingBottom()); 3948 3949 // RIGHT case 3950 view = (MockView) mActivity.findViewById(R.id.mock_view_padding_right); 3951 background = view.getBackground(); 3952 backgroundPadding = new Rect(); 3953 background.getPadding(backgroundPadding); 3954 3955 // There is some background with a non null padding 3956 assertNotNull(background); 3957 assertTrue(backgroundPadding.left != 0); 3958 assertTrue(backgroundPadding.right != 0); 3959 assertTrue(backgroundPadding.top != 0); 3960 assertTrue(backgroundPadding.bottom != 0); 3961 3962 // The XML defines android:paddingRight="0dp" and that should be the resulting padding 3963 assertEquals(backgroundPadding.left, view.getPaddingLeft()); 3964 assertEquals(backgroundPadding.top, view.getPaddingTop()); 3965 assertEquals(0, view.getPaddingRight()); 3966 assertEquals(backgroundPadding.bottom, view.getPaddingBottom()); 3967 3968 // TOP case 3969 view = (MockView) mActivity.findViewById(R.id.mock_view_padding_top); 3970 background = view.getBackground(); 3971 backgroundPadding = new Rect(); 3972 background.getPadding(backgroundPadding); 3973 3974 // There is some background with a non null padding 3975 assertNotNull(background); 3976 assertTrue(backgroundPadding.left != 0); 3977 assertTrue(backgroundPadding.right != 0); 3978 assertTrue(backgroundPadding.top != 0); 3979 assertTrue(backgroundPadding.bottom != 0); 3980 3981 // The XML defines android:paddingTop="0dp" and that should be the resulting padding 3982 assertEquals(backgroundPadding.left, view.getPaddingLeft()); 3983 assertEquals(0, view.getPaddingTop()); 3984 assertEquals(backgroundPadding.right, view.getPaddingRight()); 3985 assertEquals(backgroundPadding.bottom, view.getPaddingBottom()); 3986 3987 // BOTTOM case 3988 view = (MockView) mActivity.findViewById(R.id.mock_view_padding_bottom); 3989 background = view.getBackground(); 3990 backgroundPadding = new Rect(); 3991 background.getPadding(backgroundPadding); 3992 3993 // There is some background with a non null padding 3994 assertNotNull(background); 3995 assertTrue(backgroundPadding.left != 0); 3996 assertTrue(backgroundPadding.right != 0); 3997 assertTrue(backgroundPadding.top != 0); 3998 assertTrue(backgroundPadding.bottom != 0); 3999 4000 // The XML defines android:paddingBottom="0dp" and that should be the resulting padding 4001 assertEquals(backgroundPadding.left, view.getPaddingLeft()); 4002 assertEquals(backgroundPadding.top, view.getPaddingTop()); 4003 assertEquals(backgroundPadding.right, view.getPaddingRight()); 4004 assertEquals(0, view.getPaddingBottom()); 4005 4006 // Case for interleaved background/padding changes 4007 view = (MockView) mActivity.findViewById(R.id.mock_view_padding_runtime_updated); 4008 background = view.getBackground(); 4009 backgroundPadding = new Rect(); 4010 background.getPadding(backgroundPadding); 4011 4012 // There is some background with a null padding 4013 assertNotNull(background); 4014 assertTrue(backgroundPadding.left == 0); 4015 assertTrue(backgroundPadding.right == 0); 4016 assertTrue(backgroundPadding.top == 0); 4017 assertTrue(backgroundPadding.bottom == 0); 4018 4019 final int paddingLeft = view.getPaddingLeft(); 4020 final int paddingRight = view.getPaddingRight(); 4021 final int paddingTop = view.getPaddingTop(); 4022 final int paddingBottom = view.getPaddingBottom(); 4023 assertEquals(8, paddingLeft); 4024 assertEquals(0, paddingTop); 4025 assertEquals(8, paddingRight); 4026 assertEquals(0, paddingBottom); 4027 4028 // Manipulate background and padding 4029 background.setState(view.getDrawableState()); 4030 background.jumpToCurrentState(); 4031 view.setBackground(background); 4032 view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); 4033 4034 assertEquals(8, view.getPaddingLeft()); 4035 assertEquals(0, view.getPaddingTop()); 4036 assertEquals(8, view.getPaddingRight()); 4037 assertEquals(0, view.getPaddingBottom()); 4038 } 4039 4040 @Test testGetWindowVisibleDisplayFrame()4041 public void testGetWindowVisibleDisplayFrame() { 4042 Rect outRect = new Rect(); 4043 View view = new View(mActivity); 4044 // mAttachInfo is null 4045 view.getWindowVisibleDisplayFrame(outRect); 4046 final WindowManager windowManager = mActivity.getWindowManager(); 4047 final WindowMetrics metrics = windowManager.getMaximumWindowMetrics(); 4048 final Insets insets = 4049 metrics.getWindowInsets().getInsets( 4050 WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout()); 4051 final int expectedWidth = metrics.getBounds().width() - insets.left - insets.right; 4052 final int expectedHeight = metrics.getBounds().height() - insets.top - insets.bottom; 4053 assertEquals(0, outRect.left); 4054 assertEquals(0, outRect.top); 4055 assertEquals(expectedWidth, outRect.right); 4056 assertEquals(expectedHeight, outRect.bottom); 4057 4058 // mAttachInfo is not null 4059 outRect = new Rect(); 4060 view = mActivity.findViewById(R.id.fit_windows); 4061 // it's implementation detail 4062 view.getWindowVisibleDisplayFrame(outRect); 4063 } 4064 4065 @Test testSetScrollContainer()4066 public void testSetScrollContainer() throws Throwable { 4067 final MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view); 4068 final MockView scrollView = (MockView) mActivity.findViewById(R.id.scroll_view); 4069 Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565); 4070 final BitmapDrawable d = new BitmapDrawable(bitmap); 4071 final InputMethodManager imm = (InputMethodManager) mActivity.getSystemService( 4072 Context.INPUT_METHOD_SERVICE); 4073 final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(300, 500); 4074 mActivityRule.runOnUiThread(() -> { 4075 mockView.setBackgroundDrawable(d); 4076 mockView.setHorizontalFadingEdgeEnabled(true); 4077 mockView.setVerticalFadingEdgeEnabled(true); 4078 mockView.setLayoutParams(layoutParams); 4079 scrollView.setLayoutParams(layoutParams); 4080 4081 mockView.setFocusable(true); 4082 mockView.requestFocus(); 4083 mockView.setScrollContainer(true); 4084 scrollView.setScrollContainer(false); 4085 imm.showSoftInput(mockView, 0); 4086 }); 4087 mInstrumentation.waitForIdleSync(); 4088 4089 // FIXME: why the size of view doesn't change? 4090 4091 mActivityRule.runOnUiThread( 4092 () -> imm.hideSoftInputFromInputMethod(mockView.getWindowToken(), 0)); 4093 mInstrumentation.waitForIdleSync(); 4094 } 4095 4096 @Test testTouchMode()4097 public void testTouchMode() throws Throwable { 4098 final MockView mockView = (MockView) mActivity.findViewById(R.id.mock_view); 4099 final View fitWindowsView = mActivity.findViewById(R.id.fit_windows); 4100 mActivityRule.runOnUiThread(() -> { 4101 mockView.setFocusableInTouchMode(true); 4102 fitWindowsView.setFocusable(true); 4103 fitWindowsView.requestFocus(); 4104 }); 4105 mInstrumentation.waitForIdleSync(); 4106 assertTrue(mockView.isFocusableInTouchMode()); 4107 assertFalse(fitWindowsView.isFocusableInTouchMode()); 4108 assertTrue(mockView.isFocusable()); 4109 assertTrue(fitWindowsView.isFocusable()); 4110 assertFalse(mockView.isFocused()); 4111 assertTrue(fitWindowsView.isFocused()); 4112 assertFalse(mockView.isInTouchMode()); 4113 assertFalse(fitWindowsView.isInTouchMode()); 4114 4115 mCtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mockView); 4116 assertFalse(fitWindowsView.isFocused()); 4117 assertFalse(mockView.isFocused()); 4118 mActivityRule.runOnUiThread(mockView::requestFocus); 4119 mInstrumentation.waitForIdleSync(); 4120 assertTrue(mockView.isFocused()); 4121 mActivityRule.runOnUiThread(fitWindowsView::requestFocus); 4122 mInstrumentation.waitForIdleSync(); 4123 assertFalse(fitWindowsView.isFocused()); 4124 assertTrue(mockView.isInTouchMode()); 4125 assertTrue(fitWindowsView.isInTouchMode()); 4126 4127 KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0); 4128 mInstrumentation.sendKeySync(keyEvent); 4129 mActivityRule.runOnUiThread(() -> assertTrue(mockView.isFocused())); 4130 assertFalse(fitWindowsView.isFocused()); 4131 mActivityRule.runOnUiThread(fitWindowsView::requestFocus); 4132 mInstrumentation.waitForIdleSync(); 4133 assertFalse(mockView.isFocused()); 4134 assertTrue(fitWindowsView.isFocused()); 4135 assertFalse(mockView.isInTouchMode()); 4136 assertFalse(fitWindowsView.isInTouchMode()); 4137 4138 // Mouse events should trigger touch mode. 4139 final MotionEvent event = 4140 CtsMouseUtil.obtainMouseEvent(MotionEvent.ACTION_SCROLL, mockView, 4141 mockView.getWidth() - 1, 0); 4142 mInstrumentation.sendPointerSync(event); 4143 mInstrumentation.waitForIdleSync(); 4144 assertTrue(fitWindowsView.isInTouchMode()); 4145 4146 mInstrumentation.sendKeySync(keyEvent); 4147 mInstrumentation.waitForIdleSync(); 4148 mActivityRule.runOnUiThread(() -> assertFalse(fitWindowsView.isInTouchMode())); 4149 4150 event.setAction(MotionEvent.ACTION_DOWN); 4151 mInstrumentation.sendPointerSync(event); 4152 event.setAction(MotionEvent.ACTION_UP); 4153 mInstrumentation.sendPointerSync(event); 4154 mInstrumentation.waitForIdleSync(); 4155 assertTrue(fitWindowsView.isInTouchMode()); 4156 4157 mInstrumentation.sendKeySync(keyEvent); 4158 mInstrumentation.waitForIdleSync(); 4159 mActivityRule.runOnUiThread(() -> assertFalse(fitWindowsView.isInTouchMode())); 4160 4161 // Stylus events should trigger touch mode. 4162 event.setAction(MotionEvent.ACTION_DOWN); 4163 event.setSource(InputDevice.SOURCE_STYLUS); 4164 mInstrumentation.sendPointerSync(event); 4165 mInstrumentation.waitForIdleSync(); 4166 assertTrue(fitWindowsView.isInTouchMode()); 4167 } 4168 4169 @UiThreadTest 4170 @Test testScrollbarStyle()4171 public void testScrollbarStyle() { 4172 MockView view = (MockView) mActivity.findViewById(R.id.scroll_view); 4173 Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565); 4174 BitmapDrawable d = new BitmapDrawable(bitmap); 4175 view.setBackgroundDrawable(d); 4176 view.setHorizontalFadingEdgeEnabled(true); 4177 view.setVerticalFadingEdgeEnabled(true); 4178 4179 assertTrue(view.isHorizontalScrollBarEnabled()); 4180 assertTrue(view.isVerticalScrollBarEnabled()); 4181 int verticalScrollBarWidth = view.getVerticalScrollbarWidth(); 4182 int horizontalScrollBarHeight = view.getHorizontalScrollbarHeight(); 4183 assertTrue(verticalScrollBarWidth > 0); 4184 assertTrue(horizontalScrollBarHeight > 0); 4185 assertEquals(0, view.getPaddingRight()); 4186 assertEquals(0, view.getPaddingBottom()); 4187 4188 view.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET); 4189 assertEquals(View.SCROLLBARS_INSIDE_INSET, view.getScrollBarStyle()); 4190 assertEquals(verticalScrollBarWidth, view.getPaddingRight()); 4191 assertEquals(horizontalScrollBarHeight, view.getPaddingBottom()); 4192 4193 view.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); 4194 assertEquals(View.SCROLLBARS_OUTSIDE_OVERLAY, view.getScrollBarStyle()); 4195 assertEquals(0, view.getPaddingRight()); 4196 assertEquals(0, view.getPaddingBottom()); 4197 4198 view.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET); 4199 assertEquals(View.SCROLLBARS_OUTSIDE_INSET, view.getScrollBarStyle()); 4200 assertEquals(verticalScrollBarWidth, view.getPaddingRight()); 4201 assertEquals(horizontalScrollBarHeight, view.getPaddingBottom()); 4202 4203 // TODO: how to get the position of the Scrollbar to assert it is inside or outside. 4204 } 4205 4206 @UiThreadTest 4207 @Test testScrollFading()4208 public void testScrollFading() { 4209 MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 4210 Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565); 4211 BitmapDrawable d = new BitmapDrawable(bitmap); 4212 view.setBackgroundDrawable(d); 4213 4214 assertFalse(view.isHorizontalFadingEdgeEnabled()); 4215 assertFalse(view.isVerticalFadingEdgeEnabled()); 4216 assertEquals(0, view.getHorizontalFadingEdgeLength()); 4217 assertEquals(0, view.getVerticalFadingEdgeLength()); 4218 4219 view.setHorizontalFadingEdgeEnabled(true); 4220 view.setVerticalFadingEdgeEnabled(true); 4221 assertTrue(view.isHorizontalFadingEdgeEnabled()); 4222 assertTrue(view.isVerticalFadingEdgeEnabled()); 4223 assertTrue(view.getHorizontalFadingEdgeLength() > 0); 4224 assertTrue(view.getVerticalFadingEdgeLength() > 0); 4225 4226 final int fadingLength = 20; 4227 view.setFadingEdgeLength(fadingLength); 4228 assertEquals(fadingLength, view.getHorizontalFadingEdgeLength()); 4229 assertEquals(fadingLength, view.getVerticalFadingEdgeLength()); 4230 } 4231 4232 @UiThreadTest 4233 @Test testScrolling()4234 public void testScrolling() { 4235 MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 4236 view.reset(); 4237 assertEquals(0, view.getScrollX()); 4238 assertEquals(0, view.getScrollY()); 4239 assertFalse(view.hasCalledOnScrollChanged()); 4240 4241 view.scrollTo(0, 0); 4242 assertEquals(0, view.getScrollX()); 4243 assertEquals(0, view.getScrollY()); 4244 assertFalse(view.hasCalledOnScrollChanged()); 4245 4246 view.scrollBy(0, 0); 4247 assertEquals(0, view.getScrollX()); 4248 assertEquals(0, view.getScrollY()); 4249 assertFalse(view.hasCalledOnScrollChanged()); 4250 4251 view.scrollTo(10, 100); 4252 assertEquals(10, view.getScrollX()); 4253 assertEquals(100, view.getScrollY()); 4254 assertTrue(view.hasCalledOnScrollChanged()); 4255 4256 view.reset(); 4257 assertFalse(view.hasCalledOnScrollChanged()); 4258 view.scrollBy(-10, -100); 4259 assertEquals(0, view.getScrollX()); 4260 assertEquals(0, view.getScrollY()); 4261 assertTrue(view.hasCalledOnScrollChanged()); 4262 4263 view.reset(); 4264 assertFalse(view.hasCalledOnScrollChanged()); 4265 view.scrollTo(-1, -2); 4266 assertEquals(-1, view.getScrollX()); 4267 assertEquals(-2, view.getScrollY()); 4268 assertTrue(view.hasCalledOnScrollChanged()); 4269 } 4270 4271 @Test testInitializeScrollbarsAndFadingEdge()4272 public void testInitializeScrollbarsAndFadingEdge() { 4273 MockView view = (MockView) mActivity.findViewById(R.id.scroll_view); 4274 4275 assertTrue(view.isHorizontalScrollBarEnabled()); 4276 assertTrue(view.isVerticalScrollBarEnabled()); 4277 assertFalse(view.isHorizontalFadingEdgeEnabled()); 4278 assertFalse(view.isVerticalFadingEdgeEnabled()); 4279 4280 view = (MockView) mActivity.findViewById(R.id.scroll_view_2); 4281 final int fadingEdgeLength = 20; 4282 4283 assertTrue(view.isHorizontalScrollBarEnabled()); 4284 assertTrue(view.isVerticalScrollBarEnabled()); 4285 assertTrue(view.isHorizontalFadingEdgeEnabled()); 4286 assertTrue(view.isVerticalFadingEdgeEnabled()); 4287 assertEquals(fadingEdgeLength, view.getHorizontalFadingEdgeLength()); 4288 assertEquals(fadingEdgeLength, view.getVerticalFadingEdgeLength()); 4289 } 4290 4291 @UiThreadTest 4292 @Test testScrollIndicators()4293 public void testScrollIndicators() { 4294 MockView view = (MockView) mActivity.findViewById(R.id.scroll_view); 4295 4296 assertEquals("Set indicators match those specified in XML", 4297 View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM, 4298 view.getScrollIndicators()); 4299 4300 view.setScrollIndicators(0); 4301 assertEquals("Cleared indicators", 0, view.getScrollIndicators()); 4302 4303 view.setScrollIndicators(View.SCROLL_INDICATOR_START | View.SCROLL_INDICATOR_RIGHT); 4304 assertEquals("Set start and right indicators", 4305 View.SCROLL_INDICATOR_START | View.SCROLL_INDICATOR_RIGHT, 4306 view.getScrollIndicators()); 4307 4308 } 4309 4310 @Test testScrollbarSize()4311 public void testScrollbarSize() { 4312 final int configScrollbarSize = ViewConfiguration.get(mActivity).getScaledScrollBarSize(); 4313 final int customScrollbarSize = configScrollbarSize * 2; 4314 4315 // No explicit scrollbarSize or custom drawables, ViewConfiguration applies. 4316 final MockView view = (MockView) mActivity.findViewById(R.id.scroll_view); 4317 assertEquals(configScrollbarSize, view.getScrollBarSize()); 4318 assertEquals(configScrollbarSize, view.getVerticalScrollbarWidth()); 4319 assertEquals(configScrollbarSize, view.getHorizontalScrollbarHeight()); 4320 4321 // No custom drawables, explicit scrollbarSize takes precedence. 4322 final MockView view2 = (MockView) mActivity.findViewById(R.id.scroll_view_2); 4323 view2.setScrollBarSize(customScrollbarSize); 4324 assertEquals(customScrollbarSize, view2.getScrollBarSize()); 4325 assertEquals(customScrollbarSize, view2.getVerticalScrollbarWidth()); 4326 assertEquals(customScrollbarSize, view2.getHorizontalScrollbarHeight()); 4327 4328 // Custom drawables with no intrinsic size, ViewConfiguration applies. 4329 final MockView view3 = (MockView) mActivity.findViewById(R.id.scroll_view_3); 4330 assertEquals(configScrollbarSize, view3.getVerticalScrollbarWidth()); 4331 assertEquals(configScrollbarSize, view3.getHorizontalScrollbarHeight()); 4332 // Explicit scrollbarSize takes precedence. 4333 view3.setScrollBarSize(customScrollbarSize); 4334 assertEquals(view3.getScrollBarSize(), view3.getVerticalScrollbarWidth()); 4335 assertEquals(view3.getScrollBarSize(), view3.getHorizontalScrollbarHeight()); 4336 4337 // Custom thumb drawables with intrinsic sizes define the scrollbars' dimensions. 4338 final MockView view4 = (MockView) mActivity.findViewById(R.id.scroll_view_4); 4339 final Resources res = mActivity.getResources(); 4340 final int thumbWidth = res.getDimensionPixelSize(R.dimen.scrollbar_thumb_width); 4341 final int thumbHeight = res.getDimensionPixelSize(R.dimen.scrollbar_thumb_height); 4342 assertEquals(thumbWidth, view4.getVerticalScrollbarWidth()); 4343 assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight()); 4344 // Explicit scrollbarSize has no effect. 4345 view4.setScrollBarSize(customScrollbarSize); 4346 assertEquals(thumbWidth, view4.getVerticalScrollbarWidth()); 4347 assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight()); 4348 4349 // Custom thumb and track drawables with intrinsic sizes. Track size take precedence. 4350 final MockView view5 = (MockView) mActivity.findViewById(R.id.scroll_view_5); 4351 final int trackWidth = res.getDimensionPixelSize(R.dimen.scrollbar_track_width); 4352 final int trackHeight = res.getDimensionPixelSize(R.dimen.scrollbar_track_height); 4353 assertEquals(trackWidth, view5.getVerticalScrollbarWidth()); 4354 assertEquals(trackHeight, view5.getHorizontalScrollbarHeight()); 4355 // Explicit scrollbarSize has no effect. 4356 view5.setScrollBarSize(customScrollbarSize); 4357 assertEquals(trackWidth, view5.getVerticalScrollbarWidth()); 4358 assertEquals(trackHeight, view5.getHorizontalScrollbarHeight()); 4359 4360 // Custom thumb and track, track with no intrinsic size, ViewConfiguration applies 4361 // regardless of the thumb drawable dimensions. 4362 final MockView view6 = (MockView) mActivity.findViewById(R.id.scroll_view_6); 4363 assertEquals(configScrollbarSize, view6.getVerticalScrollbarWidth()); 4364 assertEquals(configScrollbarSize, view6.getHorizontalScrollbarHeight()); 4365 // Explicit scrollbarSize takes precedence. 4366 view6.setScrollBarSize(customScrollbarSize); 4367 assertEquals(customScrollbarSize, view6.getVerticalScrollbarWidth()); 4368 assertEquals(customScrollbarSize, view6.getHorizontalScrollbarHeight()); 4369 } 4370 4371 @Test testOnStartAndFinishTemporaryDetach()4372 public void testOnStartAndFinishTemporaryDetach() throws Throwable { 4373 final AtomicBoolean exitedDispatchStartTemporaryDetach = new AtomicBoolean(false); 4374 final AtomicBoolean exitedDispatchFinishTemporaryDetach = new AtomicBoolean(false); 4375 4376 final View view = new View(mActivity) { 4377 private boolean mEnteredDispatchStartTemporaryDetach = false; 4378 private boolean mExitedDispatchStartTemporaryDetach = false; 4379 private boolean mEnteredDispatchFinishTemporaryDetach = false; 4380 private boolean mExitedDispatchFinishTemporaryDetach = false; 4381 4382 private boolean mCalledOnStartTemporaryDetach = false; 4383 private boolean mCalledOnFinishTemporaryDetach = false; 4384 4385 @Override 4386 public void dispatchStartTemporaryDetach() { 4387 assertFalse(mEnteredDispatchStartTemporaryDetach); 4388 assertFalse(mExitedDispatchStartTemporaryDetach); 4389 assertFalse(mEnteredDispatchFinishTemporaryDetach); 4390 assertFalse(mExitedDispatchFinishTemporaryDetach); 4391 assertFalse(mCalledOnStartTemporaryDetach); 4392 assertFalse(mCalledOnFinishTemporaryDetach); 4393 mEnteredDispatchStartTemporaryDetach = true; 4394 4395 assertFalse(isTemporarilyDetached()); 4396 4397 super.dispatchStartTemporaryDetach(); 4398 4399 assertTrue(isTemporarilyDetached()); 4400 4401 assertTrue(mEnteredDispatchStartTemporaryDetach); 4402 assertFalse(mExitedDispatchStartTemporaryDetach); 4403 assertFalse(mEnteredDispatchFinishTemporaryDetach); 4404 assertFalse(mExitedDispatchFinishTemporaryDetach); 4405 assertTrue(mCalledOnStartTemporaryDetach); 4406 assertFalse(mCalledOnFinishTemporaryDetach); 4407 mExitedDispatchStartTemporaryDetach = true; 4408 exitedDispatchStartTemporaryDetach.set(true); 4409 } 4410 4411 @Override 4412 public void dispatchFinishTemporaryDetach() { 4413 assertTrue(mEnteredDispatchStartTemporaryDetach); 4414 assertTrue(mExitedDispatchStartTemporaryDetach); 4415 assertFalse(mEnteredDispatchFinishTemporaryDetach); 4416 assertFalse(mExitedDispatchFinishTemporaryDetach); 4417 assertTrue(mCalledOnStartTemporaryDetach); 4418 assertFalse(mCalledOnFinishTemporaryDetach); 4419 mEnteredDispatchFinishTemporaryDetach = true; 4420 4421 assertTrue(isTemporarilyDetached()); 4422 4423 super.dispatchFinishTemporaryDetach(); 4424 4425 assertFalse(isTemporarilyDetached()); 4426 4427 assertTrue(mEnteredDispatchStartTemporaryDetach); 4428 assertTrue(mExitedDispatchStartTemporaryDetach); 4429 assertTrue(mEnteredDispatchFinishTemporaryDetach); 4430 assertFalse(mExitedDispatchFinishTemporaryDetach); 4431 assertTrue(mCalledOnStartTemporaryDetach); 4432 assertTrue(mCalledOnFinishTemporaryDetach); 4433 mExitedDispatchFinishTemporaryDetach = true; 4434 exitedDispatchFinishTemporaryDetach.set(true); 4435 } 4436 4437 @Override 4438 public void onStartTemporaryDetach() { 4439 assertTrue(mEnteredDispatchStartTemporaryDetach); 4440 assertFalse(mExitedDispatchStartTemporaryDetach); 4441 assertFalse(mEnteredDispatchFinishTemporaryDetach); 4442 assertFalse(mExitedDispatchFinishTemporaryDetach); 4443 assertFalse(mCalledOnStartTemporaryDetach); 4444 assertFalse(mCalledOnFinishTemporaryDetach); 4445 4446 assertTrue(isTemporarilyDetached()); 4447 4448 mCalledOnStartTemporaryDetach = true; 4449 } 4450 4451 @Override 4452 public void onFinishTemporaryDetach() { 4453 assertTrue(mEnteredDispatchStartTemporaryDetach); 4454 assertTrue(mExitedDispatchStartTemporaryDetach); 4455 assertTrue(mEnteredDispatchFinishTemporaryDetach); 4456 assertFalse(mExitedDispatchFinishTemporaryDetach); 4457 assertTrue(mCalledOnStartTemporaryDetach); 4458 assertFalse(mCalledOnFinishTemporaryDetach); 4459 4460 assertFalse(isTemporarilyDetached()); 4461 4462 mCalledOnFinishTemporaryDetach = true; 4463 } 4464 }; 4465 4466 assertFalse(view.isTemporarilyDetached()); 4467 4468 mActivityRule.runOnUiThread(view::dispatchStartTemporaryDetach); 4469 mInstrumentation.waitForIdleSync(); 4470 4471 assertTrue(view.isTemporarilyDetached()); 4472 assertTrue(exitedDispatchStartTemporaryDetach.get()); 4473 assertFalse(exitedDispatchFinishTemporaryDetach.get()); 4474 4475 mActivityRule.runOnUiThread(view::dispatchFinishTemporaryDetach); 4476 mInstrumentation.waitForIdleSync(); 4477 4478 assertFalse(view.isTemporarilyDetached()); 4479 assertTrue(exitedDispatchStartTemporaryDetach.get()); 4480 assertTrue(exitedDispatchFinishTemporaryDetach.get()); 4481 } 4482 4483 @Test testKeyPreIme()4484 public void testKeyPreIme() throws Throwable { 4485 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 4486 4487 mActivityRule.runOnUiThread(() -> { 4488 view.setFocusable(true); 4489 view.requestFocus(); 4490 }); 4491 mInstrumentation.waitForIdleSync(); 4492 4493 mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A)); 4494 assertTrue(view.hasCalledDispatchKeyEventPreIme()); 4495 assertTrue(view.hasCalledOnKeyPreIme()); 4496 } 4497 4498 @Test testHapticFeedback()4499 public void testHapticFeedback() { 4500 Vibrator vib = (Vibrator) mActivity.getSystemService(Context.VIBRATOR_SERVICE); 4501 4502 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 4503 final int LONG_PRESS = HapticFeedbackConstants.LONG_PRESS; 4504 final int FLAG_IGNORE_VIEW_SETTING = HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING; 4505 final int FLAG_IGNORE_GLOBAL_SETTING = HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING; 4506 final int ALWAYS = FLAG_IGNORE_VIEW_SETTING | FLAG_IGNORE_GLOBAL_SETTING; 4507 4508 view.setHapticFeedbackEnabled(false); 4509 assertFalse(view.isHapticFeedbackEnabled()); 4510 assertFalse(view.performHapticFeedback(LONG_PRESS)); 4511 assertFalse(view.performHapticFeedback(LONG_PRESS, FLAG_IGNORE_GLOBAL_SETTING)); 4512 assertPerformHapticFeedbackTrueIfHasVibrator(vib, 4513 view.performHapticFeedback(LONG_PRESS, ALWAYS)); 4514 assertFalse(view.performHapticFeedback(HapticFeedbackConstants.NO_HAPTICS)); 4515 4516 view.setHapticFeedbackEnabled(true); 4517 assertTrue(view.isHapticFeedbackEnabled()); 4518 assertPerformHapticFeedbackTrueIfHasVibrator(vib, 4519 view.performHapticFeedback(LONG_PRESS, FLAG_IGNORE_GLOBAL_SETTING)); 4520 assertFalse(view.performHapticFeedback(HapticFeedbackConstants.NO_HAPTICS)); 4521 } 4522 4523 /** 4524 * Assert that the result must be true if the device has a vibrator. If no vibrator, the method 4525 * may return true or false depending on whether USE_ASYNC_PERFORM_HAPTIC_FEEDBACK is active. 4526 */ assertPerformHapticFeedbackTrueIfHasVibrator(Vibrator vib, boolean result)4527 private void assertPerformHapticFeedbackTrueIfHasVibrator(Vibrator vib, boolean result) { 4528 if (vib.hasVibrator()) { 4529 assertTrue(result); 4530 } 4531 } 4532 4533 @Test testInputConnection()4534 public void testInputConnection() throws Throwable { 4535 final InputMethodManager imm = (InputMethodManager) mActivity.getSystemService( 4536 Context.INPUT_METHOD_SERVICE); 4537 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 4538 final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root); 4539 final MockEditText editText = new MockEditText(mActivity); 4540 4541 mActivityRule.runOnUiThread(() -> { 4542 // Give a fixed size since, on most devices, the edittext is off-screen 4543 // and therefore doesn't get laid-out properly. 4544 viewGroup.addView(editText, 100, 30); 4545 editText.requestFocus(); 4546 }); 4547 mInstrumentation.waitForIdleSync(); 4548 assertTrue(editText.isFocused()); 4549 4550 mActivityRule.runOnUiThread(() -> imm.showSoftInput(editText, 0)); 4551 mInstrumentation.waitForIdleSync(); 4552 4553 PollingCheck.waitFor(TIMEOUT_DELTA, editText::hasCalledOnCreateInputConnection); 4554 4555 assertTrue(editText.hasCalledOnCheckIsTextEditor()); 4556 4557 mActivityRule.runOnUiThread(() -> { 4558 assertTrue(imm.isActive(editText)); 4559 assertFalse(editText.hasCalledCheckInputConnectionProxy()); 4560 imm.isActive(view); 4561 assertTrue(editText.hasCalledCheckInputConnectionProxy()); 4562 }); 4563 } 4564 4565 @Test testFilterTouchesWhenObscured()4566 public void testFilterTouchesWhenObscured() throws Throwable { 4567 View.OnTouchListener touchListener = mock(View.OnTouchListener.class); 4568 doReturn(true).when(touchListener).onTouch(any(), any()); 4569 View view = new View(mActivity); 4570 view.setOnTouchListener(touchListener); 4571 4572 MotionEvent.PointerProperties[] props = new MotionEvent.PointerProperties[] { 4573 new MotionEvent.PointerProperties() 4574 }; 4575 MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[] { 4576 new MotionEvent.PointerCoords() 4577 }; 4578 MotionEvent obscuredTouch = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 4579 1, props, coords, 0, 0, 0, 0, -1, 0, InputDevice.SOURCE_TOUCHSCREEN, 4580 MotionEvent.FLAG_WINDOW_IS_OBSCURED); 4581 MotionEvent unobscuredTouch = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 4582 1, props, coords, 0, 0, 0, 0, -1, 0, InputDevice.SOURCE_TOUCHSCREEN, 4583 0); 4584 4585 // Initially filter touches is false so all touches are dispatched. 4586 assertFalse(view.getFilterTouchesWhenObscured()); 4587 4588 view.dispatchTouchEvent(unobscuredTouch); 4589 verify(touchListener, times(1)).onTouch(view, unobscuredTouch); 4590 reset(touchListener); 4591 view.dispatchTouchEvent(obscuredTouch); 4592 verify(touchListener, times(1)).onTouch(view, obscuredTouch); 4593 reset(touchListener); 4594 4595 // Set filter touches to true so only unobscured touches are dispatched. 4596 view.setFilterTouchesWhenObscured(true); 4597 assertTrue(view.getFilterTouchesWhenObscured()); 4598 4599 view.dispatchTouchEvent(unobscuredTouch); 4600 verify(touchListener, times(1)).onTouch(view, unobscuredTouch); 4601 reset(touchListener); 4602 view.dispatchTouchEvent(obscuredTouch); 4603 verifyZeroInteractions(touchListener); 4604 reset(touchListener); 4605 4606 // Set filter touches to false so all touches are dispatched. 4607 view.setFilterTouchesWhenObscured(false); 4608 assertFalse(view.getFilterTouchesWhenObscured()); 4609 4610 view.dispatchTouchEvent(unobscuredTouch); 4611 verify(touchListener, times(1)).onTouch(view, unobscuredTouch); 4612 reset(touchListener); 4613 view.dispatchTouchEvent(obscuredTouch); 4614 verify(touchListener, times(1)).onTouch(view, obscuredTouch); 4615 reset(touchListener); 4616 } 4617 4618 @Test testBackgroundTint()4619 public void testBackgroundTint() { 4620 View inflatedView = mActivity.findViewById(R.id.background_tint); 4621 4622 assertEquals("Background tint inflated correctly", 4623 Color.WHITE, inflatedView.getBackgroundTintList().getDefaultColor()); 4624 assertEquals("Background tint mode inflated correctly", 4625 PorterDuff.Mode.SRC_OVER, inflatedView.getBackgroundTintMode()); 4626 4627 MockDrawable bg = new MockDrawable(); 4628 View view = new View(mActivity); 4629 4630 view.setBackground(bg); 4631 assertFalse("No background tint applied by default", bg.hasCalledSetTint()); 4632 4633 view.setBackgroundTintList(ColorStateList.valueOf(Color.WHITE)); 4634 assertTrue("Background tint applied when setBackgroundTints() called after setBackground()", 4635 bg.hasCalledSetTint()); 4636 4637 bg.reset(); 4638 view.setBackground(null); 4639 view.setBackground(bg); 4640 assertTrue("Background tint applied when setBackgroundTints() called before setBackground()", 4641 bg.hasCalledSetTint()); 4642 } 4643 4644 @Test testStartActionModeWithParent()4645 public void testStartActionModeWithParent() { 4646 View view = new View(mActivity); 4647 MockViewGroup parent = new MockViewGroup(mActivity); 4648 parent.addView(view); 4649 4650 ActionMode mode = view.startActionMode(null); 4651 4652 assertNotNull(mode); 4653 assertEquals(NO_OP_ACTION_MODE, mode); 4654 assertTrue(parent.isStartActionModeForChildCalled); 4655 assertEquals(ActionMode.TYPE_PRIMARY, parent.startActionModeForChildType); 4656 } 4657 4658 @Test testStartActionModeWithoutParent()4659 public void testStartActionModeWithoutParent() { 4660 View view = new View(mActivity); 4661 4662 ActionMode mode = view.startActionMode(null); 4663 4664 assertNull(mode); 4665 } 4666 4667 @Test testStartActionModeTypedWithParent()4668 public void testStartActionModeTypedWithParent() { 4669 View view = new View(mActivity); 4670 MockViewGroup parent = new MockViewGroup(mActivity); 4671 parent.addView(view); 4672 4673 ActionMode mode = view.startActionMode(null, ActionMode.TYPE_FLOATING); 4674 4675 assertNotNull(mode); 4676 assertEquals(NO_OP_ACTION_MODE, mode); 4677 assertTrue(parent.isStartActionModeForChildCalled); 4678 assertEquals(ActionMode.TYPE_FLOATING, parent.startActionModeForChildType); 4679 } 4680 4681 @Test testStartActionModeTypedWithoutParent()4682 public void testStartActionModeTypedWithoutParent() { 4683 View view = new View(mActivity); 4684 4685 ActionMode mode = view.startActionMode(null, ActionMode.TYPE_FLOATING); 4686 4687 assertNull(mode); 4688 } 4689 4690 @Test testVisibilityAggregated()4691 public void testVisibilityAggregated() throws Throwable { 4692 final View grandparent = mActivity.findViewById(R.id.viewlayout_root); 4693 final View parent = mActivity.findViewById(R.id.aggregate_visibility_parent); 4694 final MockView mv = (MockView) mActivity.findViewById(R.id.mock_view_aggregate_visibility); 4695 4696 assertEquals(parent, mv.getParent()); 4697 assertEquals(grandparent, parent.getParent()); 4698 4699 assertTrue(mv.hasCalledOnVisibilityAggregated()); 4700 assertTrue(mv.getLastAggregatedVisibility()); 4701 4702 final Runnable reset = () -> { 4703 grandparent.setVisibility(View.VISIBLE); 4704 parent.setVisibility(View.VISIBLE); 4705 mv.setVisibility(View.VISIBLE); 4706 mv.reset(); 4707 }; 4708 4709 mActivityRule.runOnUiThread(reset); 4710 4711 setVisibilityOnUiThread(parent, View.GONE); 4712 4713 assertTrue(mv.hasCalledOnVisibilityAggregated()); 4714 assertFalse(mv.getLastAggregatedVisibility()); 4715 4716 mActivityRule.runOnUiThread(reset); 4717 4718 setVisibilityOnUiThread(grandparent, View.GONE); 4719 4720 assertTrue(mv.hasCalledOnVisibilityAggregated()); 4721 assertFalse(mv.getLastAggregatedVisibility()); 4722 4723 mActivityRule.runOnUiThread(reset); 4724 mActivityRule.runOnUiThread(() -> { 4725 grandparent.setVisibility(View.GONE); 4726 parent.setVisibility(View.GONE); 4727 mv.setVisibility(View.VISIBLE); 4728 4729 grandparent.setVisibility(View.VISIBLE); 4730 }); 4731 4732 assertTrue(mv.hasCalledOnVisibilityAggregated()); 4733 assertFalse(mv.getLastAggregatedVisibility()); 4734 4735 mActivityRule.runOnUiThread(reset); 4736 mActivityRule.runOnUiThread(() -> { 4737 grandparent.setVisibility(View.GONE); 4738 parent.setVisibility(View.INVISIBLE); 4739 4740 grandparent.setVisibility(View.VISIBLE); 4741 }); 4742 4743 assertTrue(mv.hasCalledOnVisibilityAggregated()); 4744 assertFalse(mv.getLastAggregatedVisibility()); 4745 4746 mActivityRule.runOnUiThread(() -> parent.setVisibility(View.VISIBLE)); 4747 4748 assertTrue(mv.getLastAggregatedVisibility()); 4749 } 4750 4751 @Test testOverlappingRendering()4752 public void testOverlappingRendering() { 4753 View overlappingUnsetView = mActivity.findViewById(R.id.overlapping_rendering_unset); 4754 View overlappingFalseView = mActivity.findViewById(R.id.overlapping_rendering_false); 4755 View overlappingTrueView = mActivity.findViewById(R.id.overlapping_rendering_true); 4756 4757 assertTrue(overlappingUnsetView.hasOverlappingRendering()); 4758 assertTrue(overlappingUnsetView.getHasOverlappingRendering()); 4759 overlappingUnsetView.forceHasOverlappingRendering(false); 4760 assertTrue(overlappingUnsetView.hasOverlappingRendering()); 4761 assertFalse(overlappingUnsetView.getHasOverlappingRendering()); 4762 overlappingUnsetView.forceHasOverlappingRendering(true); 4763 assertTrue(overlappingUnsetView.hasOverlappingRendering()); 4764 assertTrue(overlappingUnsetView.getHasOverlappingRendering()); 4765 4766 assertTrue(overlappingTrueView.hasOverlappingRendering()); 4767 assertTrue(overlappingTrueView.getHasOverlappingRendering()); 4768 4769 assertTrue(overlappingFalseView.hasOverlappingRendering()); 4770 assertFalse(overlappingFalseView.getHasOverlappingRendering()); 4771 4772 View overridingView = new MockOverlappingRenderingSubclass(mActivity, false); 4773 assertFalse(overridingView.hasOverlappingRendering()); 4774 4775 overridingView = new MockOverlappingRenderingSubclass(mActivity, true); 4776 assertTrue(overridingView.hasOverlappingRendering()); 4777 overridingView.forceHasOverlappingRendering(false); 4778 assertFalse(overridingView.getHasOverlappingRendering()); 4779 assertTrue(overridingView.hasOverlappingRendering()); 4780 overridingView.forceHasOverlappingRendering(true); 4781 assertTrue(overridingView.getHasOverlappingRendering()); 4782 assertTrue(overridingView.hasOverlappingRendering()); 4783 } 4784 startDragAndDrop(View view, View.DragShadowBuilder shadowBuilder)4785 private boolean startDragAndDrop(View view, View.DragShadowBuilder shadowBuilder) { 4786 final int[] viewOnScreenXY = new int[2]; 4787 View decorView = mActivity.getWindow().getDecorView(); 4788 decorView.getLocationOnScreen(viewOnScreenXY); 4789 int xOnScreen = viewOnScreenXY[0] + decorView.getWidth() / 2; 4790 int yOnScreen = viewOnScreenXY[1] + decorView.getHeight() / 2; 4791 4792 final MotionEvent event = MotionEvent.obtain( 4793 SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), 4794 MotionEvent.ACTION_DOWN, xOnScreen, yOnScreen, 1); 4795 event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 4796 event.setDisplayId(mActivity.getDisplayId()); 4797 mInstrumentation.sendPointerSync(event); 4798 4799 return view.startDragAndDrop(ClipData.newPlainText("", ""), shadowBuilder, view, 0); 4800 } 4801 createDragShadowBuidler()4802 private static View.DragShadowBuilder createDragShadowBuidler() { 4803 View.DragShadowBuilder shadowBuilder = mock(View.DragShadowBuilder.class); 4804 doAnswer(a -> { 4805 final Point outPoint = (Point) a.getArguments()[0]; 4806 outPoint.x = 1; 4807 outPoint.y = 1; 4808 return null; 4809 }).when(shadowBuilder).onProvideShadowMetrics(any(), any()); 4810 return shadowBuilder; 4811 } 4812 4813 @Test testUpdateDragShadow()4814 public void testUpdateDragShadow() { 4815 View view = mActivity.findViewById(R.id.fit_windows); 4816 assertTrue(view.isAttachedToWindow()); 4817 4818 final View.DragShadowBuilder shadowBuilder = createDragShadowBuidler(); 4819 try { 4820 assertTrue("Could not start drag and drop", startDragAndDrop(view, shadowBuilder)); 4821 reset(shadowBuilder); 4822 view.updateDragShadow(shadowBuilder); 4823 // TODO: Verify with the canvas from the drag surface instead. 4824 verify(shadowBuilder).onDrawShadow(any(Canvas.class)); 4825 } finally { 4826 // Ensure to cancel drag and drop operation so that it does not affect other tests. 4827 view.cancelDragAndDrop(); 4828 } 4829 } 4830 4831 @Test testUpdateDragShadow_detachedView()4832 public void testUpdateDragShadow_detachedView() { 4833 View view = new View(mActivity); 4834 assertFalse(view.isAttachedToWindow()); 4835 4836 View.DragShadowBuilder shadowBuilder = createDragShadowBuidler(); 4837 try { 4838 assertFalse("Drag and drop for detached view must fail", 4839 startDragAndDrop(view, shadowBuilder)); 4840 reset(shadowBuilder); 4841 4842 view.updateDragShadow(shadowBuilder); 4843 verify(shadowBuilder, never()).onDrawShadow(any(Canvas.class)); 4844 } finally { 4845 // Ensure to cancel drag and drop operation so that it does not affect other tests. 4846 view.cancelDragAndDrop(); 4847 } 4848 } 4849 4850 @Test testUpdateDragShadow_noActiveDrag()4851 public void testUpdateDragShadow_noActiveDrag() { 4852 View view = mActivity.findViewById(R.id.fit_windows); 4853 assertTrue(view.isAttachedToWindow()); 4854 4855 View.DragShadowBuilder shadowBuilder = createDragShadowBuidler(); 4856 view.updateDragShadow(shadowBuilder); 4857 verify(shadowBuilder, never()).onDrawShadow(any(Canvas.class)); 4858 } 4859 4860 /** 4861 * Test for velocity APIs - it requires the flag to be enabled. 4862 * To enable the flag: 4863 * adb shell device_config put toolkit android.view.flags.view_velocity_api true 4864 */ 4865 @Test 4866 @RequiresFlagsEnabled(FLAG_VIEW_VELOCITY_API) testVelocityAPIsFlagEnabled()4867 public void testVelocityAPIsFlagEnabled() throws Throwable { 4868 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 4869 view.reset(); 4870 mActivityRule.runOnUiThread(() -> { 4871 // The values of the velocities should be 0 by default 4872 assertTrue(view.getFrameContentVelocity() == 0); 4873 4874 view.setFrameContentVelocity(-10); 4875 assertTrue(view.getFrameContentVelocity() == 10); 4876 4877 view.setFrameContentVelocity(20); 4878 assertTrue(view.getFrameContentVelocity() == 20); 4879 4880 view.invalidate(); 4881 }); 4882 mInstrumentation.waitForIdleSync(); 4883 // the velocities should be reset once the view is drawn. 4884 assertTrue(view.getFrameContentVelocity() == 0); 4885 } 4886 4887 /** 4888 * Test for velocity APIs - it requires the flag to be disabled (default value). 4889 * To disable the flag: 4890 * adb shell device_config put toolkit android.view.flags.view_velocity_api false 4891 */ 4892 @Test 4893 @RequiresFlagsDisabled(FLAG_VIEW_VELOCITY_API) testVelocityAPIsFlagDisabled()4894 public void testVelocityAPIsFlagDisabled() throws Throwable { 4895 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 4896 view.reset(); 4897 mActivityRule.runOnUiThread(() -> { 4898 // The values of the velocities should be 0 by default 4899 assertTrue(view.getFrameContentVelocity() == 0); 4900 4901 view.setFrameContentVelocity(-10); 4902 assertTrue(view.getFrameContentVelocity() == 0); 4903 4904 view.setFrameContentVelocity(20); 4905 assertTrue(view.getFrameContentVelocity() == 0); 4906 4907 view.invalidate(); 4908 }); 4909 mInstrumentation.waitForIdleSync(); 4910 // the velocities should be reset once the view is drawn. 4911 assertTrue(view.getFrameContentVelocity() == 0); 4912 } 4913 4914 /** 4915 * Test for requested frame rate APIs 4916 */ 4917 @Test 4918 @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) testFrameRateAPIsFlagEnabled()4919 public void testFrameRateAPIsFlagEnabled() throws Throwable { 4920 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 4921 view.reset(); 4922 mActivityRule.runOnUiThread(() -> { 4923 // The values of the velocities should be 0 by default 4924 assertEquals(view.getRequestedFrameRate(), 4925 view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT, 0.1); 4926 4927 view.setRequestedFrameRate(10); 4928 assertEquals(view.getRequestedFrameRate(), 10, 0.1); 4929 4930 view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_LOW); 4931 assertEquals(view.getRequestedFrameRate(), view.REQUESTED_FRAME_RATE_CATEGORY_LOW, 0.1); 4932 4933 view.requestLayout(); 4934 }); 4935 4936 mInstrumentation.waitForIdleSync(); 4937 // the value should be remained the same 4938 assertEquals(view.getRequestedFrameRate(), view.REQUESTED_FRAME_RATE_CATEGORY_LOW, 0.1); 4939 } 4940 4941 /** 4942 * Test for requested frame rate APIs 4943 */ 4944 @Test 4945 @RequiresFlagsDisabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) testFrameRateAPIsFlagDisabled()4946 public void testFrameRateAPIsFlagDisabled() throws Throwable { 4947 final MockView view = (MockView) mActivity.findViewById(R.id.mock_view); 4948 view.reset(); 4949 mActivityRule.runOnUiThread(() -> { 4950 // The values of the velocities should be 0 by default 4951 assertEquals(view.getRequestedFrameRate(), 0, 0.1); 4952 4953 view.setRequestedFrameRate(10); 4954 assertEquals(view.getRequestedFrameRate(), 0, 0.1); 4955 4956 view.setRequestedFrameRate(-1); 4957 assertEquals(view.getRequestedFrameRate(), 0, 0.1); 4958 4959 view.requestLayout(); 4960 }); 4961 4962 mInstrumentation.waitForIdleSync(); 4963 // the value should be 0 4964 assertEquals(view.getRequestedFrameRate(), 0, 0.1); 4965 } 4966 setVisibilityOnUiThread(final View view, final int visibility)4967 private void setVisibilityOnUiThread(final View view, final int visibility) throws Throwable { 4968 mActivityRule.runOnUiThread(() -> view.setVisibility(visibility)); 4969 } 4970 4971 private static class MockOverlappingRenderingSubclass extends View { 4972 boolean mOverlap; 4973 MockOverlappingRenderingSubclass(Context context, boolean overlap)4974 public MockOverlappingRenderingSubclass(Context context, boolean overlap) { 4975 super(context); 4976 mOverlap = overlap; 4977 } 4978 4979 @Override hasOverlappingRendering()4980 public boolean hasOverlappingRendering() { 4981 return mOverlap; 4982 } 4983 } 4984 4985 private static class MockViewGroup extends ViewGroup { 4986 boolean isStartActionModeForChildCalled = false; 4987 int startActionModeForChildType = ActionMode.TYPE_PRIMARY; 4988 MockViewGroup(Context context)4989 public MockViewGroup(Context context) { 4990 super(context); 4991 } 4992 4993 @Override startActionModeForChild(View originalView, ActionMode.Callback callback)4994 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { 4995 isStartActionModeForChildCalled = true; 4996 startActionModeForChildType = ActionMode.TYPE_PRIMARY; 4997 return NO_OP_ACTION_MODE; 4998 } 4999 5000 @Override startActionModeForChild( View originalView, ActionMode.Callback callback, int type)5001 public ActionMode startActionModeForChild( 5002 View originalView, ActionMode.Callback callback, int type) { 5003 isStartActionModeForChildCalled = true; 5004 startActionModeForChildType = type; 5005 return NO_OP_ACTION_MODE; 5006 } 5007 5008 @Override onLayout(boolean changed, int l, int t, int r, int b)5009 protected void onLayout(boolean changed, int l, int t, int r, int b) { 5010 // no-op 5011 } 5012 } 5013 5014 private static final ActionMode NO_OP_ACTION_MODE = 5015 new ActionMode() { 5016 @Override 5017 public void setTitle(CharSequence title) {} 5018 5019 @Override 5020 public void setTitle(int resId) {} 5021 5022 @Override 5023 public void setSubtitle(CharSequence subtitle) {} 5024 5025 @Override 5026 public void setSubtitle(int resId) {} 5027 5028 @Override 5029 public void setCustomView(View view) {} 5030 5031 @Override 5032 public void invalidate() {} 5033 5034 @Override 5035 public void finish() {} 5036 5037 @Override 5038 public Menu getMenu() { 5039 return null; 5040 } 5041 5042 @Override 5043 public CharSequence getTitle() { 5044 return null; 5045 } 5046 5047 @Override 5048 public CharSequence getSubtitle() { 5049 return null; 5050 } 5051 5052 @Override 5053 public View getCustomView() { 5054 return null; 5055 } 5056 5057 @Override 5058 public MenuInflater getMenuInflater() { 5059 return null; 5060 } 5061 }; 5062 5063 @Test testTranslationSetter()5064 public void testTranslationSetter() { 5065 View view = new View(mActivity); 5066 float offset = 10.0f; 5067 view.setTranslationX(offset); 5068 view.setTranslationY(offset); 5069 view.setTranslationZ(offset); 5070 view.setElevation(offset); 5071 5072 assertEquals("Incorrect translationX", offset, view.getTranslationX(), 0.0f); 5073 assertEquals("Incorrect translationY", offset, view.getTranslationY(), 0.0f); 5074 assertEquals("Incorrect translationZ", offset, view.getTranslationZ(), 0.0f); 5075 assertEquals("Incorrect elevation", offset, view.getElevation(), 0.0f); 5076 } 5077 5078 @Test testXYZ()5079 public void testXYZ() { 5080 View view = new View(mActivity); 5081 float offset = 10.0f; 5082 float start = 15.0f; 5083 view.setTranslationX(offset); 5084 view.setLeft((int) start); 5085 view.setTranslationY(offset); 5086 view.setTop((int) start); 5087 view.setTranslationZ(offset); 5088 view.setElevation(start); 5089 5090 assertEquals("Incorrect X value", offset + start, view.getX(), 0.0f); 5091 assertEquals("Incorrect Y value", offset + start, view.getY(), 0.0f); 5092 assertEquals("Incorrect Z value", offset + start, view.getZ(), 0.0f); 5093 } 5094 5095 @Test testOnHoverEvent()5096 public void testOnHoverEvent() { 5097 MotionEvent event; 5098 5099 View view = new View(mActivity); 5100 long downTime = SystemClock.uptimeMillis(); 5101 5102 // Preconditions. 5103 assertFalse(view.isHovered()); 5104 assertFalse(view.isClickable()); 5105 assertTrue(view.isEnabled()); 5106 5107 // Simulate an ENTER/EXIT pair on a non-clickable view. 5108 event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0); 5109 view.onHoverEvent(event); 5110 assertFalse(view.isHovered()); 5111 event.recycle(); 5112 5113 event = MotionEvent.obtain(downTime, downTime + 10, MotionEvent.ACTION_HOVER_EXIT, 0, 0, 0); 5114 view.onHoverEvent(event); 5115 assertFalse(view.isHovered()); 5116 event.recycle(); 5117 5118 // Simulate an ENTER/EXIT pair on a clickable view. 5119 view.setClickable(true); 5120 5121 event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0); 5122 view.onHoverEvent(event); 5123 assertTrue(view.isHovered()); 5124 event.recycle(); 5125 5126 event = MotionEvent.obtain(downTime, downTime + 10, MotionEvent.ACTION_HOVER_EXIT, 0, 0, 0); 5127 view.onHoverEvent(event); 5128 assertFalse(view.isHovered()); 5129 event.recycle(); 5130 5131 // Simulate an ENTER, then disable the view and simulate EXIT. 5132 event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0); 5133 view.onHoverEvent(event); 5134 assertTrue(view.isHovered()); 5135 event.recycle(); 5136 5137 view.setEnabled(false); 5138 5139 event = MotionEvent.obtain(downTime, downTime + 10, MotionEvent.ACTION_HOVER_EXIT, 0, 0, 0); 5140 view.onHoverEvent(event); 5141 assertFalse(view.isHovered()); 5142 event.recycle(); 5143 } 5144 5145 @Test(expected = IllegalArgumentException.class) testScaleXNaN()5146 public void testScaleXNaN() { 5147 View view = new View(mContext); 5148 view.setScaleX(Float.NaN); 5149 } 5150 5151 @Test(expected = IllegalArgumentException.class) testScaleXPositiveInfinity()5152 public void testScaleXPositiveInfinity() { 5153 View view = new View(mContext); 5154 view.setScaleX(Float.POSITIVE_INFINITY); 5155 } 5156 5157 @Test(expected = IllegalArgumentException.class) testScaleXNegativeInfinity()5158 public void testScaleXNegativeInfinity() { 5159 View view = new View(mContext); 5160 view.setScaleX(Float.NEGATIVE_INFINITY); 5161 } 5162 5163 @Test(expected = IllegalArgumentException.class) testScaleYNaN()5164 public void testScaleYNaN() { 5165 View view = new View(mContext); 5166 view.setScaleY(Float.NaN); 5167 } 5168 5169 @Test(expected = IllegalArgumentException.class) testScaleYPositiveInfinity()5170 public void testScaleYPositiveInfinity() { 5171 View view = new View(mContext); 5172 view.setScaleY(Float.POSITIVE_INFINITY); 5173 } 5174 5175 @Test(expected = IllegalArgumentException.class) testScaleYNegativeInfinity()5176 public void testScaleYNegativeInfinity() { 5177 View view = new View(mContext); 5178 view.setScaleY(Float.NEGATIVE_INFINITY); 5179 } 5180 5181 @Test testTransitionAlpha()5182 public void testTransitionAlpha() { 5183 View view = new View(mContext); 5184 view.setAlpha(1f); 5185 view.setTransitionAlpha(0.5f); 5186 5187 assertEquals(1f, view.getAlpha(), 0.0001f); 5188 assertEquals(0.5f, view.getTransitionAlpha(), 0.0001f); 5189 } 5190 5191 @Test testSetGetOutlineShadowColor()5192 public void testSetGetOutlineShadowColor() { 5193 ViewGroup group = (ViewGroup) LayoutInflater.from(mContext).inflate( 5194 R.layout.view_outlineshadowcolor, null); 5195 View defaultShadow = group.findViewById(R.id.default_shadow); 5196 assertEquals(Color.BLACK, defaultShadow.getOutlineSpotShadowColor()); 5197 assertEquals(Color.BLACK, defaultShadow.getOutlineAmbientShadowColor()); 5198 defaultShadow.setOutlineSpotShadowColor(Color.YELLOW); 5199 defaultShadow.setOutlineAmbientShadowColor(Color.GREEN); 5200 assertEquals(Color.YELLOW, defaultShadow.getOutlineSpotShadowColor()); 5201 assertEquals(Color.GREEN, defaultShadow.getOutlineAmbientShadowColor()); 5202 5203 View redAmbientShadow = group.findViewById(R.id.red_shadow); 5204 assertEquals(Color.RED, redAmbientShadow.getOutlineAmbientShadowColor()); 5205 assertEquals(Color.BLACK, redAmbientShadow.getOutlineSpotShadowColor()); 5206 5207 View blueSpotShadow = group.findViewById(R.id.blue_shadow); 5208 assertEquals(Color.BLUE, blueSpotShadow.getOutlineSpotShadowColor()); 5209 assertEquals(Color.BLACK, blueSpotShadow.getOutlineAmbientShadowColor()); 5210 5211 View greenShadow = group.findViewById(R.id.green_shadow); 5212 assertEquals(Color.GREEN, greenShadow.getOutlineSpotShadowColor()); 5213 assertEquals(Color.GREEN, greenShadow.getOutlineAmbientShadowColor()); 5214 } 5215 5216 @Test testTransformMatrixToGlobal()5217 public void testTransformMatrixToGlobal() { 5218 final View view = mActivity.findViewById(R.id.transform_matrix_view); 5219 final Matrix initialMatrix = view.getMatrix(); 5220 assertNotNull(initialMatrix); 5221 5222 final Matrix newMatrix = new Matrix(initialMatrix); 5223 float[] initialValues = new float[9]; 5224 newMatrix.getValues(initialValues); 5225 5226 view.transformMatrixToGlobal(newMatrix); 5227 float[] newValues = new float[9]; 5228 newMatrix.getValues(newValues); 5229 int[] location = new int[2]; 5230 view.getLocationOnScreen(location); 5231 boolean hasChanged = false; 5232 for (int i = 0; i < 9; ++i) { 5233 if (initialValues[i] != newValues[i]) { 5234 hasChanged = true; 5235 } 5236 } 5237 assertTrue("Matrix should be changed", hasChanged); 5238 assertEquals("Matrix should reflect position on screen", 5239 location[1], newValues[5], 0.001); 5240 } 5241 5242 @Test testTransformMatrixToLocal()5243 public void testTransformMatrixToLocal() { 5244 final View view1 = mActivity.findViewById(R.id.transform_matrix_view); 5245 final View view2 = mActivity.findViewById(R.id.transform_matrix_view_2); 5246 final Matrix initialMatrix = view1.getMatrix(); 5247 assertNotNull(initialMatrix); 5248 5249 final Matrix globalMatrix = new Matrix(initialMatrix); 5250 5251 view1.transformMatrixToGlobal(globalMatrix); 5252 float[] globalValues = new float[9]; 5253 globalMatrix.getValues(globalValues); 5254 5255 view2.transformMatrixToLocal(globalMatrix); 5256 float[] localValues = new float[9]; 5257 globalMatrix.getValues(localValues); 5258 5259 boolean hasChanged = false; 5260 for (int i = 0; i < 9; ++i) { 5261 if (globalValues[i] != localValues[i]) { 5262 hasChanged = true; 5263 } 5264 } 5265 assertTrue("Matrix should be changed", hasChanged); 5266 assertEquals("The first view should be 10px above the second view", 5267 -10, localValues[5], 0.001); 5268 } 5269 5270 @Test testPivot()5271 public void testPivot() { 5272 View view = new View(mContext); 5273 int widthSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY); 5274 int heightSpec = View.MeasureSpec.makeMeasureSpec(200, View.MeasureSpec.EXACTLY); 5275 view.measure(widthSpec, heightSpec); 5276 assertEquals(100, view.getMeasuredWidth()); 5277 assertEquals(200, view.getMeasuredHeight()); 5278 view.layout(0, 0, 100, 200); 5279 assertEquals(100, view.getWidth()); 5280 assertEquals(200, view.getHeight()); 5281 5282 // Assert default pivot behavior 5283 assertEquals(50, view.getPivotX(), 0.0f); 5284 assertEquals(100, view.getPivotY(), 0.0f); 5285 assertFalse(view.isPivotSet()); 5286 5287 // Assert it changes as expected 5288 view.setPivotX(15); 5289 assertEquals(15, view.getPivotX(), 0.0f); 5290 assertEquals(100, view.getPivotY(), 0.0f); 5291 assertTrue(view.isPivotSet()); 5292 view.setPivotY(0); 5293 assertEquals(0, view.getPivotY(), 0.0f); 5294 assertTrue(view.isPivotSet()); 5295 5296 // Asset resetting back to default 5297 view.resetPivot(); 5298 assertEquals(50, view.getPivotX(), 0.0f); 5299 assertEquals(100, view.getPivotY(), 0.0f); 5300 assertFalse(view.isPivotSet()); 5301 } 5302 5303 @Test testSetLeftTopRightBottom()5304 public void testSetLeftTopRightBottom() { 5305 View view = new View(mContext); 5306 view.setLeftTopRightBottom(1, 2, 3, 4); 5307 5308 assertEquals(1, view.getLeft()); 5309 assertEquals(2, view.getTop()); 5310 assertEquals(3, view.getRight()); 5311 assertEquals(4, view.getBottom()); 5312 } 5313 5314 @Test testGetUniqueDrawingId()5315 public void testGetUniqueDrawingId() { 5316 View view1 = new View(mContext); 5317 View view2 = new View(mContext); 5318 Set<Long> idSet = new HashSet<>(50); 5319 5320 assertNotEquals(view1.getUniqueDrawingId(), view2.getUniqueDrawingId()); 5321 5322 for (int i = 0; i < 50; i++) { 5323 assertTrue(idSet.add(new View(mContext).getUniqueDrawingId())); 5324 } 5325 } 5326 5327 @Test testSetVerticalScrollbarTrack()5328 public void testSetVerticalScrollbarTrack() { 5329 View view = new View(mContext); 5330 5331 ColorDrawable colorDrawable = new ColorDrawable(Color.CYAN); 5332 view.setVerticalScrollbarTrackDrawable(colorDrawable); 5333 5334 Drawable verticalTrackDrawable = view.getVerticalScrollbarTrackDrawable(); 5335 assertTrue(verticalTrackDrawable instanceof ColorDrawable); 5336 assertEquals(Color.CYAN, ((ColorDrawable) verticalTrackDrawable).getColor()); 5337 } 5338 5339 @Test testSetVerticalScrollbarThumb()5340 public void testSetVerticalScrollbarThumb() { 5341 5342 View view = new View(mContext); 5343 5344 ColorDrawable colorDrawable = new ColorDrawable(Color.CYAN); 5345 view.setVerticalScrollbarThumbDrawable(colorDrawable); 5346 5347 Drawable verticalThumbDrawable = view.getVerticalScrollbarThumbDrawable(); 5348 assertTrue(verticalThumbDrawable instanceof ColorDrawable); 5349 assertEquals(Color.CYAN, ((ColorDrawable) verticalThumbDrawable).getColor()); 5350 } 5351 5352 @Test testSetHorizontalScrollbarTrack()5353 public void testSetHorizontalScrollbarTrack() { 5354 5355 View view = new View(mContext); 5356 5357 ColorDrawable colorDrawable = new ColorDrawable(Color.CYAN); 5358 view.setHorizontalScrollbarTrackDrawable(colorDrawable); 5359 5360 Drawable horizontalTrackDrawable = view.getHorizontalScrollbarTrackDrawable(); 5361 assertTrue(horizontalTrackDrawable instanceof ColorDrawable); 5362 assertEquals(Color.CYAN, ((ColorDrawable) horizontalTrackDrawable).getColor()); 5363 } 5364 5365 @Test testSetHorizontalScrollbarThumb()5366 public void testSetHorizontalScrollbarThumb() { 5367 5368 View view = new View(mContext); 5369 5370 ColorDrawable colorDrawable = new ColorDrawable(Color.CYAN); 5371 view.setHorizontalScrollbarThumbDrawable(colorDrawable); 5372 5373 Drawable horizontalThumbDrawable = view.getHorizontalScrollbarThumbDrawable(); 5374 assertTrue(horizontalThumbDrawable instanceof ColorDrawable); 5375 assertEquals(Color.CYAN, ((ColorDrawable) horizontalThumbDrawable).getColor()); 5376 } 5377 5378 @Test testSetTransitionVisibility()5379 public void testSetTransitionVisibility() { 5380 MockView view = new MockView(mContext); 5381 view.setVisibility(View.GONE); 5382 view.setParent(mMockParent); 5383 mMockParent.reset(); 5384 5385 // setTransitionVisibility shouldn't trigger requestLayout() on the parent 5386 view.setTransitionVisibility(View.VISIBLE); 5387 5388 assertEquals(View.VISIBLE, view.getVisibility()); 5389 assertFalse(mMockParent.hasRequestLayout()); 5390 5391 // Reset state 5392 view.setVisibility(View.GONE); 5393 mMockParent.reset(); 5394 5395 // setVisibility should trigger requestLayout() on the parent 5396 view.setVisibility(View.VISIBLE); 5397 5398 assertEquals(View.VISIBLE, view.getVisibility()); 5399 assertTrue(mMockParent.hasRequestLayout()); 5400 } 5401 5402 @UiThreadTest 5403 @Test testIsShowingLayoutBounds()5404 public void testIsShowingLayoutBounds() { 5405 final View view = new View(mContext); 5406 5407 // detached view should not have debug enabled 5408 assertFalse(view.isShowingLayoutBounds()); 5409 5410 mActivity.setContentView(view); 5411 view.setShowingLayoutBounds(true); 5412 5413 assertTrue(view.isShowingLayoutBounds()); 5414 mActivity.setContentView(new View(mContext)); 5415 5416 // now that it is detached, it should be false. 5417 assertFalse(view.isShowingLayoutBounds()); 5418 } 5419 5420 @Test testClipToOutline()5421 public void testClipToOutline() { 5422 View clipToOutlineUnsetView = mActivity.findViewById(R.id.clip_to_outline_unset); 5423 assertFalse(clipToOutlineUnsetView.getClipToOutline()); 5424 clipToOutlineUnsetView.setClipToOutline(true); 5425 assertTrue(clipToOutlineUnsetView.getClipToOutline()); 5426 clipToOutlineUnsetView.setClipToOutline(false); 5427 assertFalse(clipToOutlineUnsetView.getClipToOutline()); 5428 5429 View clipToOutlineFalseView = mActivity.findViewById(R.id.clip_to_outline_false); 5430 assertFalse(clipToOutlineFalseView.getClipToOutline()); 5431 clipToOutlineFalseView.setClipToOutline(true); 5432 assertTrue(clipToOutlineFalseView.getClipToOutline()); 5433 clipToOutlineFalseView.setClipToOutline(false); 5434 assertFalse(clipToOutlineFalseView.getClipToOutline()); 5435 5436 View clipToOutlineTrueView = mActivity.findViewById(R.id.clip_to_outline_true); 5437 assertTrue(clipToOutlineTrueView.getClipToOutline()); 5438 clipToOutlineTrueView.setClipToOutline(false); 5439 assertFalse(clipToOutlineTrueView.getClipToOutline()); 5440 clipToOutlineTrueView.setClipToOutline(true); 5441 assertTrue(clipToOutlineTrueView.getClipToOutline()); 5442 } 5443 5444 private static class MockDrawable extends Drawable { 5445 private boolean mCalledSetTint = false; 5446 5447 @Override draw(Canvas canvas)5448 public void draw(Canvas canvas) {} 5449 5450 @Override setAlpha(int alpha)5451 public void setAlpha(int alpha) {} 5452 5453 @Override setColorFilter(ColorFilter cf)5454 public void setColorFilter(ColorFilter cf) {} 5455 5456 @Override getOpacity()5457 public int getOpacity() { 5458 return 0; 5459 } 5460 5461 @Override setTintList(ColorStateList tint)5462 public void setTintList(ColorStateList tint) { 5463 super.setTintList(tint); 5464 mCalledSetTint = true; 5465 } 5466 hasCalledSetTint()5467 public boolean hasCalledSetTint() { 5468 return mCalledSetTint; 5469 } 5470 reset()5471 public void reset() { 5472 mCalledSetTint = false; 5473 } 5474 } 5475 5476 private static class MockEditText extends EditText { 5477 private boolean mCalledCheckInputConnectionProxy = false; 5478 private boolean mCalledOnCreateInputConnection = false; 5479 private boolean mCalledOnCheckIsTextEditor = false; 5480 MockEditText(Context context)5481 public MockEditText(Context context) { 5482 super(context); 5483 } 5484 5485 @Override checkInputConnectionProxy(View view)5486 public boolean checkInputConnectionProxy(View view) { 5487 mCalledCheckInputConnectionProxy = true; 5488 return super.checkInputConnectionProxy(view); 5489 } 5490 hasCalledCheckInputConnectionProxy()5491 public boolean hasCalledCheckInputConnectionProxy() { 5492 return mCalledCheckInputConnectionProxy; 5493 } 5494 5495 @Override onCreateInputConnection(EditorInfo outAttrs)5496 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 5497 mCalledOnCreateInputConnection = true; 5498 return super.onCreateInputConnection(outAttrs); 5499 } 5500 hasCalledOnCreateInputConnection()5501 public boolean hasCalledOnCreateInputConnection() { 5502 return mCalledOnCreateInputConnection; 5503 } 5504 5505 @Override onCheckIsTextEditor()5506 public boolean onCheckIsTextEditor() { 5507 mCalledOnCheckIsTextEditor = true; 5508 return super.onCheckIsTextEditor(); 5509 } 5510 hasCalledOnCheckIsTextEditor()5511 public boolean hasCalledOnCheckIsTextEditor() { 5512 return mCalledOnCheckIsTextEditor; 5513 } 5514 reset()5515 public void reset() { 5516 mCalledCheckInputConnectionProxy = false; 5517 mCalledOnCreateInputConnection = false; 5518 mCalledOnCheckIsTextEditor = false; 5519 } 5520 } 5521 5522 private final static class MockViewParent extends ViewGroup { 5523 private boolean mHasRequestLayout = false; 5524 private boolean mHasCreateContextMenu = false; 5525 private boolean mHasShowContextMenuForChild = false; 5526 private boolean mHasShowContextMenuForChildXY = false; 5527 private boolean mHasChildDrawableStateChanged = false; 5528 private boolean mHasBroughtChildToFront = false; 5529 private boolean mShouldShowContextMenu = false; 5530 5531 private final static int[] DEFAULT_PARENT_STATE_SET = new int[] { 789 }; 5532 5533 @Override requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)5534 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, 5535 boolean immediate) { 5536 return false; 5537 } 5538 MockViewParent(Context context)5539 public MockViewParent(Context context) { 5540 super(context); 5541 } 5542 setShouldShowContextMenu(boolean shouldShowContextMenu)5543 void setShouldShowContextMenu(boolean shouldShowContextMenu) { 5544 mShouldShowContextMenu = shouldShowContextMenu; 5545 } 5546 5547 @Override bringChildToFront(View child)5548 public void bringChildToFront(View child) { 5549 mHasBroughtChildToFront = true; 5550 } 5551 hasBroughtChildToFront()5552 public boolean hasBroughtChildToFront() { 5553 return mHasBroughtChildToFront; 5554 } 5555 5556 @Override childDrawableStateChanged(View child)5557 public void childDrawableStateChanged(View child) { 5558 mHasChildDrawableStateChanged = true; 5559 } 5560 hasChildDrawableStateChanged()5561 public boolean hasChildDrawableStateChanged() { 5562 return mHasChildDrawableStateChanged; 5563 } 5564 5565 @Override dispatchSetPressed(boolean pressed)5566 public void dispatchSetPressed(boolean pressed) { 5567 super.dispatchSetPressed(pressed); 5568 } 5569 5570 @Override dispatchSetSelected(boolean selected)5571 public void dispatchSetSelected(boolean selected) { 5572 super.dispatchSetSelected(selected); 5573 } 5574 5575 @Override clearChildFocus(View child)5576 public void clearChildFocus(View child) { 5577 5578 } 5579 5580 @Override createContextMenu(ContextMenu menu)5581 public void createContextMenu(ContextMenu menu) { 5582 mHasCreateContextMenu = true; 5583 } 5584 hasCreateContextMenu()5585 public boolean hasCreateContextMenu() { 5586 return mHasCreateContextMenu; 5587 } 5588 5589 @Override focusSearch(View v, int direction)5590 public View focusSearch(View v, int direction) { 5591 return v; 5592 } 5593 5594 @Override focusableViewAvailable(View v)5595 public void focusableViewAvailable(View v) { 5596 5597 } 5598 5599 @Override getChildVisibleRect(View child, Rect r, Point offset)5600 public boolean getChildVisibleRect(View child, Rect r, Point offset) { 5601 return false; 5602 } 5603 5604 @Override onLayout(boolean changed, int l, int t, int r, int b)5605 protected void onLayout(boolean changed, int l, int t, int r, int b) { 5606 5607 } 5608 5609 @Override invalidateChildInParent(int[] location, Rect r)5610 public ViewParent invalidateChildInParent(int[] location, Rect r) { 5611 return null; 5612 } 5613 5614 @Override isLayoutRequested()5615 public boolean isLayoutRequested() { 5616 return false; 5617 } 5618 5619 @Override recomputeViewAttributes(View child)5620 public void recomputeViewAttributes(View child) { 5621 5622 } 5623 5624 @Override requestChildFocus(View child, View focused)5625 public void requestChildFocus(View child, View focused) { 5626 5627 } 5628 5629 @Override requestDisallowInterceptTouchEvent(boolean disallowIntercept)5630 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 5631 5632 } 5633 5634 @Override requestLayout()5635 public void requestLayout() { 5636 mHasRequestLayout = true; 5637 } 5638 hasRequestLayout()5639 public boolean hasRequestLayout() { 5640 return mHasRequestLayout; 5641 } 5642 5643 @Override requestTransparentRegion(View child)5644 public void requestTransparentRegion(View child) { 5645 5646 } 5647 5648 @Override showContextMenuForChild(View originalView)5649 public boolean showContextMenuForChild(View originalView) { 5650 mHasShowContextMenuForChild = true; 5651 return mShouldShowContextMenu; 5652 } 5653 5654 @Override showContextMenuForChild(View originalView, float x, float y)5655 public boolean showContextMenuForChild(View originalView, float x, float y) { 5656 mHasShowContextMenuForChildXY = true; 5657 return mShouldShowContextMenu; 5658 } 5659 5660 @Override startActionModeForChild(View originalView, ActionMode.Callback callback)5661 public ActionMode startActionModeForChild(View originalView, 5662 ActionMode.Callback callback) { 5663 return null; 5664 } 5665 5666 @Override startActionModeForChild(View originalView, ActionMode.Callback callback, int type)5667 public ActionMode startActionModeForChild(View originalView, 5668 ActionMode.Callback callback, int type) { 5669 return null; 5670 } 5671 hasShowContextMenuForChild()5672 public boolean hasShowContextMenuForChild() { 5673 return mHasShowContextMenuForChild; 5674 } 5675 hasShowContextMenuForChildXY()5676 public boolean hasShowContextMenuForChildXY() { 5677 return mHasShowContextMenuForChildXY; 5678 } 5679 5680 @Override onCreateDrawableState(int extraSpace)5681 protected int[] onCreateDrawableState(int extraSpace) { 5682 return DEFAULT_PARENT_STATE_SET; 5683 } 5684 5685 @Override requestSendAccessibilityEvent(View child, AccessibilityEvent event)5686 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { 5687 return false; 5688 } 5689 reset()5690 public void reset() { 5691 mHasRequestLayout = false; 5692 mHasCreateContextMenu = false; 5693 mHasShowContextMenuForChild = false; 5694 mHasShowContextMenuForChildXY = false; 5695 mHasChildDrawableStateChanged = false; 5696 mHasBroughtChildToFront = false; 5697 mShouldShowContextMenu = false; 5698 } 5699 5700 @Override childHasTransientStateChanged(View child, boolean hasTransientState)5701 public void childHasTransientStateChanged(View child, boolean hasTransientState) { 5702 5703 } 5704 5705 @Override getParentForAccessibility()5706 public ViewParent getParentForAccessibility() { 5707 return null; 5708 } 5709 5710 @Override notifySubtreeAccessibilityStateChanged(View child, View source, int changeType)5711 public void notifySubtreeAccessibilityStateChanged(View child, 5712 View source, int changeType) { 5713 5714 } 5715 5716 @Override onStartNestedScroll(View child, View target, int nestedScrollAxes)5717 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { 5718 return false; 5719 } 5720 5721 @Override onNestedScrollAccepted(View child, View target, int nestedScrollAxes)5722 public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) { 5723 } 5724 5725 @Override onStopNestedScroll(View target)5726 public void onStopNestedScroll(View target) { 5727 } 5728 5729 @Override onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)5730 public void onNestedScroll(View target, int dxConsumed, int dyConsumed, 5731 int dxUnconsumed, int dyUnconsumed) { 5732 } 5733 5734 @Override onNestedPreScroll(View target, int dx, int dy, int[] consumed)5735 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { 5736 } 5737 5738 @Override onNestedFling(View target, float velocityX, float velocityY, boolean consumed)5739 public boolean onNestedFling(View target, float velocityX, float velocityY, 5740 boolean consumed) { 5741 return false; 5742 } 5743 5744 @Override onNestedPreFling(View target, float velocityX, float velocityY)5745 public boolean onNestedPreFling(View target, float velocityX, float velocityY) { 5746 return false; 5747 } 5748 5749 @Override onNestedPrePerformAccessibilityAction(View target, int action, Bundle args)5750 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) { 5751 return false; 5752 } 5753 } 5754 5755 private static class MockViewGroupParent extends ViewGroup implements ViewParent { 5756 private boolean mHasRequestChildRectangleOnScreen = false; 5757 private Rect mLastRequestedChildRectOnScreen = new Rect( 5758 Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); 5759 MockViewGroupParent(Context context)5760 public MockViewGroupParent(Context context) { 5761 super(context); 5762 } 5763 5764 @Override onLayout(boolean changed, int l, int t, int r, int b)5765 protected void onLayout(boolean changed, int l, int t, int r, int b) { 5766 5767 } 5768 5769 @Override requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)5770 public boolean requestChildRectangleOnScreen(View child, 5771 Rect rectangle, boolean immediate) { 5772 mHasRequestChildRectangleOnScreen = true; 5773 mLastRequestedChildRectOnScreen.set(rectangle); 5774 return super.requestChildRectangleOnScreen(child, rectangle, immediate); 5775 } 5776 getLastRequestedChildRectOnScreen()5777 public Rect getLastRequestedChildRectOnScreen() { 5778 return mLastRequestedChildRectOnScreen; 5779 } 5780 hasRequestChildRectangleOnScreen()5781 public boolean hasRequestChildRectangleOnScreen() { 5782 return mHasRequestChildRectangleOnScreen; 5783 } 5784 5785 @Override detachViewFromParent(View child)5786 protected void detachViewFromParent(View child) { 5787 super.detachViewFromParent(child); 5788 } 5789 reset()5790 public void reset() { 5791 mHasRequestChildRectangleOnScreen = false; 5792 } 5793 } 5794 5795 private static final class ViewData { 5796 public int childCount; 5797 public String tag; 5798 public View firstChild; 5799 } 5800 5801 private static class MockUnhandledKeyListener implements OnUnhandledKeyEventListener { 5802 public View mLastView = null; 5803 public boolean mGotUp = false; 5804 public boolean mReturnVal = false; 5805 5806 @Override onUnhandledKeyEvent(View v, KeyEvent event)5807 public boolean onUnhandledKeyEvent(View v, KeyEvent event) { 5808 if (event.getAction() == KeyEvent.ACTION_DOWN) { 5809 mLastView = v; 5810 } else if (event.getAction() == KeyEvent.ACTION_UP) { 5811 mGotUp = true; 5812 } 5813 return mReturnVal; 5814 } reset()5815 public void reset() { 5816 mLastView = null; 5817 mGotUp = false; 5818 } fired()5819 public boolean fired() { 5820 return mLastView != null && mGotUp; 5821 } 5822 } 5823 5824 public static class ScrollTestView extends View { ScrollTestView(Context context)5825 public ScrollTestView(Context context) { 5826 super(context); 5827 } 5828 5829 @Override awakenScrollBars()5830 public boolean awakenScrollBars() { 5831 return super.awakenScrollBars(); 5832 } 5833 5834 @Override computeHorizontalScrollRange()5835 public int computeHorizontalScrollRange() { 5836 return super.computeHorizontalScrollRange(); 5837 } 5838 5839 @Override computeHorizontalScrollExtent()5840 public int computeHorizontalScrollExtent() { 5841 return super.computeHorizontalScrollExtent(); 5842 } 5843 5844 @Override computeVerticalScrollRange()5845 public int computeVerticalScrollRange() { 5846 return super.computeVerticalScrollRange(); 5847 } 5848 5849 @Override computeVerticalScrollExtent()5850 public int computeVerticalScrollExtent() { 5851 return super.computeVerticalScrollExtent(); 5852 } 5853 5854 @Override getHorizontalScrollbarHeight()5855 protected int getHorizontalScrollbarHeight() { 5856 return super.getHorizontalScrollbarHeight(); 5857 } 5858 } 5859 5860 private static final Class<?> ASYNC_INFLATE_VIEWS[] = { 5861 android.app.FragmentBreadCrumbs.class, 5862 // DISABLED because it doesn't have a AppWidgetHostView(Context, AttributeSet) 5863 // constructor, so it's not inflate-able 5864 // android.appwidget.AppWidgetHostView.class, 5865 android.gesture.GestureOverlayView.class, 5866 android.inputmethodservice.ExtractEditText.class, 5867 android.inputmethodservice.KeyboardView.class, 5868 // android.media.tv.TvView.class, 5869 // android.opengl.GLSurfaceView.class, 5870 // android.view.SurfaceView.class, 5871 android.view.TextureView.class, 5872 android.view.ViewStub.class, 5873 // android.webkit.WebView.class, 5874 android.widget.AbsoluteLayout.class, 5875 android.widget.AdapterViewFlipper.class, 5876 android.widget.AnalogClock.class, 5877 android.widget.AutoCompleteTextView.class, 5878 android.widget.Button.class, 5879 android.widget.CalendarView.class, 5880 android.widget.CheckBox.class, 5881 android.widget.CheckedTextView.class, 5882 android.widget.Chronometer.class, 5883 android.widget.DatePicker.class, 5884 android.widget.DialerFilter.class, 5885 android.widget.DigitalClock.class, 5886 android.widget.EditText.class, 5887 android.widget.ExpandableListView.class, 5888 android.widget.FrameLayout.class, 5889 android.widget.Gallery.class, 5890 android.widget.GridView.class, 5891 android.widget.HorizontalScrollView.class, 5892 android.widget.ImageButton.class, 5893 android.widget.ImageSwitcher.class, 5894 android.widget.ImageView.class, 5895 android.widget.LinearLayout.class, 5896 android.widget.ListView.class, 5897 android.widget.MediaController.class, 5898 android.widget.MultiAutoCompleteTextView.class, 5899 android.widget.NumberPicker.class, 5900 android.widget.ProgressBar.class, 5901 android.widget.QuickContactBadge.class, 5902 android.widget.RadioButton.class, 5903 android.widget.RadioGroup.class, 5904 android.widget.RatingBar.class, 5905 android.widget.RelativeLayout.class, 5906 android.widget.ScrollView.class, 5907 android.widget.SeekBar.class, 5908 // DISABLED because it has required attributes 5909 // android.widget.SlidingDrawer.class, 5910 android.widget.Spinner.class, 5911 android.widget.StackView.class, 5912 android.widget.Switch.class, 5913 android.widget.TabHost.class, 5914 android.widget.TabWidget.class, 5915 android.widget.TableLayout.class, 5916 android.widget.TableRow.class, 5917 android.widget.TextClock.class, 5918 android.widget.TextSwitcher.class, 5919 android.widget.TextView.class, 5920 android.widget.TimePicker.class, 5921 android.widget.ToggleButton.class, 5922 android.widget.TwoLineListItem.class, 5923 // android.widget.VideoView.class, 5924 android.widget.ViewAnimator.class, 5925 android.widget.ViewFlipper.class, 5926 android.widget.ViewSwitcher.class, 5927 android.widget.ZoomButton.class, 5928 android.widget.ZoomControls.class, 5929 }; 5930 } 5931