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