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