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