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