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