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