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.core.app.ActivityScenario;
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( Context context, int dialogNumber)320     public static ActivityScenario<DialogStubActivity> startDialogActivity(
321             Context context, int dialogNumber) {
322         Intent intent = new Intent(Intent.ACTION_MAIN);
323         intent.putExtra(TEST_DIALOG_NUMBER_EXTRA, dialogNumber);
324         intent.setClass(context, DialogStubActivity.class);
325         return ActivityScenario.launch(intent);
326     }
327 
328     @Override
onCreate(Bundle savedInstanceState)329     protected void onCreate(Bundle savedInstanceState) {
330         super.onCreate(savedInstanceState);
331 
332         setContentView(R.layout.dialog_stub_layout);
333 
334         Intent intent = getIntent();
335         int dialogNum = intent.getIntExtra(TEST_DIALOG_NUMBER_EXTRA, -1);
336         if (dialogNum != -1) {
337             showDialog(dialogNum);
338         }
339     }
340 
setUpTitle(final String title)341     public void setUpTitle(final String title) {
342         runOnUiThread(new Runnable() {
343             public void run() {
344                 getDialog().setTitle(title);
345             }
346         });
347     }
348 
setUpTitle(final int id)349     public void setUpTitle(final int id) {
350         runOnUiThread(new Runnable() {
351             public void run() {
352                 getDialog().setTitle(id);
353             }
354         });
355     }
356 
357     class MockAlertDialog extends AlertDialog {
MockAlertDialog(Context context)358         public MockAlertDialog(Context context) {
359             super(context);
360         }
361 
MockAlertDialog(Context context, int theme)362         public MockAlertDialog(Context context, int theme) {
363             super(context, theme);
364         }
365 
MockAlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener)366         public MockAlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
367             super(context, cancelable, cancelListener);
368         }
369 
370         @Override
onKeyDown(int keyCode, KeyEvent event)371         public boolean onKeyDown(int keyCode, KeyEvent event) {
372             onKeyDownCalled = true;
373             return super.onKeyDown(keyCode, event);
374         }
375 
376         @Override
onKeyUp(int keyCode, KeyEvent event)377         public boolean onKeyUp(int keyCode, KeyEvent event) {
378             onKeyUpCalled = true;
379             return super.onKeyUp(keyCode, event);
380         }
381 
382         @Override
onCreate(Bundle savedInstanceState)383         protected void onCreate(Bundle savedInstanceState) {
384             onCreateCalled = true;
385             super.onCreate(savedInstanceState);
386         }
387 
388     }
389 
390     class MockOnClickListener implements DialogInterface.OnClickListener {
391         private final int mId;
392 
MockOnClickListener(final int buttonId)393         public MockOnClickListener(final int buttonId) {
394             mId = buttonId;
395         }
396 
onClick(DialogInterface dialog, int which)397         public void onClick(DialogInterface dialog, int which) {
398             switch (mId) {
399                 case DialogInterface.BUTTON_POSITIVE:
400                     isPositiveButtonClicked = true;
401                     break;
402                 case DialogInterface.BUTTON_NEGATIVE:
403                     isNegativeButtonClicked = true;
404                     break;
405                 case DialogInterface.BUTTON_NEUTRAL:
406                     isNeutralButtonClicked = true;
407                     break;
408                 default:
409                     break;
410             }
411         }
412     }
413 
414     class MockDatePickerDialog extends DatePickerDialog {
MockDatePickerDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth)415         public MockDatePickerDialog(Context context, OnDateSetListener callBack, int year,
416                 int monthOfYear, int dayOfMonth) {
417             super(context, callBack, year, monthOfYear, dayOfMonth);
418         }
419 
MockDatePickerDialog(Context context, int theme, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth)420         public MockDatePickerDialog(Context context, int theme, OnDateSetListener callBack,
421                 int year, int monthOfYear, int dayOfMonth) {
422             super(context, theme, callBack, year, monthOfYear, dayOfMonth);
423         }
424 
425         @Override
onClick(DialogInterface dialog, int which)426         public void onClick(DialogInterface dialog, int which) {
427             onClickCalled = true;
428             super.onClick(dialog, which);
429         }
430 
431         @Override
onDateChanged(DatePicker view, int year, int month, int day)432         public void onDateChanged(DatePicker view, int year, int month, int day) {
433             onDateChangedCalled = true;
434             super.onDateChanged(view, year, month, day);
435         }
436 
437         @Override
onRestoreInstanceState(Bundle savedInstanceState)438         public void onRestoreInstanceState(Bundle savedInstanceState) {
439             onRestoreInstanceStateCalled = true;
440             super.onRestoreInstanceState(savedInstanceState);
441         }
442 
443         @Override
onSaveInstanceState()444         public Bundle onSaveInstanceState() {
445             onSaveInstanceStateCalled = true;
446             return super.onSaveInstanceState();
447         }
448 
449     }
450 }
451