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