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