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 
17 package android.app.stubs;
18 
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.DatePickerDialog;
22 import android.app.DatePickerDialog.OnDateSetListener;
23 import android.app.Dialog;
24 import android.app.TimePickerDialog;
25 import android.app.TimePickerDialog.OnTimeSetListener;
26 import android.content.Context;
27 import android.content.DialogInterface;
28 import android.content.DialogInterface.OnCancelListener;
29 import android.content.Intent;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.os.Message;
33 import android.util.Log;
34 import android.view.KeyEvent;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.widget.DatePicker;
38 import android.widget.TimePicker;
39 
40 import androidx.test.rule.ActivityTestRule;
41 
42 /*
43  * Stub class for  Dialog, AlertDialog, DatePickerDialog, TimePickerDialog etc.
44  */
45 public class DialogStubActivity extends Activity {
46     public static final int TEST_DIALOG_WITHOUT_THEME = 0;
47     public static final int TEST_DIALOG_WITH_THEME = 1;
48     public static final int TEST_ALERTDIALOG = 2;
49     public static final int TEST_CUSTOM_ALERTDIALOG = 3;
50     public static final int TEST_DATEPICKERDIALOG = 4;
51     public static final int TEST_DATEPICKERDIALOG_WITH_THEME = 5;
52     public static final int TEST_TIMEPICKERDIALOG = 6;
53     public static final int TEST_TIMEPICKERDIALOG_WITH_THEME = 7;
54     public static final int TEST_ONSTART_AND_ONSTOP = 8;
55     public static final int TEST_ALERTDIALOG_DEPRECATED = 9;
56     public static final int TEST_ALERTDIALOG_CALLBACK = 10;
57     public static final int TEST_CUSTOM_ALERTDIALOG_VIEW = 11;
58     public static final int TEST_ALERTDIALOG_DEPRECATED_WITH_MESSAGE = 12;
59     public static final int TEST_ALERTDIALOG_THEME = 13;
60     public static final int TEST_ALERTDIALOG_CANCELABLE = 14;
61     public static final int TEST_ALERTDIALOG_NOT_CANCELABLE = 15;
62     public static final int TEST_PROTECTED_CANCELABLE = 16;
63     public static final int TEST_PROTECTED_NOT_CANCELABLE = 17;
64     public static final int TEST_ALERT_DIALOG_ICON_DRAWABLE = 18;
65     public static final int TEST_ALERT_DIALOG_ICON_ATTRIBUTE = 19;
66     public static final int TEST_ALERTDIALOG_WITH_MESSAGE = 20;
67 
68     public static final int SPACING_LEFT = 10;
69     public static final int SPACING_TOP = 20;
70     public static final int SPACING_RIGHT = 30;
71     public static final int SPACING_BOTTOM = 40;
72     public static int buttonIndex;
73 
74     public static final String DEFAULT_ALERTDIALOG_TITLE = "AlertDialog";
75     public static final String DEFAULT_ALERTDIALOG_MESSAGE = "AlertDialog message";
76     private static final String LOG_TAG = "DialogStubActivity";
77 
78     public boolean isPositiveButtonClicked = false;
79     public boolean isNegativeButtonClicked = false;
80     public boolean isNeutralButtonClicked = false;
81     public boolean isCallBackCalled;
82     public boolean onCancelCalled;
83     public boolean onKeyDownCalled;
84     public boolean onKeyUpCalled;
85     public boolean onCreateCalled;
86     public boolean onCancelListenerCalled;
87     public boolean onClickCalled;
88     public static boolean onDateChangedCalled;
89     public static boolean onRestoreInstanceStateCalled;
90     public boolean onSaveInstanceStateCalled;
91     public int updatedYear;
92     public int updatedMonth;
93     public int updatedDay;
94 
95     public final int INITIAL_YEAR = 2008;
96     public final int INITIAL_MONTH = 7;
97     public final int INITIAL_DAY_OF_MONTH = 27;
98     private final int INITIAL_HOUR = 10;
99     private final int INITIAL_MINUTE = 35;
100     private Dialog mDialog;
101     private AlertDialog mAlertDialog;
102     private OnDateSetListener mOnDateSetListener = new OnDateSetListener() {
103         public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
104             updatedYear = year;
105             updatedMonth = monthOfYear;
106             updatedDay = dayOfMonth;
107         }
108     };
109 
110     @SuppressWarnings("deprecation")
111     @Override
onCreateDialog(int id)112     protected Dialog onCreateDialog(int id) {
113         switch (id) {
114             case TEST_DIALOG_WITHOUT_THEME:
115                 mDialog = new Dialog(this);
116                 mDialog.setTitle("Hello, Dialog");
117                 break;
118 
119             case TEST_DIALOG_WITH_THEME:
120                 mDialog = new Dialog(this, 1);
121                 break;
122 
123             case TEST_ALERTDIALOG:
124                 mDialog = getAlertDialogInstance(false);
125                 break;
126 
127             case TEST_CUSTOM_ALERTDIALOG:
128                 mDialog = getCustomAlertDialogInstance(false);
129                 break;
130 
131             case TEST_CUSTOM_ALERTDIALOG_VIEW:
132                 mDialog = getCustomAlertDialogInstance(true);
133                 break;
134 
135             case TEST_DATEPICKERDIALOG:
136                 mDialog = new MockDatePickerDialog(this, mOnDateSetListener, INITIAL_YEAR,
137                         INITIAL_MONTH, INITIAL_DAY_OF_MONTH);
138                 break;
139 
140             case TEST_DATEPICKERDIALOG_WITH_THEME:
141                 mDialog = new MockDatePickerDialog(this,
142                         com.android.internal.R.style.Theme_Translucent, mOnDateSetListener,
143                         INITIAL_YEAR, INITIAL_MONTH, INITIAL_DAY_OF_MONTH);
144                 break;
145 
146             case TEST_TIMEPICKERDIALOG:
147                 mDialog = new TimePickerDialog(this, new OnTimeSetListener() {
148                     public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
149                         isCallBackCalled = true;
150                     }
151                 }, INITIAL_HOUR, INITIAL_MINUTE, true);
152                 break;
153 
154             case TEST_TIMEPICKERDIALOG_WITH_THEME:
155                 mDialog = new TimePickerDialog(this,
156                         com.android.internal.R.style.Theme_Translucent, null, INITIAL_HOUR,
157                         INITIAL_MINUTE, true);
158                 break;
159 
160             case TEST_ONSTART_AND_ONSTOP:
161                 mDialog = new TestDialog(this);
162                 Log.i(LOG_TAG, "mTestDialog:" + mDialog);
163                 return mDialog;
164 
165             case TEST_ALERTDIALOG_DEPRECATED:
166                 mDialog = getAlertDialogInstance(true);
167                 break;
168 
169             case TEST_ALERTDIALOG_DEPRECATED_WITH_MESSAGE:
170             case TEST_ALERTDIALOG_WITH_MESSAGE:
171                 final Handler handler = new Handler() {
172                     @Override
173                     public void handleMessage(Message msg) {
174                         buttonIndex = msg.what;
175                         super.handleMessage(msg);
176                     }
177                 };
178                 final Message positiveMessage = Message.obtain();
179                 positiveMessage.setTarget(handler);
180                 positiveMessage.what = DialogInterface.BUTTON_POSITIVE;
181 
182                 final Message negativeMessage = Message.obtain();
183                 negativeMessage.setTarget(handler);
184                 negativeMessage.what = DialogInterface.BUTTON_NEGATIVE;
185 
186                 final Message neutralMessage = Message.obtain();
187                 neutralMessage.setTarget(handler);
188                 neutralMessage.what = DialogInterface.BUTTON_NEUTRAL;
189                 mAlertDialog = getAlertDialogInstance(false);
190                 if (id == TEST_ALERTDIALOG_DEPRECATED_WITH_MESSAGE) {
191                     mAlertDialog.setButton(getString(R.string.alert_dialog_positive),
192                             positiveMessage);
193                     mAlertDialog.setButton2(getString(R.string.alert_dialog_negative),
194                             negativeMessage);
195                     mAlertDialog.setButton3(getString(R.string.alert_dialog_neutral),
196                             neutralMessage);
197                 } else {
198                     mAlertDialog.setButton(AlertDialog.BUTTON_POSITIVE,
199                             getString(R.string.alert_dialog_positive), positiveMessage);
200                     mAlertDialog.setButton(AlertDialog.BUTTON_NEUTRAL,
201                             getString(R.string.alert_dialog_neutral), neutralMessage);
202                     mAlertDialog.setButton(AlertDialog.BUTTON_NEGATIVE,
203                             getString(R.string.alert_dialog_negative), negativeMessage);
204                 }
205                 mDialog = mAlertDialog;
206                 break;
207 
208             case TEST_ALERTDIALOG_CALLBACK:
209                 mDialog = new MockAlertDialog(this);
210                 break;
211             case TEST_ALERTDIALOG_THEME:
212                 mDialog = new MockAlertDialog(this, R.style.Theme_AlertDialog);
213                 break;
214             case TEST_ALERTDIALOG_CANCELABLE:
215                 mDialog = getAlertDialogCancelableInstance(true);
216                 break;
217             case TEST_ALERTDIALOG_NOT_CANCELABLE:
218                 mDialog = getAlertDialogCancelableInstance(false);
219                 break;
220             case TEST_PROTECTED_CANCELABLE:
221                 mDialog = new TestDialog(this, true, new OnCancelListener() {
222                     public void onCancel(DialogInterface dialog) {
223                         onCancelListenerCalled = true;
224                     }
225                 });
226                 break;
227             case TEST_PROTECTED_NOT_CANCELABLE:
228                 mDialog = new TestDialog(this, false, new OnCancelListener() {
229                     public void onCancel(DialogInterface dialog) {
230                         onCancelListenerCalled = true;
231                     }
232                 });
233                 break;
234             case TEST_ALERT_DIALOG_ICON_DRAWABLE:
235                 mAlertDialog = getAlertDialogInstance(false);
236                 mAlertDialog.setIcon(mAlertDialog.getContext().getDrawable(R.drawable.robot));
237                 mDialog = mAlertDialog;
238                 break;
239             case TEST_ALERT_DIALOG_ICON_ATTRIBUTE:
240                 mAlertDialog = getAlertDialogInstance(false);
241                 mAlertDialog.setIconAttribute(android.R.attr.alertDialogIcon);
242                 mDialog = mAlertDialog;
243                 break;
244 
245             default:
246                 break;
247         }
248 
249         Log.i(LOG_TAG, "mDialog:" + mDialog);
250         return mDialog;
251     }
252 
getAlertDialogCancelableInstance(boolean cancelable)253     private AlertDialog getAlertDialogCancelableInstance(boolean cancelable) {
254         OnCancelListener cancelListener = new OnCancelListener() {
255             public void onCancel(DialogInterface dialog) {
256                 onCancelCalled = true;
257             }
258         };
259         return new MockAlertDialog(this, cancelable, cancelListener);
260     }
261 
262     @SuppressWarnings("deprecation")
getAlertDialogInstance(boolean deprecated)263     private AlertDialog getAlertDialogInstance(boolean deprecated) {
264         mAlertDialog = new AlertDialog.Builder(DialogStubActivity.this).create();
265         mAlertDialog.setIcon(R.drawable.pass);
266         mAlertDialog.setTitle(DEFAULT_ALERTDIALOG_TITLE);
267         mAlertDialog.setMessage(DEFAULT_ALERTDIALOG_MESSAGE);
268         mAlertDialog.setInverseBackgroundForced(true);
269         final DialogInterface.OnClickListener positiveListener = new MockOnClickListener(
270                 DialogInterface.BUTTON_POSITIVE);
271         final DialogInterface.OnClickListener netativeListener = new MockOnClickListener(
272                 DialogInterface.BUTTON_NEGATIVE);
273         final DialogInterface.OnClickListener neutralListener = new MockOnClickListener(
274                 DialogInterface.BUTTON_NEUTRAL);
275 
276         if (deprecated) {
277             mAlertDialog.setButton(getString(R.string.alert_dialog_positive), positiveListener);
278             mAlertDialog.setButton2(getString(R.string.alert_dialog_negative), netativeListener);
279             mAlertDialog.setButton3(getString(R.string.alert_dialog_neutral), neutralListener);
280         } else {
281             mAlertDialog.setButton(DialogInterface.BUTTON_POSITIVE,
282                     getString(R.string.alert_dialog_positive), positiveListener);
283             mAlertDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
284                     getString(R.string.alert_dialog_negative), netativeListener);
285             mAlertDialog.setButton(DialogInterface.BUTTON_NEUTRAL,
286                     getString(R.string.alert_dialog_neutral), neutralListener);
287         }
288         return mAlertDialog;
289 
290     }
291 
getCustomAlertDialogInstance(boolean withSpacing)292     private AlertDialog getCustomAlertDialogInstance(boolean withSpacing) {
293         final LayoutInflater inflate = getLayoutInflater();
294         final View customTitleViewCustom = inflate.inflate(R.layout.alertdialog_custom_title, null);
295         final View textEntryView = inflate.inflate(R.layout.alert_dialog_text_entry_2, null);
296         mAlertDialog = new AlertDialog.Builder(DialogStubActivity.this).create();
297         mAlertDialog.setCustomTitle(customTitleViewCustom);
298         mAlertDialog.setMessage(DEFAULT_ALERTDIALOG_MESSAGE);
299         if (withSpacing) {
300             mAlertDialog.setView(textEntryView, SPACING_LEFT, SPACING_TOP, SPACING_RIGHT,
301                     SPACING_BOTTOM);
302         } else {
303             mAlertDialog.setView(textEntryView);
304         }
305 
306         return mAlertDialog;
307 
308     }
309 
getDialog()310     public Dialog getDialog() {
311         return mDialog;
312     }
313 
getDialogTitle()314     public String getDialogTitle() {
315         return (String) mDialog.getWindow().getAttributes().getTitle();
316     }
317 
318     private static final String TEST_DIALOG_NUMBER_EXTRA = "testDialogNumber";
319 
startDialogActivity( ActivityTestRule<T> rule, int dialogNumber)320     public static <T extends Activity> T startDialogActivity(
321             ActivityTestRule<T> rule, int dialogNumber) {
322         Intent intent = new Intent(Intent.ACTION_MAIN);
323         intent.putExtra(TEST_DIALOG_NUMBER_EXTRA, dialogNumber);
324         return rule.launchActivity(intent);
325     }
326 
327     @Override
onCreate(Bundle savedInstanceState)328     protected void onCreate(Bundle savedInstanceState) {
329         super.onCreate(savedInstanceState);
330 
331         setContentView(R.layout.dialog_stub_layout);
332 
333         Intent intent = getIntent();
334         int dialogNum = intent.getIntExtra(TEST_DIALOG_NUMBER_EXTRA, -1);
335         if (dialogNum != -1) {
336             showDialog(dialogNum);
337         }
338     }
339 
setUpTitle(final String title)340     public void setUpTitle(final String title) {
341         runOnUiThread(new Runnable() {
342             public void run() {
343                 getDialog().setTitle(title);
344             }
345         });
346     }
347 
setUpTitle(final int id)348     public void setUpTitle(final int id) {
349         runOnUiThread(new Runnable() {
350             public void run() {
351                 getDialog().setTitle(id);
352             }
353         });
354     }
355 
356     class MockAlertDialog extends AlertDialog {
MockAlertDialog(Context context)357         public MockAlertDialog(Context context) {
358             super(context);
359         }
360 
MockAlertDialog(Context context, int theme)361         public MockAlertDialog(Context context, int theme) {
362             super(context, theme);
363         }
364 
MockAlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener)365         public MockAlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
366             super(context, cancelable, cancelListener);
367         }
368 
369         @Override
onKeyDown(int keyCode, KeyEvent event)370         public boolean onKeyDown(int keyCode, KeyEvent event) {
371             onKeyDownCalled = true;
372             return super.onKeyDown(keyCode, event);
373         }
374 
375         @Override
onKeyUp(int keyCode, KeyEvent event)376         public boolean onKeyUp(int keyCode, KeyEvent event) {
377             onKeyUpCalled = true;
378             return super.onKeyUp(keyCode, event);
379         }
380 
381         @Override
onCreate(Bundle savedInstanceState)382         protected void onCreate(Bundle savedInstanceState) {
383             onCreateCalled = true;
384             super.onCreate(savedInstanceState);
385         }
386 
387     }
388 
389     class MockOnClickListener implements DialogInterface.OnClickListener {
390         private final int mId;
391 
MockOnClickListener(final int buttonId)392         public MockOnClickListener(final int buttonId) {
393             mId = buttonId;
394         }
395 
onClick(DialogInterface dialog, int which)396         public void onClick(DialogInterface dialog, int which) {
397             switch (mId) {
398                 case DialogInterface.BUTTON_POSITIVE:
399                     isPositiveButtonClicked = true;
400                     break;
401                 case DialogInterface.BUTTON_NEGATIVE:
402                     isNegativeButtonClicked = true;
403                     break;
404                 case DialogInterface.BUTTON_NEUTRAL:
405                     isNeutralButtonClicked = true;
406                     break;
407                 default:
408                     break;
409             }
410         }
411     }
412 
413     class MockDatePickerDialog extends DatePickerDialog {
MockDatePickerDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth)414         public MockDatePickerDialog(Context context, OnDateSetListener callBack, int year,
415                 int monthOfYear, int dayOfMonth) {
416             super(context, callBack, year, monthOfYear, dayOfMonth);
417         }
418 
MockDatePickerDialog(Context context, int theme, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth)419         public MockDatePickerDialog(Context context, int theme, OnDateSetListener callBack,
420                 int year, int monthOfYear, int dayOfMonth) {
421             super(context, theme, callBack, year, monthOfYear, dayOfMonth);
422         }
423 
424         @Override
onClick(DialogInterface dialog, int which)425         public void onClick(DialogInterface dialog, int which) {
426             onClickCalled = true;
427             super.onClick(dialog, which);
428         }
429 
430         @Override
onDateChanged(DatePicker view, int year, int month, int day)431         public void onDateChanged(DatePicker view, int year, int month, int day) {
432             onDateChangedCalled = true;
433             super.onDateChanged(view, year, month, day);
434         }
435 
436         @Override
onRestoreInstanceState(Bundle savedInstanceState)437         public void onRestoreInstanceState(Bundle savedInstanceState) {
438             onRestoreInstanceStateCalled = true;
439             super.onRestoreInstanceState(savedInstanceState);
440         }
441 
442         @Override
onSaveInstanceState()443         public Bundle onSaveInstanceState() {
444             onSaveInstanceStateCalled = true;
445             return super.onSaveInstanceState();
446         }
447 
448     }
449 }
450