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