1 /*
2  * Copyright (C) 2015 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.support.v7.app;
18 
19 import android.app.Dialog;
20 import android.content.Context;
21 import android.content.DialogInterface;
22 import android.database.Cursor;
23 import android.graphics.drawable.Drawable;
24 import android.os.Bundle;
25 import android.os.Message;
26 import android.support.annotation.ArrayRes;
27 import android.support.annotation.AttrRes;
28 import android.support.annotation.DrawableRes;
29 import android.support.annotation.NonNull;
30 import android.support.annotation.Nullable;
31 import android.support.annotation.StringRes;
32 import android.support.annotation.StyleRes;
33 import android.support.v7.appcompat.R;
34 import android.util.TypedValue;
35 import android.view.ContextThemeWrapper;
36 import android.view.KeyEvent;
37 import android.view.View;
38 import android.view.WindowManager;
39 import android.widget.AdapterView;
40 import android.widget.Button;
41 import android.widget.ListAdapter;
42 import android.widget.ListView;
43 
44 /**
45  * A subclass of Dialog that can display one, two or three buttons. If you only want to
46  * display a String in this dialog box, use the setMessage() method.  If you
47  * want to display a more complex view, look up the FrameLayout called "custom"
48  * and add your view to it:
49  *
50  * <pre>
51  * FrameLayout fl = (FrameLayout) findViewById(android.R.id.custom);
52  * fl.addView(myView, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
53  * </pre>
54  *
55  * <p>The AlertDialog class takes care of automatically setting
56  * {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
57  * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} for you based on whether
58  * any views in the dialog return true from {@link View#onCheckIsTextEditor()
59  * View.onCheckIsTextEditor()}.  Generally you want this set for a Dialog
60  * without text editors, so that it will be placed on top of the current
61  * input method UI.  You can modify this behavior by forcing the flag to your
62  * desired mode after calling {@link #onCreate}.
63  *
64  * <div class="special reference">
65  * <h3>Developer Guides</h3>
66  * <p>For more information about creating dialogs, read the
67  * <a href="{@docRoot}guide/topics/ui/dialogs.html">Dialogs</a> developer guide.</p>
68  * </div>
69  */
70 public class AlertDialog extends AppCompatDialog implements DialogInterface {
71 
72     private final AlertController mAlert;
73 
74     /**
75      * No layout hint.
76      */
77     static final int LAYOUT_HINT_NONE = 0;
78 
79     /**
80      * Hint layout to the side.
81      */
82     static final int LAYOUT_HINT_SIDE = 1;
83 
AlertDialog(@onNull Context context)84     protected AlertDialog(@NonNull Context context) {
85         this(context, 0);
86     }
87 
88     /**
89      * Construct an AlertDialog that uses an explicit theme.  The actual style
90      * that an AlertDialog uses is a private implementation, however you can
91      * here supply either the name of an attribute in the theme from which
92      * to get the dialog's style (such as {@link R.attr#alertDialogTheme}.
93      */
AlertDialog(@onNull Context context, @StyleRes int themeResId)94     protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
95         super(context, resolveDialogTheme(context, themeResId));
96         mAlert = new AlertController(getContext(), this, getWindow());
97     }
98 
AlertDialog(@onNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener)99     protected AlertDialog(@NonNull Context context, boolean cancelable,
100             @Nullable OnCancelListener cancelListener) {
101         this(context, 0);
102         setCancelable(cancelable);
103         setOnCancelListener(cancelListener);
104     }
105 
resolveDialogTheme(@onNull Context context, @StyleRes int resid)106     private static int resolveDialogTheme(@NonNull Context context, @StyleRes int resid) {
107         if (resid >= 0x01000000) {   // start of real resource IDs.
108             return resid;
109         } else {
110             TypedValue outValue = new TypedValue();
111             context.getTheme().resolveAttribute(R.attr.alertDialogTheme, outValue, true);
112             return outValue.resourceId;
113         }
114     }
115 
116     /**
117      * Gets one of the buttons used in the dialog. Returns null if the specified
118      * button does not exist or the dialog has not yet been fully created (for
119      * example, via {@link #show()} or {@link #create()}).
120      *
121      * @param whichButton The identifier of the button that should be returned.
122      *                    For example, this can be
123      *                    {@link DialogInterface#BUTTON_POSITIVE}.
124      * @return The button from the dialog, or null if a button does not exist.
125      */
getButton(int whichButton)126     public Button getButton(int whichButton) {
127         return mAlert.getButton(whichButton);
128     }
129 
130     /**
131      * Gets the list view used in the dialog.
132      *
133      * @return The {@link ListView} from the dialog.
134      */
getListView()135     public ListView getListView() {
136         return mAlert.getListView();
137     }
138 
139     @Override
setTitle(CharSequence title)140     public void setTitle(CharSequence title) {
141         super.setTitle(title);
142         mAlert.setTitle(title);
143     }
144 
145     /**
146      * @see Builder#setCustomTitle(View)
147      *
148      * This method has no effect if called after {@link #show()}.
149      */
setCustomTitle(View customTitleView)150     public void setCustomTitle(View customTitleView) {
151         mAlert.setCustomTitle(customTitleView);
152     }
153 
154     /**
155      * Sets the message to display.
156      *
157      * @param message The message to display in the dialog.
158      */
setMessage(CharSequence message)159     public void setMessage(CharSequence message) {
160         mAlert.setMessage(message);
161     }
162 
163     /**
164      * Set the view to display in the dialog. This method has no effect if called
165      * after {@link #show()}.
166      */
setView(View view)167     public void setView(View view) {
168         mAlert.setView(view);
169     }
170 
171     /**
172      * Set the view to display in the dialog, specifying the spacing to appear around that
173      * view.  This method has no effect if called after {@link #show()}.
174      *
175      * @param view              The view to show in the content area of the dialog
176      * @param viewSpacingLeft   Extra space to appear to the left of {@code view}
177      * @param viewSpacingTop    Extra space to appear above {@code view}
178      * @param viewSpacingRight  Extra space to appear to the right of {@code view}
179      * @param viewSpacingBottom Extra space to appear below {@code view}
180      */
setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, int viewSpacingBottom)181     public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight,
182             int viewSpacingBottom) {
183         mAlert.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom);
184     }
185 
186     /**
187      * Internal api to allow hinting for the best button panel layout.
188      *
189      * @hide
190      */
setButtonPanelLayoutHint(int layoutHint)191     void setButtonPanelLayoutHint(int layoutHint) {
192         mAlert.setButtonPanelLayoutHint(layoutHint);
193     }
194 
195     /**
196      * Sets a message to be sent when a button is pressed. This method has no effect if called
197      * after {@link #show()}.
198      *
199      * @param whichButton Which button to set the message for, can be one of
200      *                    {@link DialogInterface#BUTTON_POSITIVE},
201      *                    {@link DialogInterface#BUTTON_NEGATIVE}, or
202      *                    {@link DialogInterface#BUTTON_NEUTRAL}
203      * @param text        The text to display in positive button.
204      * @param msg         The {@link Message} to be sent when clicked.
205      */
setButton(int whichButton, CharSequence text, Message msg)206     public void setButton(int whichButton, CharSequence text, Message msg) {
207         mAlert.setButton(whichButton, text, null, msg);
208     }
209 
210     /**
211      * Sets a listener to be invoked when the positive button of the dialog is pressed. This method
212      * has no effect if called after {@link #show()}.
213      *
214      * @param whichButton Which button to set the listener on, can be one of
215      *                    {@link DialogInterface#BUTTON_POSITIVE},
216      *                    {@link DialogInterface#BUTTON_NEGATIVE}, or
217      *                    {@link DialogInterface#BUTTON_NEUTRAL}
218      * @param text        The text to display in positive button.
219      * @param listener    The {@link DialogInterface.OnClickListener} to use.
220      */
setButton(int whichButton, CharSequence text, OnClickListener listener)221     public void setButton(int whichButton, CharSequence text, OnClickListener listener) {
222         mAlert.setButton(whichButton, text, listener, null);
223     }
224 
225     /**
226      * Set resId to 0 if you don't want an icon.
227      * @param resId the resourceId of the drawable to use as the icon or 0
228      * if you don't want an icon.
229      */
setIcon(int resId)230     public void setIcon(int resId) {
231         mAlert.setIcon(resId);
232     }
233 
234     /**
235      * Set the {@link Drawable} to be used in the title.
236      *
237      * @param icon Drawable to use as the icon or null if you don't want an icon.
238      */
setIcon(Drawable icon)239     public void setIcon(Drawable icon) {
240         mAlert.setIcon(icon);
241     }
242 
243     /**
244      * Sets an icon as supplied by a theme attribute. e.g. android.R.attr.alertDialogIcon
245      *
246      * @param attrId ID of a theme attribute that points to a drawable resource.
247      */
setIconAttribute(int attrId)248     public void setIconAttribute(int attrId) {
249         TypedValue out = new TypedValue();
250         getContext().getTheme().resolveAttribute(attrId, out, true);
251         mAlert.setIcon(out.resourceId);
252     }
253 
254     @Override
onCreate(Bundle savedInstanceState)255     protected void onCreate(Bundle savedInstanceState) {
256         super.onCreate(savedInstanceState);
257         mAlert.installContent();
258     }
259 
260     @Override
onKeyDown(int keyCode, KeyEvent event)261     public boolean onKeyDown(int keyCode, KeyEvent event) {
262         if (mAlert.onKeyDown(keyCode, event)) {
263             return true;
264         }
265         return super.onKeyDown(keyCode, event);
266     }
267 
268     @Override
onKeyUp(int keyCode, KeyEvent event)269     public boolean onKeyUp(int keyCode, KeyEvent event) {
270         if (mAlert.onKeyUp(keyCode, event)) {
271             return true;
272         }
273         return super.onKeyUp(keyCode, event);
274     }
275 
276     public static class Builder {
277         private final AlertController.AlertParams P;
278         private final int mTheme;
279 
280         /**
281          * Creates a builder for an alert dialog that uses the default alert
282          * dialog theme.
283          * <p>
284          * The default alert dialog theme is defined by
285          * {@link android.R.attr#alertDialogTheme} within the parent
286          * {@code context}'s theme.
287          *
288          * @param context the parent context
289          */
Builder(@onNull Context context)290         public Builder(@NonNull Context context) {
291             this(context, resolveDialogTheme(context, 0));
292         }
293 
294         /**
295          * Creates a builder for an alert dialog that uses an explicit theme
296          * resource.
297          * <p>
298          * The specified theme resource ({@code themeResId}) is applied on top
299          * of the parent {@code context}'s theme. It may be specified as a
300          * style resource containing a fully-populated theme, such as
301          * {@link R.style#Theme_AppCompat_Dialog}, to replace all
302          * attributes in the parent {@code context}'s theme including primary
303          * and accent colors.
304          * <p>
305          * To preserve attributes such as primary and accent colors, the
306          * {@code themeResId} may instead be specified as an overlay theme such
307          * as {@link R.style#ThemeOverlay_AppCompat_Dialog}. This will
308          * override only the window attributes necessary to style the alert
309          * window as a dialog.
310          * <p>
311          * Alternatively, the {@code themeResId} may be specified as {@code 0}
312          * to use the parent {@code context}'s resolved value for
313          * {@link android.R.attr#alertDialogTheme}.
314          *
315          * @param context the parent context
316          * @param themeResId the resource ID of the theme against which to inflate
317          *                   this dialog, or {@code 0} to use the parent
318          *                   {@code context}'s default alert dialog theme
319          */
Builder(@onNull Context context, @StyleRes int themeResId)320         public Builder(@NonNull Context context, @StyleRes int themeResId) {
321             P = new AlertController.AlertParams(new ContextThemeWrapper(
322                     context, resolveDialogTheme(context, themeResId)));
323             mTheme = themeResId;
324         }
325 
326         /**
327          * Returns a {@link Context} with the appropriate theme for dialogs created by this Builder.
328          * Applications should use this Context for obtaining LayoutInflaters for inflating views
329          * that will be used in the resulting dialogs, as it will cause views to be inflated with
330          * the correct theme.
331          *
332          * @return A Context for built Dialogs.
333          */
334         @NonNull
getContext()335         public Context getContext() {
336             return P.mContext;
337         }
338 
339         /**
340          * Set the title using the given resource id.
341          *
342          * @return This Builder object to allow for chaining of calls to set methods
343          */
setTitle(@tringRes int titleId)344         public Builder setTitle(@StringRes int titleId) {
345             P.mTitle = P.mContext.getText(titleId);
346             return this;
347         }
348 
349         /**
350          * Set the title displayed in the {@link Dialog}.
351          *
352          * @return This Builder object to allow for chaining of calls to set methods
353          */
setTitle(CharSequence title)354         public Builder setTitle(CharSequence title) {
355             P.mTitle = title;
356             return this;
357         }
358 
359         /**
360          * Set the title using the custom view {@code customTitleView}.
361          * <p>
362          * The methods {@link #setTitle(int)} and {@link #setIcon(int)} should
363          * be sufficient for most titles, but this is provided if the title
364          * needs more customization. Using this will replace the title and icon
365          * set via the other methods.
366          * <p>
367          * <strong>Note:</strong> To ensure consistent styling, the custom view
368          * should be inflated or constructed using the alert dialog's themed
369          * context obtained via {@link #getContext()}.
370          *
371          * @param customTitleView the custom view to use as the title
372          * @return this Builder object to allow for chaining of calls to set
373          *         methods
374          */
setCustomTitle(View customTitleView)375         public Builder setCustomTitle(View customTitleView) {
376             P.mCustomTitleView = customTitleView;
377             return this;
378         }
379 
380         /**
381          * Set the message to display using the given resource id.
382          *
383          * @return This Builder object to allow for chaining of calls to set methods
384          */
setMessage(@tringRes int messageId)385         public Builder setMessage(@StringRes int messageId) {
386             P.mMessage = P.mContext.getText(messageId);
387             return this;
388         }
389 
390         /**
391          * Set the message to display.
392          *
393          * @return This Builder object to allow for chaining of calls to set methods
394          */
setMessage(CharSequence message)395         public Builder setMessage(CharSequence message) {
396             P.mMessage = message;
397             return this;
398         }
399 
400         /**
401          * Set the resource id of the {@link Drawable} to be used in the title.
402          * <p>
403          * Takes precedence over values set using {@link #setIcon(Drawable)}.
404          *
405          * @return This Builder object to allow for chaining of calls to set methods
406          */
setIcon(@rawableRes int iconId)407         public Builder setIcon(@DrawableRes int iconId) {
408             P.mIconId = iconId;
409             return this;
410         }
411 
412         /**
413          * Set the {@link Drawable} to be used in the title.
414          * <p>
415          * <strong>Note:</strong> To ensure consistent styling, the drawable
416          * should be inflated or constructed using the alert dialog's themed
417          * context obtained via {@link #getContext()}.
418          *
419          * @return this Builder object to allow for chaining of calls to set
420          *         methods
421          */
setIcon(Drawable icon)422         public Builder setIcon(Drawable icon) {
423             P.mIcon = icon;
424             return this;
425         }
426 
427         /**
428          * Set an icon as supplied by a theme attribute. e.g.
429          * {@link android.R.attr#alertDialogIcon}.
430          * <p>
431          * Takes precedence over values set using {@link #setIcon(int)} or
432          * {@link #setIcon(Drawable)}.
433          *
434          * @param attrId ID of a theme attribute that points to a drawable resource.
435          */
setIconAttribute(@ttrRes int attrId)436         public Builder setIconAttribute(@AttrRes int attrId) {
437             TypedValue out = new TypedValue();
438             P.mContext.getTheme().resolveAttribute(attrId, out, true);
439             P.mIconId = out.resourceId;
440             return this;
441         }
442 
443         /**
444          * Set a listener to be invoked when the positive button of the dialog is pressed.
445          * @param textId The resource id of the text to display in the positive button
446          * @param listener The {@link DialogInterface.OnClickListener} to use.
447          *
448          * @return This Builder object to allow for chaining of calls to set methods
449          */
setPositiveButton(@tringRes int textId, final OnClickListener listener)450         public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {
451             P.mPositiveButtonText = P.mContext.getText(textId);
452             P.mPositiveButtonListener = listener;
453             return this;
454         }
455 
456         /**
457          * Set a listener to be invoked when the positive button of the dialog is pressed.
458          * @param text The text to display in the positive button
459          * @param listener The {@link DialogInterface.OnClickListener} to use.
460          *
461          * @return This Builder object to allow for chaining of calls to set methods
462          */
setPositiveButton(CharSequence text, final OnClickListener listener)463         public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
464             P.mPositiveButtonText = text;
465             P.mPositiveButtonListener = listener;
466             return this;
467         }
468 
469         /**
470          * Set a listener to be invoked when the negative button of the dialog is pressed.
471          * @param textId The resource id of the text to display in the negative button
472          * @param listener The {@link DialogInterface.OnClickListener} to use.
473          *
474          * @return This Builder object to allow for chaining of calls to set methods
475          */
setNegativeButton(@tringRes int textId, final OnClickListener listener)476         public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener) {
477             P.mNegativeButtonText = P.mContext.getText(textId);
478             P.mNegativeButtonListener = listener;
479             return this;
480         }
481 
482         /**
483          * Set a listener to be invoked when the negative button of the dialog is pressed.
484          * @param text The text to display in the negative button
485          * @param listener The {@link DialogInterface.OnClickListener} to use.
486          *
487          * @return This Builder object to allow for chaining of calls to set methods
488          */
setNegativeButton(CharSequence text, final OnClickListener listener)489         public Builder setNegativeButton(CharSequence text, final OnClickListener listener) {
490             P.mNegativeButtonText = text;
491             P.mNegativeButtonListener = listener;
492             return this;
493         }
494 
495         /**
496          * Set a listener to be invoked when the neutral button of the dialog is pressed.
497          * @param textId The resource id of the text to display in the neutral button
498          * @param listener The {@link DialogInterface.OnClickListener} to use.
499          *
500          * @return This Builder object to allow for chaining of calls to set methods
501          */
setNeutralButton(@tringRes int textId, final OnClickListener listener)502         public Builder setNeutralButton(@StringRes int textId, final OnClickListener listener) {
503             P.mNeutralButtonText = P.mContext.getText(textId);
504             P.mNeutralButtonListener = listener;
505             return this;
506         }
507 
508         /**
509          * Set a listener to be invoked when the neutral button of the dialog is pressed.
510          * @param text The text to display in the neutral button
511          * @param listener The {@link DialogInterface.OnClickListener} to use.
512          *
513          * @return This Builder object to allow for chaining of calls to set methods
514          */
setNeutralButton(CharSequence text, final OnClickListener listener)515         public Builder setNeutralButton(CharSequence text, final OnClickListener listener) {
516             P.mNeutralButtonText = text;
517             P.mNeutralButtonListener = listener;
518             return this;
519         }
520 
521         /**
522          * Sets whether the dialog is cancelable or not.  Default is true.
523          *
524          * @return This Builder object to allow for chaining of calls to set methods
525          */
setCancelable(boolean cancelable)526         public Builder setCancelable(boolean cancelable) {
527             P.mCancelable = cancelable;
528             return this;
529         }
530 
531         /**
532          * Sets the callback that will be called if the dialog is canceled.
533          *
534          * <p>Even in a cancelable dialog, the dialog may be dismissed for reasons other than
535          * being canceled or one of the supplied choices being selected.
536          * If you are interested in listening for all cases where the dialog is dismissed
537          * and not just when it is canceled, see
538          * {@link #setOnDismissListener(android.content.DialogInterface.OnDismissListener)
539          * setOnDismissListener}.</p>
540          *
541          * @return This Builder object to allow for chaining of calls to set methods
542          * @see #setCancelable(boolean)
543          * @see #setOnDismissListener(android.content.DialogInterface.OnDismissListener)
544          *
545          * @return This Builder object to allow for chaining of calls to set methods
546          */
setOnCancelListener(OnCancelListener onCancelListener)547         public Builder setOnCancelListener(OnCancelListener onCancelListener) {
548             P.mOnCancelListener = onCancelListener;
549             return this;
550         }
551 
552         /**
553          * Sets the callback that will be called when the dialog is dismissed for any reason.
554          *
555          * @return This Builder object to allow for chaining of calls to set methods
556          */
setOnDismissListener(OnDismissListener onDismissListener)557         public Builder setOnDismissListener(OnDismissListener onDismissListener) {
558             P.mOnDismissListener = onDismissListener;
559             return this;
560         }
561 
562         /**
563          * Sets the callback that will be called if a key is dispatched to the dialog.
564          *
565          * @return This Builder object to allow for chaining of calls to set methods
566          */
setOnKeyListener(OnKeyListener onKeyListener)567         public Builder setOnKeyListener(OnKeyListener onKeyListener) {
568             P.mOnKeyListener = onKeyListener;
569             return this;
570         }
571 
572         /**
573          * Set a list of items to be displayed in the dialog as the content, you will be notified of the
574          * selected item via the supplied listener. This should be an array type i.e. R.array.foo
575          *
576          * @return This Builder object to allow for chaining of calls to set methods
577          */
setItems(@rrayRes int itemsId, final OnClickListener listener)578         public Builder setItems(@ArrayRes int itemsId, final OnClickListener listener) {
579             P.mItems = P.mContext.getResources().getTextArray(itemsId);
580             P.mOnClickListener = listener;
581             return this;
582         }
583 
584         /**
585          * Set a list of items to be displayed in the dialog as the content, you will be notified of the
586          * selected item via the supplied listener.
587          *
588          * @return This Builder object to allow for chaining of calls to set methods
589          */
setItems(CharSequence[] items, final OnClickListener listener)590         public Builder setItems(CharSequence[] items, final OnClickListener listener) {
591             P.mItems = items;
592             P.mOnClickListener = listener;
593             return this;
594         }
595 
596         /**
597          * Set a list of items, which are supplied by the given {@link ListAdapter}, to be
598          * displayed in the dialog as the content, you will be notified of the
599          * selected item via the supplied listener.
600          *
601          * @param adapter The {@link ListAdapter} to supply the list of items
602          * @param listener The listener that will be called when an item is clicked.
603          *
604          * @return This Builder object to allow for chaining of calls to set methods
605          */
setAdapter(final ListAdapter adapter, final OnClickListener listener)606         public Builder setAdapter(final ListAdapter adapter, final OnClickListener listener) {
607             P.mAdapter = adapter;
608             P.mOnClickListener = listener;
609             return this;
610         }
611 
612         /**
613          * Set a list of items, which are supplied by the given {@link Cursor}, to be
614          * displayed in the dialog as the content, you will be notified of the
615          * selected item via the supplied listener.
616          *
617          * @param cursor The {@link Cursor} to supply the list of items
618          * @param listener The listener that will be called when an item is clicked.
619          * @param labelColumn The column name on the cursor containing the string to display
620          *          in the label.
621          *
622          * @return This Builder object to allow for chaining of calls to set methods
623          */
setCursor(final Cursor cursor, final OnClickListener listener, String labelColumn)624         public Builder setCursor(final Cursor cursor, final OnClickListener listener,
625                 String labelColumn) {
626             P.mCursor = cursor;
627             P.mLabelColumn = labelColumn;
628             P.mOnClickListener = listener;
629             return this;
630         }
631 
632         /**
633          * Set a list of items to be displayed in the dialog as the content,
634          * you will be notified of the selected item via the supplied listener.
635          * This should be an array type, e.g. R.array.foo. The list will have
636          * a check mark displayed to the right of the text for each checked
637          * item. Clicking on an item in the list will not dismiss the dialog.
638          * Clicking on a button will dismiss the dialog.
639          *
640          * @param itemsId the resource id of an array i.e. R.array.foo
641          * @param checkedItems specifies which items are checked. It should be null in which case no
642          *        items are checked. If non null it must be exactly the same length as the array of
643          *        items.
644          * @param listener notified when an item on the list is clicked. The dialog will not be
645          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
646          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
647          *
648          * @return This Builder object to allow for chaining of calls to set methods
649          */
setMultiChoiceItems(@rrayRes int itemsId, boolean[] checkedItems, final OnMultiChoiceClickListener listener)650         public Builder setMultiChoiceItems(@ArrayRes int itemsId, boolean[] checkedItems,
651                 final OnMultiChoiceClickListener listener) {
652             P.mItems = P.mContext.getResources().getTextArray(itemsId);
653             P.mOnCheckboxClickListener = listener;
654             P.mCheckedItems = checkedItems;
655             P.mIsMultiChoice = true;
656             return this;
657         }
658 
659         /**
660          * Set a list of items to be displayed in the dialog as the content,
661          * you will be notified of the selected item via the supplied listener.
662          * The list will have a check mark displayed to the right of the text
663          * for each checked item. Clicking on an item in the list will not
664          * dismiss the dialog. Clicking on a button will dismiss the dialog.
665          *
666          * @param items the text of the items to be displayed in the list.
667          * @param checkedItems specifies which items are checked. It should be null in which case no
668          *        items are checked. If non null it must be exactly the same length as the array of
669          *        items.
670          * @param listener notified when an item on the list is clicked. The dialog will not be
671          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
672          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
673          *
674          * @return This Builder object to allow for chaining of calls to set methods
675          */
setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, final OnMultiChoiceClickListener listener)676         public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems,
677                 final OnMultiChoiceClickListener listener) {
678             P.mItems = items;
679             P.mOnCheckboxClickListener = listener;
680             P.mCheckedItems = checkedItems;
681             P.mIsMultiChoice = true;
682             return this;
683         }
684 
685         /**
686          * Set a list of items to be displayed in the dialog as the content,
687          * you will be notified of the selected item via the supplied listener.
688          * The list will have a check mark displayed to the right of the text
689          * for each checked item. Clicking on an item in the list will not
690          * dismiss the dialog. Clicking on a button will dismiss the dialog.
691          *
692          * @param cursor the cursor used to provide the items.
693          * @param isCheckedColumn specifies the column name on the cursor to use to determine
694          *        whether a checkbox is checked or not. It must return an integer value where 1
695          *        means checked and 0 means unchecked.
696          * @param labelColumn The column name on the cursor containing the string to display in the
697          *        label.
698          * @param listener notified when an item on the list is clicked. The dialog will not be
699          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
700          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
701          *
702          * @return This Builder object to allow for chaining of calls to set methods
703          */
setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, final OnMultiChoiceClickListener listener)704         public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn,
705                 final OnMultiChoiceClickListener listener) {
706             P.mCursor = cursor;
707             P.mOnCheckboxClickListener = listener;
708             P.mIsCheckedColumn = isCheckedColumn;
709             P.mLabelColumn = labelColumn;
710             P.mIsMultiChoice = true;
711             return this;
712         }
713 
714         /**
715          * Set a list of items to be displayed in the dialog as the content, you will be notified of
716          * the selected item via the supplied listener. This should be an array type i.e.
717          * R.array.foo The list will have a check mark displayed to the right of the text for the
718          * checked item. Clicking on an item in the list will not dismiss the dialog. Clicking on a
719          * button will dismiss the dialog.
720          *
721          * @param itemsId the resource id of an array i.e. R.array.foo
722          * @param checkedItem specifies which item is checked. If -1 no items are checked.
723          * @param listener notified when an item on the list is clicked. The dialog will not be
724          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
725          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
726          *
727          * @return This Builder object to allow for chaining of calls to set methods
728          */
setSingleChoiceItems(@rrayRes int itemsId, int checkedItem, final OnClickListener listener)729         public Builder setSingleChoiceItems(@ArrayRes int itemsId, int checkedItem,
730                 final OnClickListener listener) {
731             P.mItems = P.mContext.getResources().getTextArray(itemsId);
732             P.mOnClickListener = listener;
733             P.mCheckedItem = checkedItem;
734             P.mIsSingleChoice = true;
735             return this;
736         }
737 
738         /**
739          * Set a list of items to be displayed in the dialog as the content, you will be notified of
740          * the selected item via the supplied listener. The list will have a check mark displayed to
741          * the right of the text for the checked item. Clicking on an item in the list will not
742          * dismiss the dialog. Clicking on a button will dismiss the dialog.
743          *
744          * @param cursor the cursor to retrieve the items from.
745          * @param checkedItem specifies which item is checked. If -1 no items are checked.
746          * @param labelColumn The column name on the cursor containing the string to display in the
747          *        label.
748          * @param listener notified when an item on the list is clicked. The dialog will not be
749          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
750          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
751          *
752          * @return This Builder object to allow for chaining of calls to set methods
753          */
setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn, final OnClickListener listener)754         public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn,
755                 final OnClickListener listener) {
756             P.mCursor = cursor;
757             P.mOnClickListener = listener;
758             P.mCheckedItem = checkedItem;
759             P.mLabelColumn = labelColumn;
760             P.mIsSingleChoice = true;
761             return this;
762         }
763 
764         /**
765          * Set a list of items to be displayed in the dialog as the content, you will be notified of
766          * the selected item via the supplied listener. The list will have a check mark displayed to
767          * the right of the text for the checked item. Clicking on an item in the list will not
768          * dismiss the dialog. Clicking on a button will dismiss the dialog.
769          *
770          * @param items the items to be displayed.
771          * @param checkedItem specifies which item is checked. If -1 no items are checked.
772          * @param listener notified when an item on the list is clicked. The dialog will not be
773          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
774          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
775          *
776          * @return This Builder object to allow for chaining of calls to set methods
777          */
setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener)778         public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener) {
779             P.mItems = items;
780             P.mOnClickListener = listener;
781             P.mCheckedItem = checkedItem;
782             P.mIsSingleChoice = true;
783             return this;
784         }
785 
786         /**
787          * Set a list of items to be displayed in the dialog as the content, you will be notified of
788          * the selected item via the supplied listener. The list will have a check mark displayed to
789          * the right of the text for the checked item. Clicking on an item in the list will not
790          * dismiss the dialog. Clicking on a button will dismiss the dialog.
791          *
792          * @param adapter The {@link ListAdapter} to supply the list of items
793          * @param checkedItem specifies which item is checked. If -1 no items are checked.
794          * @param listener notified when an item on the list is clicked. The dialog will not be
795          *        dismissed when an item is clicked. It will only be dismissed if clicked on a
796          *        button, if no buttons are supplied it's up to the user to dismiss the dialog.
797          *
798          * @return This Builder object to allow for chaining of calls to set methods
799          */
setSingleChoiceItems(ListAdapter adapter, int checkedItem, final OnClickListener listener)800         public Builder setSingleChoiceItems(ListAdapter adapter, int checkedItem, final OnClickListener listener) {
801             P.mAdapter = adapter;
802             P.mOnClickListener = listener;
803             P.mCheckedItem = checkedItem;
804             P.mIsSingleChoice = true;
805             return this;
806         }
807 
808         /**
809          * Sets a listener to be invoked when an item in the list is selected.
810          *
811          * @param listener the listener to be invoked
812          * @return this Builder object to allow for chaining of calls to set methods
813          * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
814          */
setOnItemSelectedListener(final AdapterView.OnItemSelectedListener listener)815         public Builder setOnItemSelectedListener(final AdapterView.OnItemSelectedListener listener) {
816             P.mOnItemSelectedListener = listener;
817             return this;
818         }
819 
820         /**
821          * Set a custom view resource to be the contents of the Dialog. The
822          * resource will be inflated, adding all top-level views to the screen.
823          *
824          * @param layoutResId Resource ID to be inflated.
825          * @return this Builder object to allow for chaining of calls to set
826          *         methods
827          */
setView(int layoutResId)828         public Builder setView(int layoutResId) {
829             P.mView = null;
830             P.mViewLayoutResId = layoutResId;
831             P.mViewSpacingSpecified = false;
832             return this;
833         }
834 
835         /**
836          * Sets a custom view to be the contents of the alert dialog.
837          * <p>
838          * When using a pre-Holo theme, if the supplied view is an instance of
839          * a {@link ListView} then the light background will be used.
840          * <p>
841          * <strong>Note:</strong> To ensure consistent styling, the custom view
842          * should be inflated or constructed using the alert dialog's themed
843          * context obtained via {@link #getContext()}.
844          *
845          * @param view the view to use as the contents of the alert dialog
846          * @return this Builder object to allow for chaining of calls to set
847          *         methods
848          */
setView(View view)849         public Builder setView(View view) {
850             P.mView = view;
851             P.mViewLayoutResId = 0;
852             P.mViewSpacingSpecified = false;
853             return this;
854         }
855 
856         /**
857          * Set a custom view to be the contents of the Dialog, specifying the
858          * spacing to appear around that view. If the supplied view is an
859          * instance of a {@link ListView} the light background will be used.
860          *
861          * @param view              The view to use as the contents of the Dialog.
862          * @param viewSpacingLeft   Spacing between the left edge of the view and
863          *                          the dialog frame
864          * @param viewSpacingTop    Spacing between the top edge of the view and
865          *                          the dialog frame
866          * @param viewSpacingRight  Spacing between the right edge of the view
867          *                          and the dialog frame
868          * @param viewSpacingBottom Spacing between the bottom edge of the view
869          *                          and the dialog frame
870          * @return This Builder object to allow for chaining of calls to set
871          * methods
872          *
873          *
874          * This is currently hidden because it seems like people should just
875          * be able to put padding around the view.
876          * @hide
877          */
878         @Deprecated
setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, int viewSpacingBottom)879         public Builder setView(View view, int viewSpacingLeft, int viewSpacingTop,
880                 int viewSpacingRight, int viewSpacingBottom) {
881             P.mView = view;
882             P.mViewLayoutResId = 0;
883             P.mViewSpacingSpecified = true;
884             P.mViewSpacingLeft = viewSpacingLeft;
885             P.mViewSpacingTop = viewSpacingTop;
886             P.mViewSpacingRight = viewSpacingRight;
887             P.mViewSpacingBottom = viewSpacingBottom;
888             return this;
889         }
890 
891         /**
892          * Sets the Dialog to use the inverse background, regardless of what the
893          * contents is.
894          *
895          * @param useInverseBackground Whether to use the inverse background
896          * @return This Builder object to allow for chaining of calls to set methods
897          * @deprecated This flag is only used for pre-Material themes. Instead,
898          *             specify the window background using on the alert dialog
899          *             theme.
900          */
901         @Deprecated
setInverseBackgroundForced(boolean useInverseBackground)902         public Builder setInverseBackgroundForced(boolean useInverseBackground) {
903             P.mForceInverseBackground = useInverseBackground;
904             return this;
905         }
906 
907         /**
908          * @hide
909          */
setRecycleOnMeasureEnabled(boolean enabled)910         public Builder setRecycleOnMeasureEnabled(boolean enabled) {
911             P.mRecycleOnMeasure = enabled;
912             return this;
913         }
914 
915 
916         /**
917          * Creates an {@link AlertDialog} with the arguments supplied to this
918          * builder.
919          * <p>
920          * Calling this method does not display the dialog. If no additional
921          * processing is needed, {@link #show()} may be called instead to both
922          * create and display the dialog.
923          */
create()924         public AlertDialog create() {
925             // We can't use Dialog's 3-arg constructor with the createThemeContextWrapper param,
926             // so we always have to re-set the theme
927             final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
928             P.apply(dialog.mAlert);
929             dialog.setCancelable(P.mCancelable);
930             if (P.mCancelable) {
931                 dialog.setCanceledOnTouchOutside(true);
932             }
933             dialog.setOnCancelListener(P.mOnCancelListener);
934             dialog.setOnDismissListener(P.mOnDismissListener);
935             if (P.mOnKeyListener != null) {
936                 dialog.setOnKeyListener(P.mOnKeyListener);
937             }
938             return dialog;
939         }
940 
941         /**
942          * Creates an {@link AlertDialog} with the arguments supplied to this
943          * builder and immediately displays the dialog.
944          * <p>
945          * Calling this method is functionally identical to:
946          * <pre>
947          *     AlertDialog dialog = builder.create();
948          *     dialog.show();
949          * </pre>
950          */
show()951         public AlertDialog show() {
952             final AlertDialog dialog = create();
953             dialog.show();
954             return dialog;
955         }
956     }
957 
958 }
959