1 /* 2 * Copyright (C) 2008 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 package android.app.cts; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.assertSame; 23 import static org.junit.Assert.assertTrue; 24 import static org.junit.Assert.fail; 25 import static org.junit.Assume.assumeFalse; 26 27 import android.app.Dialog; 28 import android.app.Instrumentation; 29 import android.app.stubs.DialogStubActivity; 30 import android.app.stubs.R; 31 import android.app.stubs.TestDialog; 32 import android.content.Context; 33 import android.content.DialogInterface; 34 import android.content.DialogInterface.OnCancelListener; 35 import android.content.DialogInterface.OnDismissListener; 36 import android.content.DialogInterface.OnKeyListener; 37 import android.content.pm.PackageManager; 38 import android.content.res.Resources; 39 import android.content.res.TypedArray; 40 import android.graphics.Canvas; 41 import android.graphics.ColorFilter; 42 import android.graphics.drawable.Drawable; 43 import android.net.Uri; 44 import android.os.Handler; 45 import android.os.HandlerThread; 46 import android.os.Looper; 47 import android.os.Message; 48 import android.os.SystemClock; 49 import android.view.InputDevice; 50 import android.view.KeyEvent; 51 import android.view.LayoutInflater; 52 import android.view.MotionEvent; 53 import android.view.View; 54 import android.view.ViewConfiguration; 55 import android.view.ViewGroup; 56 import android.view.Window; 57 import android.view.WindowManager; 58 import android.widget.LinearLayout; 59 60 import androidx.test.annotation.UiThreadTest; 61 import androidx.test.core.app.ActivityScenario; 62 import androidx.test.ext.junit.runners.AndroidJUnit4; 63 import androidx.test.platform.app.InstrumentationRegistry; 64 65 import com.android.compatibility.common.util.PollingCheck; 66 67 import org.junit.After; 68 import org.junit.Before; 69 import org.junit.Test; 70 import org.junit.runner.RunWith; 71 72 import java.lang.ref.WeakReference; 73 74 @RunWith(AndroidJUnit4.class) 75 public class DialogTest { 76 77 /** 78 * please refer to Dialog 79 */ 80 private static final int DISMISS = 0x43; 81 private static final int CANCEL = 0x44; 82 83 private boolean mCalledCallback; 84 private boolean mIsKey0Listened; 85 private boolean mIsKey1Listened; 86 private boolean mOnCancelListenerCalled; 87 88 private Instrumentation mInstrumentation; 89 private Context mContext; 90 private ActivityScenario<DialogStubActivity> mScenario; 91 private DialogStubActivity mActivity; 92 93 @Before setup()94 public void setup() throws Throwable { 95 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 96 mContext = mInstrumentation.getContext(); 97 CtsAppTestUtils.turnScreenOn(mInstrumentation, mContext); 98 mInstrumentation.waitForIdleSync(); 99 } 100 101 @After tearDown()102 public void tearDown() { 103 if (mScenario != null) { 104 mScenario.close(); 105 mScenario = null; 106 } 107 } 108 startDialogActivity(int dialogNumber)109 private void startDialogActivity(int dialogNumber) { 110 mScenario = DialogStubActivity.startDialogActivity( 111 mInstrumentation.getTargetContext(), dialogNumber); 112 mScenario.onActivity(activity -> { 113 mActivity = activity; 114 }); 115 PollingCheck.waitFor(mActivity.getDialog().getWindow().getDecorView()::hasWindowFocus); 116 } 117 118 @UiThreadTest 119 @Test testConstructor()120 public void testConstructor() { 121 new Dialog(mContext); 122 Dialog d = new Dialog(mContext, 0); 123 // According to javadoc of constructors, it will set theme to system default theme, 124 // when we set no theme id or set it theme id to 0. 125 // But CTS can no assert dialog theme equals system internal theme. 126 127 d = new Dialog(mContext, R.style.TextAppearance); 128 TypedArray ta = 129 d.getContext().getTheme().obtainStyledAttributes(R.styleable.TextAppearance); 130 assertTextAppearanceStyle(ta); 131 132 final Window w = d.getWindow(); 133 ta = w.getContext().getTheme().obtainStyledAttributes(R.styleable.TextAppearance); 134 assertTextAppearanceStyle(ta); 135 } 136 137 @Test testConstructor_protectedCancellable()138 public void testConstructor_protectedCancellable() { 139 startDialogActivity(DialogStubActivity.TEST_PROTECTED_CANCELABLE); 140 mActivity.onCancelListenerCalled = false; 141 sendKeys(KeyEvent.KEYCODE_BACK); 142 PollingCheck.waitFor(() -> mActivity.onCancelListenerCalled); 143 } 144 145 @Test testConstructor_protectedNotCancellable()146 public void testConstructor_protectedNotCancellable() { 147 startDialogActivity(DialogStubActivity.TEST_PROTECTED_NOT_CANCELABLE); 148 mActivity.onCancelListenerCalled = false; 149 sendKeys(KeyEvent.KEYCODE_BACK); 150 assertFalse(mActivity.onCancelListenerCalled); 151 } 152 153 @Test testConstructor_protectedCancellableEsc()154 public void testConstructor_protectedCancellableEsc() { 155 startDialogActivity(DialogStubActivity.TEST_PROTECTED_CANCELABLE); 156 mActivity.onCancelListenerCalled = false; 157 sendKeys(KeyEvent.KEYCODE_ESCAPE); 158 PollingCheck.waitFor(() -> { 159 return mActivity.onCancelListenerCalled; }); 160 } 161 162 @Test testConstructor_protectedNotCancellableEsc()163 public void testConstructor_protectedNotCancellableEsc() { 164 startDialogActivity(DialogStubActivity.TEST_PROTECTED_NOT_CANCELABLE); 165 mActivity.onCancelListenerCalled = false; 166 sendKeys(KeyEvent.KEYCODE_ESCAPE); 167 assertFalse(mActivity.onCancelListenerCalled); 168 } 169 assertTextAppearanceStyle(TypedArray ta)170 private void assertTextAppearanceStyle(TypedArray ta) { 171 final int defValue = -1; 172 // get Theme and assert 173 final Resources.Theme expected = mContext.getResources().newTheme(); 174 expected.setTo(mContext.getTheme()); 175 expected.applyStyle(R.style.TextAppearance, true); 176 TypedArray expectedTa = expected.obtainStyledAttributes(R.styleable.TextAppearance); 177 assertEquals(expectedTa.getIndexCount(), ta.getIndexCount()); 178 assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColor, defValue), 179 ta.getColor(R.styleable.TextAppearance_textColor, defValue)); 180 assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorHint, defValue), 181 ta.getColor(R.styleable.TextAppearance_textColorHint, defValue)); 182 assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorLink, defValue), 183 ta.getColor(R.styleable.TextAppearance_textColorLink, defValue)); 184 assertEquals(expectedTa.getColor(R.styleable.TextAppearance_textColorHighlight, defValue), 185 ta.getColor(R.styleable.TextAppearance_textColorHighlight, defValue)); 186 assertEquals(expectedTa.getDimension(R.styleable.TextAppearance_textSize, defValue), 187 ta.getDimension(R.styleable.TextAppearance_textSize, defValue), Float.MIN_VALUE); 188 assertEquals(expectedTa.getInt(R.styleable.TextAppearance_textStyle, defValue), 189 ta.getInt(R.styleable.TextAppearance_textStyle, defValue)); 190 } 191 192 @Test testOnStartCreateStop()193 public void testOnStartCreateStop(){ 194 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 195 final TestDialog d = (TestDialog) mActivity.getDialog(); 196 197 assertTrue(d.isOnStartCalled); 198 assertTrue(d.isOnCreateCalled); 199 200 assertFalse(d.isOnStopCalled); 201 sendKeys(KeyEvent.KEYCODE_BACK); 202 PollingCheck.waitFor(() -> { 203 return d.isOnStopCalled; }); 204 } 205 206 @Test testOnStartCreateStopEsc()207 public void testOnStartCreateStopEsc(){ 208 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 209 final TestDialog d = (TestDialog) mActivity.getDialog(); 210 211 assertTrue(d.isOnStartCalled); 212 assertTrue(d.isOnCreateCalled); 213 214 assertFalse(d.isOnStopCalled); 215 sendKeys(KeyEvent.KEYCODE_ESCAPE); 216 PollingCheck.waitFor(() -> d.isOnStopCalled); 217 } 218 219 @Test testAccessOwnerActivity()220 public void testAccessOwnerActivity() throws Throwable { 221 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 222 Dialog d = mActivity.getDialog(); 223 assertNotNull(d); 224 assertSame(mActivity, d.getOwnerActivity()); 225 d.setVolumeControlStream(d.getVolumeControlStream() + 1); 226 assertEquals(d.getOwnerActivity().getVolumeControlStream() + 1, d.getVolumeControlStream()); 227 228 try { 229 d.setOwnerActivity(null); 230 fail("Should throw NullPointerException"); 231 } catch (NullPointerException e) { 232 // expected 233 } 234 235 mScenario.onActivity(activity -> { 236 Dialog dialog = new Dialog(mContext); 237 assertNull(dialog.getOwnerActivity()); 238 }); 239 mInstrumentation.waitForIdleSync(); 240 } 241 242 @Test testShow()243 public void testShow() throws Throwable { 244 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 245 final Dialog d = mActivity.getDialog(); 246 final View decor = d.getWindow().getDecorView(); 247 248 mScenario.onActivity(activity -> { 249 d.hide(); 250 }); 251 mInstrumentation.waitForIdleSync(); 252 253 assertEquals(View.GONE, decor.getVisibility()); 254 assertFalse(d.isShowing()); 255 256 mScenario.onActivity(activity -> { 257 d.show(); 258 }); 259 mInstrumentation.waitForIdleSync(); 260 261 assertEquals(View.VISIBLE, decor.getVisibility()); 262 assertTrue(d.isShowing()); 263 dialogDismiss(d); 264 assertFalse(d.isShowing()); 265 } 266 267 @Test testOnSaveInstanceState()268 public void testOnSaveInstanceState() throws InterruptedException { 269 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 270 final TestDialog d = (TestDialog) mActivity.getDialog(); 271 272 d.onSaveInstanceStateObserver.startObserving(); 273 TestDialog.onRestoreInstanceStateObserver.startObserving(); 274 mScenario.recreate(); 275 d.onSaveInstanceStateObserver.await(); 276 TestDialog.onRestoreInstanceStateObserver.await(); 277 } 278 279 @Test testGetCurrentFocus()280 public void testGetCurrentFocus() throws Throwable { 281 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 282 final TestDialog d = (TestDialog) mActivity.getDialog(); 283 assertNull(d.getCurrentFocus()); 284 285 mScenario.onActivity(activity -> { 286 d.takeKeyEvents(true); 287 d.setContentView(R.layout.alert_dialog_text_entry); 288 }); 289 mInstrumentation.waitForIdleSync(); 290 291 sendKeys(KeyEvent.KEYCODE_0); 292 // When mWindow is not null getCurrentFocus is the view in dialog 293 assertEquals(d.getWindow().getCurrentFocus(), d.getCurrentFocus()); 294 } 295 296 @Test testSetContentView()297 public void testSetContentView() throws Throwable { 298 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 299 final Dialog d = mActivity.getDialog(); 300 assertNotNull(d); 301 302 // set content view to a four elements layout 303 mScenario.onActivity(activity -> { 304 d.setContentView(R.layout.alert_dialog_text_entry); 305 }); 306 mInstrumentation.waitForIdleSync(); 307 308 // check if four elements are right there 309 assertNotNull(d.findViewById(R.id.username_view)); 310 assertNotNull(d.findViewById(R.id.username_edit)); 311 assertNotNull(d.findViewById(R.id.password_view)); 312 assertNotNull(d.findViewById(R.id.password_edit)); 313 314 final LayoutInflater inflate1 = d.getLayoutInflater(); 315 316 // set content view to a two elements layout 317 mScenario.onActivity(activity -> { 318 d.setContentView(inflate1.inflate(R.layout.alert_dialog_text_entry_2, null)); 319 }); 320 mInstrumentation.waitForIdleSync(); 321 322 // check if only two elements are right there 323 assertNotNull(d.findViewById(R.id.username_view)); 324 assertNotNull(d.findViewById(R.id.username_edit)); 325 assertNull(d.findViewById(R.id.password_view)); 326 assertNull(d.findViewById(R.id.password_edit)); 327 328 final WindowManager.LayoutParams lp = d.getWindow().getAttributes(); 329 final LayoutInflater inflate2 = mActivity.getLayoutInflater(); 330 331 // set content view to a four elements layout 332 mScenario.onActivity(activity -> { 333 d.setContentView(inflate2.inflate(R.layout.alert_dialog_text_entry, null), lp); 334 }); 335 mInstrumentation.waitForIdleSync(); 336 337 // check if four elements are right there 338 assertNotNull(d.findViewById(R.id.username_view)); 339 assertNotNull(d.findViewById(R.id.username_edit)); 340 assertNotNull(d.findViewById(R.id.password_view)); 341 assertNotNull(d.findViewById(R.id.password_edit)); 342 343 final WindowManager.LayoutParams lp2 = d.getWindow().getAttributes(); 344 final LayoutInflater inflate3 = mActivity.getLayoutInflater(); 345 lp2.height = ViewGroup.LayoutParams.WRAP_CONTENT; 346 lp2.width = ViewGroup.LayoutParams.WRAP_CONTENT; 347 348 // add a check box view 349 mScenario.onActivity(activity -> { 350 d.addContentView(inflate3.inflate(R.layout.checkbox_layout, null), lp2); 351 }); 352 mInstrumentation.waitForIdleSync(); 353 354 // check if four elements are right there, and new add view there. 355 assertNotNull(d.findViewById(R.id.check_box)); 356 assertNotNull(d.findViewById(R.id.username_view)); 357 assertNotNull(d.findViewById(R.id.username_edit)); 358 assertNotNull(d.findViewById(R.id.password_view)); 359 assertNotNull(d.findViewById(R.id.password_edit)); 360 } 361 362 @Test testRequireViewById()363 public void testRequireViewById() throws Throwable { 364 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 365 final Dialog d = mActivity.getDialog(); 366 assertNotNull(d); 367 368 // set content view to a four elements layout 369 mScenario.onActivity(activity -> { 370 d.setContentView(R.layout.alert_dialog_text_entry); 371 }); 372 mInstrumentation.waitForIdleSync(); 373 374 // check if four elements are right there 375 assertNotNull(d.requireViewById(R.id.username_view)); 376 assertNotNull(d.requireViewById(R.id.username_edit)); 377 assertNotNull(d.requireViewById(R.id.password_view)); 378 assertNotNull(d.requireViewById(R.id.password_edit)); 379 try { 380 d.requireViewById(R.id.check_box); // not present 381 fail("should not get here, check_box should not be found"); 382 } catch (IllegalArgumentException e) { 383 // expected 384 } 385 try { 386 d.requireViewById(View.NO_ID); // invalid 387 fail("should not get here, NO_ID should not be found"); 388 } catch (IllegalArgumentException e) { 389 // expected 390 } 391 } 392 393 394 @Test testSetTitle()395 public void testSetTitle() { 396 final String expectedTitle = "Test Dialog Without theme"; 397 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 398 399 assertNotNull(mActivity.getDialog()); 400 mActivity.setUpTitle(expectedTitle); 401 mInstrumentation.waitForIdleSync(); 402 403 final Dialog d = mActivity.getDialog(); 404 assertEquals(expectedTitle, (String) d.getWindow().getAttributes().getTitle()); 405 406 mActivity.setUpTitle(R.string.hello_android); 407 mInstrumentation.waitForIdleSync(); 408 assertEquals(mActivity.getResources().getString(R.string.hello_android), 409 (String) d.getWindow().getAttributes().getTitle()); 410 } 411 412 @Test testOnKeyDownKeyUp()413 public void testOnKeyDownKeyUp() { 414 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 415 final TestDialog d = (TestDialog) mActivity.getDialog(); 416 assertFalse(d.isOnKeyDownCalled); 417 assertFalse(d.isOnKeyUpCalled); 418 419 // send key 0 down and up events, onKeyDown return false 420 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0); 421 assertTrue(d.isOnKeyDownCalled); 422 assertTrue(d.isOnKeyUpCalled); 423 assertEquals(KeyEvent.KEYCODE_0, d.keyDownCode); 424 assertFalse(d.onKeyDownReturn); 425 426 // send key back down and up events, onKeyDown return true 427 mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK); 428 assertEquals(KeyEvent.KEYCODE_BACK, d.keyDownCode); 429 assertTrue(d.onKeyDownReturn); 430 } 431 432 @Test testOnKeyMultiple()433 public void testOnKeyMultiple() { 434 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 435 final TestDialog d = (TestDialog) mActivity.getDialog(); 436 437 assertNull(d.keyMultipleEvent); 438 d.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_UNKNOWN)); 439 assertTrue(d.isOnKeyMultipleCalled); 440 assertFalse(d.onKeyMultipleReturn); 441 assertEquals(KeyEvent.KEYCODE_UNKNOWN, d.keyMultipleEvent.getKeyCode()); 442 assertEquals(KeyEvent.ACTION_MULTIPLE, d.keyMultipleEvent.getAction()); 443 } 444 sendTouchEvent(long downTime, int action, float x, float y)445 private MotionEvent sendTouchEvent(long downTime, int action, float x, float y) { 446 long eventTime = downTime; 447 if (action != MotionEvent.ACTION_DOWN) { 448 eventTime += 1; 449 } 450 MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0); 451 event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 452 mInstrumentation.getUiAutomation().injectInputEvent(event, true); 453 mInstrumentation.waitForIdleSync(); 454 return event; 455 } 456 457 @Test testTouchEvent()458 public void testTouchEvent() { 459 // Watch activities cover the entire screen, so there is no way to touch outside. 460 assumeFalse(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)); 461 462 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 463 final TestDialog d = (TestDialog) mActivity.getDialog(); 464 465 int dialogLocation[] = new int[2]; 466 d.getWindow().getDecorView().getRootView().getLocationOnScreen(dialogLocation); 467 468 final int touchSlop = ViewConfiguration.get(mActivity).getScaledWindowTouchSlop(); 469 final int x = dialogLocation[0]; 470 final int y = dialogLocation[1] - (touchSlop + 1); 471 472 assertNull(d.onTouchEvent); 473 assertNull(d.touchEvent); 474 assertFalse(d.isOnTouchEventCalled); 475 476 // Tap outside the dialog window. Expect the event to be ignored 477 // because closeOnTouchOutside is false. 478 d.setCanceledOnTouchOutside(false); 479 480 long downTime = SystemClock.uptimeMillis(); 481 482 sendTouchEvent(downTime, MotionEvent.ACTION_DOWN, x, y).recycle(); 483 MotionEvent touchMotionEvent = sendTouchEvent(downTime, MotionEvent.ACTION_UP, x, y); 484 485 assertMotionEventEquals(touchMotionEvent, d.touchEvent); 486 assertTrue(d.isOnTouchEventCalled); 487 assertMotionEventEquals(touchMotionEvent, d.onTouchEvent); 488 d.isOnTouchEventCalled = false; 489 assertTrue(d.isShowing()); 490 touchMotionEvent.recycle(); 491 492 // Send a touch event outside the dialog window. Expect the dialog to be dismissed 493 // because closeOnTouchOutside is true. 494 d.setCanceledOnTouchOutside(true); 495 downTime = SystemClock.uptimeMillis(); 496 497 sendTouchEvent(downTime, MotionEvent.ACTION_DOWN, x, y).recycle(); 498 touchMotionEvent = sendTouchEvent(downTime, MotionEvent.ACTION_UP, x, y); 499 500 assertMotionEventEquals(touchMotionEvent, d.touchEvent); 501 assertTrue(d.isOnTouchEventCalled); 502 assertMotionEventEquals(touchMotionEvent, d.onTouchEvent); 503 assertFalse(d.isShowing()); 504 touchMotionEvent.recycle(); 505 } 506 507 @Test testTrackballEvent()508 public void testTrackballEvent() { 509 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 510 final TestDialog d = (TestDialog) mActivity.getDialog(); 511 long eventTime = SystemClock.uptimeMillis(); 512 final MotionEvent trackBallEvent = MotionEvent.obtain(eventTime, eventTime, 513 MotionEvent.ACTION_DOWN, 0.0f, 0.0f, 0); 514 515 assertNull(d.trackballEvent); 516 assertNull(d.onTrackballEvent); 517 518 assertFalse(d.isOnTrackballEventCalled); 519 mInstrumentation.sendTrackballEventSync(trackBallEvent); 520 assertTrue(d.isOnTrackballEventCalled); 521 assertMotionEventEquals(trackBallEvent, d.trackballEvent); 522 assertMotionEventEquals(trackBallEvent, d.onTrackballEvent); 523 524 } 525 assertMotionEventEquals(final MotionEvent expected, final MotionEvent actual)526 private void assertMotionEventEquals(final MotionEvent expected, final MotionEvent actual) { 527 assertNotNull(actual); 528 assertEquals(expected.getDownTime(), actual.getDownTime()); 529 assertEquals(expected.getEventTime(), actual.getEventTime()); 530 assertEquals(expected.getAction(), actual.getAction()); 531 assertEquals(expected.getMetaState(), actual.getMetaState()); 532 assertEquals(expected.getSize(), actual.getSize(), Float.MIN_VALUE); 533 // As MotionEvent doc says the value of X and Y coordinate may have 534 // a fraction for input devices that are sub-pixel precise, 535 // so we won't assert them here. 536 } 537 538 @Test testOnWindowAttributesChanged()539 public void testOnWindowAttributesChanged() throws Throwable { 540 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 541 final TestDialog d = (TestDialog) mActivity.getDialog(); 542 543 assertTrue(d.isOnWindowAttributesChangedCalled); 544 d.isOnWindowAttributesChangedCalled = false; 545 546 final WindowManager.LayoutParams lp = d.getWindow().getAttributes(); 547 lp.setTitle("test OnWindowAttributesChanged"); 548 mScenario.onActivity(activity -> { 549 d.getWindow().setAttributes(lp); 550 }); 551 mInstrumentation.waitForIdleSync(); 552 553 assertTrue(d.isOnWindowAttributesChangedCalled); 554 assertSame(lp, d.getWindow().getAttributes()); 555 } 556 557 @Test testOnContentChanged()558 public void testOnContentChanged() throws Throwable { 559 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 560 final TestDialog d = (TestDialog) mActivity.getDialog(); 561 assertNotNull(d); 562 563 assertFalse(d.isOnContentChangedCalled); 564 565 mScenario.onActivity(activity -> { 566 d.setContentView(R.layout.alert_dialog_text_entry); 567 }); 568 mInstrumentation.waitForIdleSync(); 569 570 assertTrue(d.isOnContentChangedCalled); 571 } 572 573 @Test testOnWindowFocusChanged()574 public void testOnWindowFocusChanged() throws Throwable { 575 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 576 final TestDialog d = (TestDialog) mActivity.getDialog(); 577 assertTrue(d.isOnWindowFocusChangedCalled); 578 d.isOnWindowFocusChangedCalled = false; 579 580 // show a new dialog, the new dialog get focus 581 mScenario.onActivity(activity -> { 582 mActivity.showDialog(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 583 }); 584 585 PollingCheck.waitFor(() -> d.isOnWindowFocusChangedCalled); 586 } 587 588 @Test testDispatchKeyEvent()589 public void testDispatchKeyEvent() { 590 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 591 final TestDialog d = (TestDialog) mActivity.getDialog(); 592 593 sendKeys(KeyEvent.KEYCODE_0); 594 assertFalse(d.dispatchKeyEventResult); 595 assertEquals(KeyEvent.KEYCODE_0, d.keyEvent.getKeyCode()); 596 597 d.setOnKeyListener(new OnKeyListener() { 598 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { 599 if (KeyEvent.ACTION_DOWN == event.getAction()) { 600 if (KeyEvent.KEYCODE_0 == keyCode) { 601 mIsKey0Listened = true; 602 return true; 603 } 604 605 if (KeyEvent.KEYCODE_1 == keyCode) { 606 mIsKey1Listened = true; 607 return true; 608 } 609 } 610 611 return false; 612 } 613 }); 614 615 mIsKey1Listened = false; 616 sendKeys(KeyEvent.KEYCODE_1); 617 assertTrue(mIsKey1Listened); 618 619 mIsKey0Listened = false; 620 sendKeys(KeyEvent.KEYCODE_0); 621 assertTrue(mIsKey0Listened); 622 } 623 624 /* 625 * Test point 626 * 1. registerForContextMenu() will OnCreateContextMenuListener on the view to this activity, 627 * so onCreateContextMenu() will be called when it is time to show the context menu. 628 * 2. Close context menu will make onPanelClosed to be called, 629 * and onPanelClosed will calls through to the new onPanelClosed method. 630 * 3. unregisterForContextMenu() will remove the OnCreateContextMenuListener on the view, 631 * so onCreateContextMenu() will not be called when try to open context menu. 632 * 4. Selected a item of context menu will make onMenuItemSelected() to be called, 633 * and onMenuItemSelected will calls through to the new onContextItemSelected method. 634 * 5. onContextMenuClosed is called whenever the context menu is being closed (either by 635 * the user canceling the menu with the back/menu button, or when an item is selected). 636 */ 637 @Test testContextMenu()638 public void testContextMenu() throws Throwable { 639 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 640 final TestDialog d = (TestDialog) mActivity.getDialog(); 641 final LinearLayout parent = new LinearLayout(mContext); 642 final MockView v = new MockView(mContext); 643 parent.addView(v); 644 assertFalse(v.isShowContextMenuCalled); 645 // Register for context menu and open it 646 mScenario.onActivity(activity -> { 647 d.addContentView(parent, new LinearLayout.LayoutParams( 648 ViewGroup.LayoutParams.MATCH_PARENT, 649 ViewGroup.LayoutParams.WRAP_CONTENT)); 650 d.registerForContextMenu(v); 651 d.openContextMenu(v); 652 }); 653 PollingCheck.waitFor(d::contextMenuHasWindowFocus); 654 PollingCheck.waitFor(() -> v.isShowContextMenuCalled); 655 PollingCheck.waitFor(() -> d.isOnCreateContextMenuCalled); 656 657 assertFalse(d.isOnPanelClosedCalled); 658 assertFalse(d.isOnContextMenuClosedCalled); 659 // Close context menu 660 d.isOnWindowFocusChangedCalled = false; 661 sendKeys(KeyEvent.KEYCODE_BACK); 662 PollingCheck.waitFor(() -> d.isOnPanelClosedCalled); 663 // Wait for window focus change after pressing back 664 PollingCheck.waitFor(() -> d.isOnWindowFocusChangedCalled); 665 // Here isOnContextMenuClosedCalled should be true, see bug 1716918. 666 assertFalse(d.isOnContextMenuClosedCalled); 667 668 v.isShowContextMenuCalled = false; 669 d.isOnCreateContextMenuCalled = false; 670 // Unregister for context menu, and try to open it 671 mScenario.onActivity(activity -> { 672 d.unregisterForContextMenu(v); 673 }); 674 675 mScenario.onActivity(activity -> { 676 d.openContextMenu(v); 677 }); 678 679 assertTrue(v.isShowContextMenuCalled); 680 assertFalse(d.isOnCreateContextMenuCalled); 681 682 // Register for context menu and open it again 683 v.isShowContextMenuCalled = false; 684 d.isOnCreateContextMenuCalled = false; 685 mScenario.onActivity(activity -> { 686 d.registerForContextMenu(v); 687 d.openContextMenu(v); 688 }); 689 PollingCheck.waitFor(() -> d.isOnCreateContextMenuCalled); 690 PollingCheck.waitFor(() -> v.isShowContextMenuCalled); 691 PollingCheck.waitFor(d::contextMenuHasWindowFocus); 692 693 assertFalse(d.isOnContextItemSelectedCalled); 694 assertFalse(d.isOnMenuItemSelectedCalled); 695 d.isOnPanelClosedCalled = false; 696 assertFalse(d.isOnContextMenuClosedCalled); 697 // select a context menu item 698 d.selectContextMenuItem(); 699 assertTrue(d.isOnMenuItemSelectedCalled); 700 // Here isOnContextItemSelectedCalled should be true, see bug 1716918. 701 assertFalse(d.isOnContextItemSelectedCalled); 702 PollingCheck.waitFor(() -> d.isOnPanelClosedCalled); 703 // Here isOnContextMenuClosedCalled should be true, see bug 1716918. 704 assertFalse(d.isOnContextMenuClosedCalled); 705 } 706 707 @Test testOnSearchRequested()708 public void testOnSearchRequested() { 709 } 710 711 @Test testTakeKeyEvents()712 public void testTakeKeyEvents() throws Throwable { 713 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 714 final TestDialog d = (TestDialog) mActivity.getDialog(); 715 final View v = d.getWindow().getDecorView(); 716 assertNull(d.getCurrentFocus()); 717 takeKeyEvents(d, true); 718 assertTrue(v.isFocusable()); 719 sendKeys(KeyEvent.KEYCODE_0); 720 assertEquals(KeyEvent.KEYCODE_0, d.keyEvent.getKeyCode()); 721 d.keyEvent = null; 722 723 takeKeyEvents(d, false); 724 assertNull(d.getCurrentFocus()); 725 assertFalse(v.isFocusable()); 726 sendKeys(KeyEvent.KEYCODE_0); 727 // d.keyEvent should be null 728 } 729 takeKeyEvents(final Dialog d, final boolean get)730 private void takeKeyEvents(final Dialog d, final boolean get) throws Throwable { 731 mScenario.onActivity(activity -> { 732 d.takeKeyEvents(get); 733 }); 734 } 735 736 @Test testRequestWindowFeature()737 public void testRequestWindowFeature() { 738 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 739 // called requestWindowFeature at TestDialog onCreate method 740 assertTrue(((TestDialog) mActivity.getDialog()).isRequestWindowFeature); 741 } 742 743 @Test testSetFeatureDrawableResource()744 public void testSetFeatureDrawableResource() throws Throwable { 745 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 746 mScenario.onActivity(activity -> { 747 mActivity.getDialog().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, 748 R.drawable.robot); 749 }); 750 mInstrumentation.waitForIdleSync(); 751 } 752 753 @Test testSetFeatureDrawableUri()754 public void testSetFeatureDrawableUri() throws Throwable { 755 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 756 mScenario.onActivity(activity -> { 757 mActivity.getDialog().setFeatureDrawableUri(Window.FEATURE_LEFT_ICON, 758 Uri.parse("http://www.google.com")); 759 }); 760 mInstrumentation.waitForIdleSync(); 761 } 762 763 @Test testSetFeatureDrawable()764 public void testSetFeatureDrawable() throws Throwable { 765 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 766 mScenario.onActivity(activity -> { 767 mActivity.getDialog().setFeatureDrawable(Window.FEATURE_LEFT_ICON, 768 new MockDrawable()); 769 }); 770 mInstrumentation.waitForIdleSync(); 771 } 772 773 @Test testSetFeatureDrawableAlpha()774 public void testSetFeatureDrawableAlpha() throws Throwable { 775 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 776 mScenario.onActivity(activity -> { 777 mActivity.getDialog().setFeatureDrawableAlpha(Window.FEATURE_LEFT_ICON, 0); 778 }); 779 mInstrumentation.waitForIdleSync(); 780 } 781 782 @Test testGetLayoutInflater()783 public void testGetLayoutInflater() { 784 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 785 final Dialog d = mActivity.getDialog(); 786 assertEquals(d.getWindow().getLayoutInflater(), d.getLayoutInflater()); 787 } 788 789 @Test testSetCancellable_true()790 public void testSetCancellable_true() { 791 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 792 final Dialog d = mActivity.getDialog(); 793 794 d.setCancelable(true); 795 assertTrue(d.isShowing()); 796 sendKeys(KeyEvent.KEYCODE_BACK); 797 PollingCheck.waitFor(() -> !d.isShowing()); 798 } 799 800 @Test testSetCancellable_false()801 public void testSetCancellable_false() { 802 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 803 final Dialog d = mActivity.getDialog(); 804 805 d.setCancelable(false); 806 assertTrue(d.isShowing()); 807 sendKeys(KeyEvent.KEYCODE_BACK); 808 assertTrue(d.isShowing()); 809 } 810 811 @Test testSetCancellableEsc_true()812 public void testSetCancellableEsc_true() { 813 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 814 final Dialog d = mActivity.getDialog(); 815 816 d.setCancelable(true); 817 assertTrue(d.isShowing()); 818 sendKeys(KeyEvent.KEYCODE_ESCAPE); 819 PollingCheck.waitFor(() -> !d.isShowing()); 820 } 821 822 @Test testSetCancellableEsc_false()823 public void testSetCancellableEsc_false() { 824 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 825 final Dialog d = mActivity.getDialog(); 826 827 d.setCancelable(false); 828 assertTrue(d.isShowing()); 829 sendKeys(KeyEvent.KEYCODE_ESCAPE); 830 assertTrue(d.isShowing()); 831 } 832 833 /* 834 * Test point 835 * 1. Cancel the dialog. 836 * 2. Set a listener to be invoked when the dialog is canceled. 837 */ 838 @Test testCancel_listener()839 public void testCancel_listener() throws Throwable { 840 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 841 final Dialog d = mActivity.getDialog(); 842 843 assertTrue(d.isShowing()); 844 mOnCancelListenerCalled = false; 845 846 d.setOnCancelListener(new OnCancelListener() { 847 public void onCancel(DialogInterface dialog) { 848 mOnCancelListenerCalled = true; 849 } 850 }); 851 dialogCancel(d); 852 853 assertFalse(d.isShowing()); 854 assertTrue(mOnCancelListenerCalled); 855 } 856 857 @Test testCancel_noListener()858 public void testCancel_noListener() throws Throwable { 859 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 860 final Dialog d = mActivity.getDialog(); 861 862 assertTrue(d.isShowing()); 863 mOnCancelListenerCalled = false; 864 d.setOnCancelListener(null); 865 dialogCancel(d); 866 867 assertFalse(d.isShowing()); 868 assertFalse(mOnCancelListenerCalled); 869 } 870 871 @Test testSetCancelMessage()872 public void testSetCancelMessage() throws Exception { 873 mCalledCallback = false; 874 startDialogActivity(DialogStubActivity.TEST_ONSTART_AND_ONSTOP); 875 final TestDialog d = (TestDialog) mActivity.getDialog(); 876 final HandlerThread ht = new HandlerThread("DialogTest"); 877 ht.start(); 878 879 d.setCancelMessage(new MockDismissCancelHandler(d, ht.getLooper()).obtainMessage(CANCEL, 880 new OnCancelListener() { 881 public void onCancel(DialogInterface dialog) { 882 mCalledCallback = true; 883 } 884 })); 885 assertTrue(d.isShowing()); 886 assertFalse(mCalledCallback); 887 sendKeys(KeyEvent.KEYCODE_BACK); 888 PollingCheck.waitFor(() -> mCalledCallback); 889 PollingCheck.waitFor(() -> !d.isShowing()); 890 891 ht.join(100); 892 } 893 894 /* 895 * Test point 896 * 1. Set a listener to be invoked when the dialog is dismissed. 897 * 2. set onDismissListener to null, it will not changed flag after dialog dismissed. 898 */ 899 @Test testSetOnDismissListener_listener()900 public void testSetOnDismissListener_listener() throws Throwable { 901 mCalledCallback = false; 902 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 903 final Dialog d = mActivity.getDialog(); 904 905 d.setOnDismissListener(new OnDismissListener() { 906 public void onDismiss(DialogInterface dialog) { 907 mCalledCallback = true; 908 } 909 }); 910 911 assertTrue(d.isShowing()); 912 assertFalse(mCalledCallback); 913 dialogDismiss(d); 914 assertTrue(mCalledCallback); 915 assertFalse(d.isShowing()); 916 } 917 918 @Test testSetOnDismissListener_noListener()919 public void testSetOnDismissListener_noListener() throws Throwable { 920 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 921 final Dialog d = mActivity.getDialog(); 922 assertTrue(d.isShowing()); 923 mCalledCallback = false; 924 d.setOnDismissListener(null); 925 dialogDismiss(d); 926 assertFalse(mCalledCallback); 927 assertFalse(d.isShowing()); 928 } 929 930 @Test testSetDismissMessage()931 public void testSetDismissMessage() throws Throwable { 932 mCalledCallback = false; 933 startDialogActivity(DialogStubActivity.TEST_DIALOG_WITHOUT_THEME); 934 final Dialog d = mActivity.getDialog(); 935 936 final HandlerThread ht = new HandlerThread("DialogTest"); 937 ht.start(); 938 939 d.setDismissMessage(new MockDismissCancelHandler(d, ht.getLooper()).obtainMessage(DISMISS, 940 new OnDismissListener() { 941 public void onDismiss(DialogInterface dialog) { 942 mCalledCallback = true; 943 } 944 })); 945 assertTrue(d.isShowing()); 946 assertFalse(mCalledCallback); 947 dialogDismiss(d); 948 ht.join(100); 949 assertTrue(mCalledCallback); 950 assertFalse(d.isShowing()); 951 } 952 dialogDismiss(final Dialog d)953 private void dialogDismiss(final Dialog d) throws Throwable { 954 mScenario.onActivity(activity -> { 955 d.dismiss(); 956 }); 957 mInstrumentation.waitForIdleSync(); 958 } 959 dialogCancel(final Dialog d)960 private void dialogCancel(final Dialog d) throws Throwable { 961 mScenario.onActivity(activity -> { 962 d.cancel(); 963 }); 964 mInstrumentation.waitForIdleSync(); 965 } 966 sendKeys(int keyCode)967 private void sendKeys(int keyCode) { 968 mInstrumentation.sendKeyDownUpSync(keyCode); 969 } 970 971 private static class MockDismissCancelHandler extends Handler { 972 private WeakReference<DialogInterface> mDialog; 973 MockDismissCancelHandler(Dialog dialog, Looper looper)974 public MockDismissCancelHandler(Dialog dialog, Looper looper) { 975 super(looper); 976 977 mDialog = new WeakReference<DialogInterface>(dialog); 978 } 979 980 @Override handleMessage(Message msg)981 public void handleMessage(Message msg) { 982 switch (msg.what) { 983 case DISMISS: 984 ((OnDismissListener) msg.obj).onDismiss(mDialog.get()); 985 break; 986 case CANCEL: 987 ((OnCancelListener) msg.obj).onCancel(mDialog.get()); 988 break; 989 } 990 } 991 } 992 993 private static class MockDrawable extends Drawable { 994 @Override draw(Canvas canvas)995 public void draw(Canvas canvas) { 996 } 997 998 @Override getOpacity()999 public int getOpacity() { 1000 return 0; 1001 } 1002 1003 @Override setAlpha(int alpha)1004 public void setAlpha(int alpha) { 1005 } 1006 1007 @Override setColorFilter(ColorFilter cf)1008 public void setColorFilter(ColorFilter cf) { 1009 } 1010 } 1011 1012 private static class MockView extends View { 1013 public boolean isShowContextMenuCalled; 1014 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 1015 MockView(Context context)1016 public MockView(Context context) { 1017 super(context); 1018 } 1019 setOnCreateContextMenuListener(OnCreateContextMenuListener l)1020 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 1021 super.setOnCreateContextMenuListener(l); 1022 mOnCreateContextMenuListener = l; 1023 } 1024 1025 @Override showContextMenu()1026 public boolean showContextMenu() { 1027 isShowContextMenuCalled = true; 1028 return super.showContextMenu(); 1029 } 1030 } 1031 } 1032