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