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