blob: 0fd05c1cb8cdbbce8cd3a1cb4429557cb2dfa717 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.app;
18
Romain Guy980a9382010-01-08 15:06:28 -080019import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
Gilles Debunne076c7fb2010-10-04 12:00:02 -070020
21import com.android.internal.R;
22
Alan Viverette62c79e92015-02-26 09:47:10 -080023import android.annotation.Nullable;
Mathew Inwoodaf972c82018-08-20 14:13:20 +010024import android.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.app.AlertDialog;
26import android.content.Context;
27import android.content.DialogInterface;
Michael Kwan937035e2016-06-09 11:59:21 -070028import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.content.res.TypedArray;
30import android.database.Cursor;
31import android.graphics.drawable.Drawable;
32import android.os.Handler;
33import android.os.Message;
Makoto Onukie8bbf952018-04-20 14:04:50 -070034import android.text.Layout;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.text.TextUtils;
Makoto Onukie8bbf952018-04-20 14:04:50 -070036import android.text.method.LinkMovementMethod;
37import android.text.method.MovementMethod;
Romain Guy6fe2b222010-02-22 14:11:40 -080038import android.util.AttributeSet;
Adam Powell3320dcd2010-11-05 20:06:02 -070039import android.util.TypedValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.view.Gravity;
41import android.view.KeyEvent;
42import android.view.LayoutInflater;
43import android.view.View;
44import android.view.ViewGroup;
Gilles Debunne076c7fb2010-10-04 12:00:02 -070045import android.view.ViewGroup.LayoutParams;
Alan Viverette35c3cb62014-10-30 13:51:21 -070046import android.view.ViewParent;
Alan Viverette62c79e92015-02-26 09:47:10 -080047import android.view.ViewStub;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.view.Window;
Vinod Krishnan119ba2c2014-05-05 14:58:15 -070049import android.view.WindowInsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.widget.AdapterView;
Gilles Debunne076c7fb2010-10-04 12:00:02 -070052import android.widget.AdapterView.OnItemClickListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.widget.ArrayAdapter;
54import android.widget.Button;
55import android.widget.CheckedTextView;
56import android.widget.CursorAdapter;
57import android.widget.FrameLayout;
58import android.widget.ImageView;
59import android.widget.LinearLayout;
60import android.widget.ListAdapter;
61import android.widget.ListView;
62import android.widget.ScrollView;
63import android.widget.SimpleCursorAdapter;
64import android.widget.TextView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
66import java.lang.ref.WeakReference;
67
68public class AlertController {
Michael Kwan246caac2016-05-17 00:46:58 -070069 public static final int MICRO = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070
71 private final Context mContext;
72 private final DialogInterface mDialogInterface;
Michael Kwancc6e6f02016-05-16 12:54:57 -070073 protected final Window mWindow;
Alan Viveretteb17c6c12014-09-03 16:27:51 -070074
Mathew Inwoodaf972c82018-08-20 14:13:20 +010075 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 private CharSequence mTitle;
Michael Kwancc6e6f02016-05-16 12:54:57 -070077 protected CharSequence mMessage;
78 protected ListView mListView;
Mathew Inwoodaf972c82018-08-20 14:13:20 +010079 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 private View mView;
81
Alan Viveretteec186702013-12-05 11:10:31 -080082 private int mViewLayoutResId;
83
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 private int mViewSpacingLeft;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 private int mViewSpacingTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 private int mViewSpacingRight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 private int mViewSpacingBottom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 private boolean mViewSpacingSpecified = false;
Alan Viveretteb17c6c12014-09-03 16:27:51 -070089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 private Button mButtonPositive;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 private CharSequence mButtonPositiveText;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 private Message mButtonPositiveMessage;
93
94 private Button mButtonNegative;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 private CharSequence mButtonNegativeText;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private Message mButtonNegativeMessage;
97
98 private Button mButtonNeutral;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 private CharSequence mButtonNeutralText;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private Message mButtonNeutralMessage;
101
Michael Kwancc6e6f02016-05-16 12:54:57 -0700102 protected ScrollView mScrollView;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700103
Alan Viverettea1a68042014-04-28 13:30:08 -0700104 private int mIconId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 private Drawable mIcon;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private ImageView mIconView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 private TextView mTitleView;
Michael Kwancc6e6f02016-05-16 12:54:57 -0700109 protected TextView mMessageView;
Makoto Onukie8bbf952018-04-20 14:04:50 -0700110 private MovementMethod mMessageMovementMethod;
111 @Layout.HyphenationFrequency
112 private Integer mMessageHyphenationFrequency;
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100113 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 private View mCustomTitleView;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700115
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100116 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 private boolean mForceInverseBackground;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 private ListAdapter mAdapter;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 private int mCheckedItem = -1;
122
Adam Powellfcca00a2010-11-30 21:26:29 -0800123 private int mAlertDialogLayout;
Craig Stout4c0cb8a2014-04-04 13:03:10 -0700124 private int mButtonPanelSideLayout;
Adam Powellfcca00a2010-11-30 21:26:29 -0800125 private int mListLayout;
126 private int mMultiChoiceItemLayout;
127 private int mSingleChoiceItemLayout;
128 private int mListItemLayout;
129
Alan Viverette2e750a12016-01-29 12:53:26 -0500130 private boolean mShowTitle;
131
Craig Stout4c0cb8a2014-04-04 13:03:10 -0700132 private int mButtonPanelLayoutHint = AlertDialog.LAYOUT_HINT_NONE;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 private Handler mHandler;
135
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800136 private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
137 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 public void onClick(View v) {
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800139 final Message m;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 if (v == mButtonPositive && mButtonPositiveMessage != null) {
141 m = Message.obtain(mButtonPositiveMessage);
142 } else if (v == mButtonNegative && mButtonNegativeMessage != null) {
143 m = Message.obtain(mButtonNegativeMessage);
144 } else if (v == mButtonNeutral && mButtonNeutralMessage != null) {
145 m = Message.obtain(mButtonNeutralMessage);
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800146 } else {
147 m = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 }
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 if (m != null) {
151 m.sendToTarget();
152 }
153
154 // Post a message so we dismiss after the above handlers are executed
155 mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
156 .sendToTarget();
157 }
158 };
159
160 private static final class ButtonHandler extends Handler {
161 // Button clicks have Message.what as the BUTTON{1,2,3} constant
162 private static final int MSG_DISMISS_DIALOG = 1;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 private WeakReference<DialogInterface> mDialog;
165
166 public ButtonHandler(DialogInterface dialog) {
Alan Viverette2e750a12016-01-29 12:53:26 -0500167 mDialog = new WeakReference<>(dialog);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 }
169
170 @Override
171 public void handleMessage(Message msg) {
172 switch (msg.what) {
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 case DialogInterface.BUTTON_POSITIVE:
175 case DialogInterface.BUTTON_NEGATIVE:
176 case DialogInterface.BUTTON_NEUTRAL:
177 ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
178 break;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 case MSG_DISMISS_DIALOG:
181 ((DialogInterface) msg.obj).dismiss();
182 }
183 }
184 }
185
Adam Powell3320dcd2010-11-05 20:06:02 -0700186 private static boolean shouldCenterSingleButton(Context context) {
Alan Viverette89900832015-04-08 12:45:54 -0700187 final TypedValue outValue = new TypedValue();
188 context.getTheme().resolveAttribute(R.attr.alertDialogCenterButtons, outValue, true);
Adam Powell3320dcd2010-11-05 20:06:02 -0700189 return outValue.data != 0;
190 }
191
Michael Kwancc6e6f02016-05-16 12:54:57 -0700192 public static final AlertController create(Context context, DialogInterface di, Window window) {
193 final TypedArray a = context.obtainStyledAttributes(
Lucas Dupin250c61c2018-10-31 09:48:14 -0700194 null, R.styleable.AlertDialog, R.attr.alertDialogStyle,
195 R.style.Theme_DeviceDefault_Settings);
Michael Kwancc6e6f02016-05-16 12:54:57 -0700196 int controllerType = a.getInt(R.styleable.AlertDialog_controllerType, 0);
197 a.recycle();
198
199 switch (controllerType) {
Michael Kwan246caac2016-05-17 00:46:58 -0700200 case MICRO:
201 return new MicroAlertController(context, di, window);
Michael Kwancc6e6f02016-05-16 12:54:57 -0700202 default:
203 return new AlertController(context, di, window);
204 }
205 }
206
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100207 @UnsupportedAppUsage
Michael Kwancc6e6f02016-05-16 12:54:57 -0700208 protected AlertController(Context context, DialogInterface di, Window window) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 mContext = context;
210 mDialogInterface = di;
211 mWindow = window;
212 mHandler = new ButtonHandler(di);
Adam Powellfcca00a2010-11-30 21:26:29 -0800213
Alan Viverette89900832015-04-08 12:45:54 -0700214 final TypedArray a = context.obtainStyledAttributes(null,
215 R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
Adam Powellfcca00a2010-11-30 21:26:29 -0800216
Alan Viverette89900832015-04-08 12:45:54 -0700217 mAlertDialogLayout = a.getResourceId(
218 R.styleable.AlertDialog_layout, R.layout.alert_dialog);
Craig Stout4c0cb8a2014-04-04 13:03:10 -0700219 mButtonPanelSideLayout = a.getResourceId(
Alan Viverette89900832015-04-08 12:45:54 -0700220 R.styleable.AlertDialog_buttonPanelSideLayout, 0);
Adam Powellfcca00a2010-11-30 21:26:29 -0800221 mListLayout = a.getResourceId(
Alan Viverette89900832015-04-08 12:45:54 -0700222 R.styleable.AlertDialog_listLayout, R.layout.select_dialog);
223
Adam Powellfcca00a2010-11-30 21:26:29 -0800224 mMultiChoiceItemLayout = a.getResourceId(
Alan Viverette89900832015-04-08 12:45:54 -0700225 R.styleable.AlertDialog_multiChoiceItemLayout,
226 R.layout.select_dialog_multichoice);
Adam Powellfcca00a2010-11-30 21:26:29 -0800227 mSingleChoiceItemLayout = a.getResourceId(
Alan Viverette89900832015-04-08 12:45:54 -0700228 R.styleable.AlertDialog_singleChoiceItemLayout,
229 R.layout.select_dialog_singlechoice);
Adam Powellfcca00a2010-11-30 21:26:29 -0800230 mListItemLayout = a.getResourceId(
Alan Viverette89900832015-04-08 12:45:54 -0700231 R.styleable.AlertDialog_listItemLayout,
232 R.layout.select_dialog_item);
Alan Viverette2e750a12016-01-29 12:53:26 -0500233 mShowTitle = a.getBoolean(R.styleable.AlertDialog_showTitle, true);
Adam Powellfcca00a2010-11-30 21:26:29 -0800234
235 a.recycle();
Chris Banesccf8e662016-03-23 16:20:00 +0000236
237 /* We use a custom title so never request a window title */
238 window.requestFeature(Window.FEATURE_NO_TITLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 static boolean canTextInput(View v) {
242 if (v.onCheckIsTextEditor()) {
243 return true;
244 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 if (!(v instanceof ViewGroup)) {
247 return false;
248 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 ViewGroup vg = (ViewGroup)v;
251 int i = vg.getChildCount();
252 while (i > 0) {
253 i--;
254 v = vg.getChildAt(i);
255 if (canTextInput(v)) {
256 return true;
257 }
258 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 return false;
261 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700262
Eugene Suslacf00ade2017-04-10 11:51:58 -0700263 public void installContent(AlertParams params) {
264 params.apply(this);
265 installContent();
266 }
267
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100268 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 public void installContent() {
Craig Stout4c0cb8a2014-04-04 13:03:10 -0700270 int contentView = selectContentView();
271 mWindow.setContentView(contentView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 setupView();
273 }
Craig Stout4c0cb8a2014-04-04 13:03:10 -0700274
275 private int selectContentView() {
276 if (mButtonPanelSideLayout == 0) {
277 return mAlertDialogLayout;
278 }
279 if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
280 return mButtonPanelSideLayout;
281 }
282 // TODO: use layout hint side for long messages/lists
283 return mAlertDialogLayout;
284 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700285
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100286 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 public void setTitle(CharSequence title) {
288 mTitle = title;
289 if (mTitleView != null) {
290 mTitleView.setText(title);
291 }
292 }
293
294 /**
295 * @see AlertDialog.Builder#setCustomTitle(View)
296 */
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100297 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 public void setCustomTitle(View customTitleView) {
299 mCustomTitleView = customTitleView;
300 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700301
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100302 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 public void setMessage(CharSequence message) {
304 mMessage = message;
305 if (mMessageView != null) {
306 mMessageView.setText(message);
307 }
308 }
309
Makoto Onukie8bbf952018-04-20 14:04:50 -0700310 public void setMessageMovementMethod(MovementMethod movementMethod) {
311 mMessageMovementMethod = movementMethod;
312 if (mMessageView != null) {
313 mMessageView.setMovementMethod(movementMethod);
314 }
315 }
316
317 public void setMessageHyphenationFrequency(
318 @Layout.HyphenationFrequency int hyphenationFrequency) {
319 mMessageHyphenationFrequency = hyphenationFrequency;
320 if (mMessageView != null) {
321 mMessageView.setHyphenationFrequency(hyphenationFrequency);
322 }
323 }
324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 /**
Alan Viveretteec186702013-12-05 11:10:31 -0800326 * Set the view resource to display in the dialog.
327 */
328 public void setView(int layoutResId) {
329 mView = null;
330 mViewLayoutResId = layoutResId;
331 mViewSpacingSpecified = false;
332 }
333
334 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 * Set the view to display in the dialog.
336 */
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100337 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 public void setView(View view) {
339 mView = view;
Alan Viveretteec186702013-12-05 11:10:31 -0800340 mViewLayoutResId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 mViewSpacingSpecified = false;
342 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 /**
345 * Set the view to display in the dialog along with the spacing around that view
346 */
347 public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight,
348 int viewSpacingBottom) {
349 mView = view;
Alan Viveretteec186702013-12-05 11:10:31 -0800350 mViewLayoutResId = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 mViewSpacingSpecified = true;
352 mViewSpacingLeft = viewSpacingLeft;
353 mViewSpacingTop = viewSpacingTop;
354 mViewSpacingRight = viewSpacingRight;
355 mViewSpacingBottom = viewSpacingBottom;
356 }
357
358 /**
Craig Stout4c0cb8a2014-04-04 13:03:10 -0700359 * Sets a hint for the best button panel layout.
360 */
361 public void setButtonPanelLayoutHint(int layoutHint) {
362 mButtonPanelLayoutHint = layoutHint;
363 }
364
365 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 * Sets a click listener or a message to be sent when the button is clicked.
367 * You only need to pass one of {@code listener} or {@code msg}.
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700368 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 * @param whichButton Which button, can be one of
370 * {@link DialogInterface#BUTTON_POSITIVE},
371 * {@link DialogInterface#BUTTON_NEGATIVE}, or
372 * {@link DialogInterface#BUTTON_NEUTRAL}
373 * @param text The text to display in positive button.
374 * @param listener The {@link DialogInterface.OnClickListener} to use.
375 * @param msg The {@link Message} to be sent when clicked.
376 */
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100377 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 public void setButton(int whichButton, CharSequence text,
379 DialogInterface.OnClickListener listener, Message msg) {
380
381 if (msg == null && listener != null) {
382 msg = mHandler.obtainMessage(whichButton, listener);
383 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 switch (whichButton) {
386
387 case DialogInterface.BUTTON_POSITIVE:
388 mButtonPositiveText = text;
389 mButtonPositiveMessage = msg;
390 break;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 case DialogInterface.BUTTON_NEGATIVE:
393 mButtonNegativeText = text;
394 mButtonNegativeMessage = msg;
395 break;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 case DialogInterface.BUTTON_NEUTRAL:
398 mButtonNeutralText = text;
399 mButtonNeutralMessage = msg;
400 break;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 default:
403 throw new IllegalArgumentException("Button does not exist");
404 }
405 }
406
407 /**
Alan Viverettea1a68042014-04-28 13:30:08 -0700408 * Specifies the icon to display next to the alert title.
409 *
410 * @param resId the resource identifier of the drawable to use as the icon,
411 * or 0 for no icon
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 */
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100413 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 public void setIcon(int resId) {
Alan Viverettea1a68042014-04-28 13:30:08 -0700415 mIcon = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 mIconId = resId;
Alan Viverettea1a68042014-04-28 13:30:08 -0700417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 if (mIconView != null) {
Alan Viverettea1a68042014-04-28 13:30:08 -0700419 if (resId != 0) {
Chris Banes476da772015-12-15 17:14:15 +0000420 mIconView.setVisibility(View.VISIBLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 mIconView.setImageResource(mIconId);
Alan Viverettea1a68042014-04-28 13:30:08 -0700422 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 mIconView.setVisibility(View.GONE);
424 }
425 }
426 }
Alan Viverettea1a68042014-04-28 13:30:08 -0700427
428 /**
429 * Specifies the icon to display next to the alert title.
430 *
431 * @param icon the drawable to use as the icon or null for no icon
432 */
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100433 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 public void setIcon(Drawable icon) {
435 mIcon = icon;
Alan Viverettea1a68042014-04-28 13:30:08 -0700436 mIconId = 0;
437
438 if (mIconView != null) {
439 if (icon != null) {
Chris Banes12a47ac2015-12-17 10:00:26 +0000440 mIconView.setVisibility(View.VISIBLE);
Alan Viverettea1a68042014-04-28 13:30:08 -0700441 mIconView.setImageDrawable(icon);
442 } else {
443 mIconView.setVisibility(View.GONE);
444 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 }
446 }
447
blunden576e1df2012-09-10 23:29:04 +0200448 /**
449 * @param attrId the attributeId of the theme-specific drawable
450 * to resolve the resourceId for.
451 *
452 * @return resId the resourceId of the theme-specific drawable
453 */
454 public int getIconAttributeResId(int attrId) {
455 TypedValue out = new TypedValue();
456 mContext.getTheme().resolveAttribute(attrId, out, true);
457 return out.resourceId;
458 }
459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 public void setInverseBackgroundForced(boolean forceInverseBackground) {
461 mForceInverseBackground = forceInverseBackground;
462 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700463
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100464 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 public ListView getListView() {
466 return mListView;
467 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700468
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100469 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 public Button getButton(int whichButton) {
471 switch (whichButton) {
472 case DialogInterface.BUTTON_POSITIVE:
Romain Guy6fe2b222010-02-22 14:11:40 -0800473 return mButtonPositive;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 case DialogInterface.BUTTON_NEGATIVE:
Romain Guy6fe2b222010-02-22 14:11:40 -0800475 return mButtonNegative;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 case DialogInterface.BUTTON_NEUTRAL:
Romain Guy6fe2b222010-02-22 14:11:40 -0800477 return mButtonNeutral;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 default:
479 return null;
480 }
481 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700482
Romain Guy6fe2b222010-02-22 14:11:40 -0800483 @SuppressWarnings({"UnusedDeclaration"})
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100484 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 public boolean onKeyDown(int keyCode, KeyEvent event) {
Romain Guy6fe2b222010-02-22 14:11:40 -0800486 return mScrollView != null && mScrollView.executeKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 }
488
Romain Guy6fe2b222010-02-22 14:11:40 -0800489 @SuppressWarnings({"UnusedDeclaration"})
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100490 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 public boolean onKeyUp(int keyCode, KeyEvent event) {
Romain Guy6fe2b222010-02-22 14:11:40 -0800492 return mScrollView != null && mScrollView.executeKeyEvent(event);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 }
Vinod Krishnan119ba2c2014-05-05 14:58:15 -0700494
Alan Viverette62c79e92015-02-26 09:47:10 -0800495 /**
496 * Resolves whether a custom or default panel should be used. Removes the
497 * default panel if a custom panel should be used. If the resolved panel is
498 * a view stub, inflates before returning.
499 *
500 * @param customPanel the custom panel
501 * @param defaultPanel the default panel
502 * @return the panel to use
503 */
504 @Nullable
505 private ViewGroup resolvePanel(@Nullable View customPanel, @Nullable View defaultPanel) {
506 if (customPanel == null) {
507 // Inflate the default panel, if needed.
508 if (defaultPanel instanceof ViewStub) {
509 defaultPanel = ((ViewStub) defaultPanel).inflate();
510 }
511
512 return (ViewGroup) defaultPanel;
513 }
514
515 // Remove the default panel entirely.
516 if (defaultPanel != null) {
517 final ViewParent parent = defaultPanel.getParent();
518 if (parent instanceof ViewGroup) {
519 ((ViewGroup) parent).removeView(defaultPanel);
520 }
521 }
522
523 // Inflate the custom panel, if needed.
524 if (customPanel instanceof ViewStub) {
525 customPanel = ((ViewStub) customPanel).inflate();
526 }
527
528 return (ViewGroup) customPanel;
529 }
530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 private void setupView() {
Alan Viverette62c79e92015-02-26 09:47:10 -0800532 final View parentPanel = mWindow.findViewById(R.id.parentPanel);
533 final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
534 final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
535 final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
536
537 // Install custom content before setting up the title or buttons so
538 // that we can handle panel overrides.
539 final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
540 setupCustomContent(customPanel);
541
542 final View customTopPanel = customPanel.findViewById(R.id.topPanel);
543 final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
544 final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);
545
546 // Resolve the correct panels and remove the defaults, if needed.
547 final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
548 final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
549 final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 setupContent(contentPanel);
Alan Viverette62c79e92015-02-26 09:47:10 -0800552 setupButtons(buttonPanel);
553 setupTitle(topPanel);
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700554
Alan Viverette62c79e92015-02-26 09:47:10 -0800555 final boolean hasCustomPanel = customPanel != null
556 && customPanel.getVisibility() != View.GONE;
557 final boolean hasTopPanel = topPanel != null
558 && topPanel.getVisibility() != View.GONE;
559 final boolean hasButtonPanel = buttonPanel != null
560 && buttonPanel.getVisibility() != View.GONE;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700561
Robert Horvathb96ca992019-04-02 19:05:26 +0200562 if (!parentPanel.isInTouchMode()) {
563 final View content = hasCustomPanel ? customPanel : contentPanel;
564 if (!requestFocusForContent(content)) {
565 requestFocusForDefaultButton();
566 }
567 }
568
Alan Viverette62c79e92015-02-26 09:47:10 -0800569 // Only display the text spacer if we don't have buttons.
570 if (!hasButtonPanel) {
571 if (contentPanel != null) {
572 final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
573 if (spacer != null) {
574 spacer.setVisibility(View.VISIBLE);
575 }
Adam Powelld044ad92014-09-15 14:30:23 -0700576 }
Dianne Hackbornef575752011-01-18 17:35:17 -0800577 mWindow.setCloseOnTouchOutsideIfNotSet(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 }
579
Alan Viverette62c79e92015-02-26 09:47:10 -0800580 if (hasTopPanel) {
Alan Viverette922e1c62015-05-05 17:18:27 -0700581 // Only clip scrolling content to padding if we have a title.
582 if (mScrollView != null) {
583 mScrollView.setClipToPadding(true);
584 }
585
586 // Only show the divider if we have a title.
Alan Viveretted6bfb822016-03-30 20:56:30 -0400587 View divider = null;
Alan Viverette922e1c62015-05-05 17:18:27 -0700588 if (mMessage != null || mListView != null || hasCustomPanel) {
Alan Viveretted6bfb822016-03-30 20:56:30 -0400589 if (!hasCustomPanel) {
590 divider = topPanel.findViewById(R.id.titleDividerNoCustom);
591 }
592 if (divider == null) {
593 divider = topPanel.findViewById(R.id.titleDivider);
594 }
595
Alan Viverette62c79e92015-02-26 09:47:10 -0800596 } else {
597 divider = topPanel.findViewById(R.id.titleDividerTop);
598 }
599
600 if (divider != null) {
601 divider.setVisibility(View.VISIBLE);
602 }
Alan Viveretted6bfb822016-03-30 20:56:30 -0400603 } else {
604 if (contentPanel != null) {
605 final View spacer = contentPanel.findViewById(R.id.textSpacerNoTitle);
606 if (spacer != null) {
607 spacer.setVisibility(View.VISIBLE);
608 }
609 }
610 }
611
612 if (mListView instanceof RecycleListView) {
613 ((RecycleListView) mListView).setHasDecor(hasTopPanel, hasButtonPanel);
Alan Viverette62c79e92015-02-26 09:47:10 -0800614 }
615
Alan Viverette922e1c62015-05-05 17:18:27 -0700616 // Update scroll indicators as needed.
617 if (!hasCustomPanel) {
618 final View content = mListView != null ? mListView : mScrollView;
619 if (content != null) {
620 final int indicators = (hasTopPanel ? View.SCROLL_INDICATOR_TOP : 0)
621 | (hasButtonPanel ? View.SCROLL_INDICATOR_BOTTOM : 0);
622 content.setScrollIndicators(indicators,
623 View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
624 }
625 }
626
Alan Viverette62c79e92015-02-26 09:47:10 -0800627 final TypedArray a = mContext.obtainStyledAttributes(
628 null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
629 setBackground(a, topPanel, contentPanel, customPanel, buttonPanel,
630 hasTopPanel, hasCustomPanel, hasButtonPanel);
631 a.recycle();
632 }
633
Robert Horvathb96ca992019-04-02 19:05:26 +0200634 private boolean requestFocusForContent(View content) {
635 if (content != null && content.requestFocus()) {
636 return true;
637 }
638
639 if (mListView != null) {
640 mListView.setSelection(0);
641 return true;
642 }
643
644 return false;
645 }
646
647 private void requestFocusForDefaultButton() {
648 if (mButtonPositive.getVisibility() == View.VISIBLE) {
649 mButtonPositive.requestFocus();
650 } else if (mButtonNegative.getVisibility() == View.VISIBLE) {
651 mButtonNegative.requestFocus();
652 } else if (mButtonNeutral.getVisibility() == View.VISIBLE) {
653 mButtonNeutral.requestFocus();
654 }
655 }
656
Alan Viverette62c79e92015-02-26 09:47:10 -0800657 private void setupCustomContent(ViewGroup customPanel) {
Alan Viveretteec186702013-12-05 11:10:31 -0800658 final View customView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 if (mView != null) {
Alan Viveretteec186702013-12-05 11:10:31 -0800660 customView = mView;
661 } else if (mViewLayoutResId != 0) {
662 final LayoutInflater inflater = LayoutInflater.from(mContext);
663 customView = inflater.inflate(mViewLayoutResId, customPanel, false);
664 } else {
665 customView = null;
666 }
667
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800668 final boolean hasCustomView = customView != null;
669 if (!hasCustomView || !canTextInput(customView)) {
Alan Viveretteec186702013-12-05 11:10:31 -0800670 mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
671 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
672 }
673
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800674 if (hasCustomView) {
Alan Viveretteec186702013-12-05 11:10:31 -0800675 final FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);
676 custom.addView(customView, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 if (mViewSpacingSpecified) {
Alan Viveretteec186702013-12-05 11:10:31 -0800679 custom.setPadding(
680 mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 }
Alan Viveretteec186702013-12-05 11:10:31 -0800682
The Android Open Source Project10592532009-03-18 17:39:46 -0700683 if (mListView != null) {
684 ((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0;
685 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 } else {
Alan Viveretteec186702013-12-05 11:10:31 -0800687 customPanel.setVisibility(View.GONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 }
690
Michael Kwan81450812016-07-19 09:48:45 -0700691 protected void setupTitle(ViewGroup topPanel) {
Alan Viverette2e750a12016-01-29 12:53:26 -0500692 if (mCustomTitleView != null && mShowTitle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 // Add the custom title view directly to the topPanel layout
Alan Viverette2e750a12016-01-29 12:53:26 -0500694 final LayoutParams lp = new LayoutParams(
Alan Viverette154c2c22014-10-29 15:46:06 -0700695 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700696
Adam Powell5ea0bc12011-07-21 13:07:05 -0700697 topPanel.addView(mCustomTitleView, 0, lp);
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 // Hide the title template
Alan Viverette2e750a12016-01-29 12:53:26 -0500700 final View titleTemplate = mWindow.findViewById(R.id.title_template);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 titleTemplate.setVisibility(View.GONE);
702 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 mIconView = (ImageView) mWindow.findViewById(R.id.icon);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704
Alan Viverettea1a68042014-04-28 13:30:08 -0700705 final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
Alan Viverette2e750a12016-01-29 12:53:26 -0500706 if (hasTextTitle && mShowTitle) {
Alan Viverettea1a68042014-04-28 13:30:08 -0700707 // Display the title if a title is supplied, else hide it.
708 mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 mTitleView.setText(mTitle);
Alan Viverettea1a68042014-04-28 13:30:08 -0700710
711 // Do this last so that if the user has supplied any icons we
712 // use them instead of the default ones. If the user has
713 // specified 0 then make it disappear.
714 if (mIconId != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 mIconView.setImageResource(mIconId);
716 } else if (mIcon != null) {
717 mIconView.setImageDrawable(mIcon);
Alan Viverettea1a68042014-04-28 13:30:08 -0700718 } else {
719 // Apply the padding from the icon to ensure the title is
720 // aligned correctly.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 mTitleView.setPadding(mIconView.getPaddingLeft(),
722 mIconView.getPaddingTop(),
723 mIconView.getPaddingRight(),
724 mIconView.getPaddingBottom());
725 mIconView.setVisibility(View.GONE);
726 }
727 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 // Hide the title template
Alan Viverettea1a68042014-04-28 13:30:08 -0700729 final View titleTemplate = mWindow.findViewById(R.id.title_template);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 titleTemplate.setVisibility(View.GONE);
731 mIconView.setVisibility(View.GONE);
Martin Sjoline74e7e22010-06-22 21:42:11 +0200732 topPanel.setVisibility(View.GONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 }
734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 }
736
Michael Kwancc6e6f02016-05-16 12:54:57 -0700737 protected void setupContent(ViewGroup contentPanel) {
Alan Viverette62c79e92015-02-26 09:47:10 -0800738 mScrollView = (ScrollView) contentPanel.findViewById(R.id.scrollView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 mScrollView.setFocusable(false);
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 // Special case for users that only want to display a String
Alan Viverette62c79e92015-02-26 09:47:10 -0800742 mMessageView = (TextView) contentPanel.findViewById(R.id.message);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 if (mMessageView == null) {
744 return;
745 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 if (mMessage != null) {
748 mMessageView.setText(mMessage);
Makoto Onukie8bbf952018-04-20 14:04:50 -0700749 if (mMessageMovementMethod != null) {
750 mMessageView.setMovementMethod(mMessageMovementMethod);
751 }
752 if (mMessageHyphenationFrequency != null) {
753 mMessageView.setHyphenationFrequency(mMessageHyphenationFrequency);
754 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 } else {
756 mMessageView.setVisibility(View.GONE);
757 mScrollView.removeView(mMessageView);
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 if (mListView != null) {
Alan Viverette35c3cb62014-10-30 13:51:21 -0700760 final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent();
761 final int childIndex = scrollParent.indexOfChild(mScrollView);
762 scrollParent.removeViewAt(childIndex);
763 scrollParent.addView(mListView, childIndex,
Alan Viverette154c2c22014-10-29 15:46:06 -0700764 new LayoutParams(MATCH_PARENT, MATCH_PARENT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 } else {
766 contentPanel.setVisibility(View.GONE);
767 }
768 }
Alan Viverette154c2c22014-10-29 15:46:06 -0700769 }
770
771 private static void manageScrollIndicators(View v, View upIndicator, View downIndicator) {
772 if (upIndicator != null) {
773 upIndicator.setVisibility(v.canScrollVertically(-1) ? View.VISIBLE : View.INVISIBLE);
774 }
775 if (downIndicator != null) {
776 downIndicator.setVisibility(v.canScrollVertically(1) ? View.VISIBLE : View.INVISIBLE);
777 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 }
779
Michael Kwan81450812016-07-19 09:48:45 -0700780 protected void setupButtons(ViewGroup buttonPanel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 int BIT_BUTTON_POSITIVE = 1;
782 int BIT_BUTTON_NEGATIVE = 2;
783 int BIT_BUTTON_NEUTRAL = 4;
784 int whichButtons = 0;
Alan Viverette62c79e92015-02-26 09:47:10 -0800785 mButtonPositive = (Button) buttonPanel.findViewById(R.id.button1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 mButtonPositive.setOnClickListener(mButtonHandler);
787
788 if (TextUtils.isEmpty(mButtonPositiveText)) {
789 mButtonPositive.setVisibility(View.GONE);
790 } else {
791 mButtonPositive.setText(mButtonPositiveText);
792 mButtonPositive.setVisibility(View.VISIBLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
794 }
795
Alan Viverette62c79e92015-02-26 09:47:10 -0800796 mButtonNegative = (Button) buttonPanel.findViewById(R.id.button2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 mButtonNegative.setOnClickListener(mButtonHandler);
798
799 if (TextUtils.isEmpty(mButtonNegativeText)) {
800 mButtonNegative.setVisibility(View.GONE);
801 } else {
802 mButtonNegative.setText(mButtonNegativeText);
803 mButtonNegative.setVisibility(View.VISIBLE);
804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
806 }
807
Alan Viverette62c79e92015-02-26 09:47:10 -0800808 mButtonNeutral = (Button) buttonPanel.findViewById(R.id.button3);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 mButtonNeutral.setOnClickListener(mButtonHandler);
810
811 if (TextUtils.isEmpty(mButtonNeutralText)) {
812 mButtonNeutral.setVisibility(View.GONE);
813 } else {
814 mButtonNeutral.setText(mButtonNeutralText);
815 mButtonNeutral.setVisibility(View.VISIBLE);
816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
818 }
819
Adam Powell3320dcd2010-11-05 20:06:02 -0700820 if (shouldCenterSingleButton(mContext)) {
821 /*
822 * If we only have 1 button it should be centered on the layout and
823 * expand to fill 50% of the available space.
824 */
825 if (whichButtons == BIT_BUTTON_POSITIVE) {
826 centerButton(mButtonPositive);
827 } else if (whichButtons == BIT_BUTTON_NEGATIVE) {
Sangkyu Lee3079e582013-02-15 21:11:18 +0900828 centerButton(mButtonNegative);
Adam Powell3320dcd2010-11-05 20:06:02 -0700829 } else if (whichButtons == BIT_BUTTON_NEUTRAL) {
830 centerButton(mButtonNeutral);
831 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700833
Alan Viverette62c79e92015-02-26 09:47:10 -0800834 final boolean hasButtons = whichButtons != 0;
835 if (!hasButtons) {
836 buttonPanel.setVisibility(View.GONE);
837 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 }
839
840 private void centerButton(Button button) {
841 LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) button.getLayoutParams();
842 params.gravity = Gravity.CENTER_HORIZONTAL;
843 params.weight = 0.5f;
844 button.setLayoutParams(params);
845 View leftSpacer = mWindow.findViewById(R.id.leftSpacer);
Adam Powella93347a2011-06-14 13:37:14 -0700846 if (leftSpacer != null) {
847 leftSpacer.setVisibility(View.VISIBLE);
848 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 View rightSpacer = mWindow.findViewById(R.id.rightSpacer);
Adam Powella93347a2011-06-14 13:37:14 -0700850 if (rightSpacer != null) {
851 rightSpacer.setVisibility(View.VISIBLE);
852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800855 private void setBackground(TypedArray a, View topPanel, View contentPanel, View customPanel,
856 View buttonPanel, boolean hasTitle, boolean hasCustomView, boolean hasButtons) {
Vinod Krishnan119ba2c2014-05-05 14:58:15 -0700857 int fullDark = 0;
858 int topDark = 0;
859 int centerDark = 0;
860 int bottomDark = 0;
861 int fullBright = 0;
862 int topBright = 0;
863 int centerBright = 0;
864 int bottomBright = 0;
865 int bottomMedium = 0;
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700866
867 // If the needsDefaultBackgrounds attribute is set, we know we're
868 // inheriting from a framework style.
869 final boolean needsDefaultBackgrounds = a.getBoolean(
870 R.styleable.AlertDialog_needsDefaultBackgrounds, true);
871 if (needsDefaultBackgrounds) {
Vinod Krishnan119ba2c2014-05-05 14:58:15 -0700872 fullDark = R.drawable.popup_full_dark;
873 topDark = R.drawable.popup_top_dark;
874 centerDark = R.drawable.popup_center_dark;
875 bottomDark = R.drawable.popup_bottom_dark;
876 fullBright = R.drawable.popup_full_bright;
877 topBright = R.drawable.popup_top_bright;
878 centerBright = R.drawable.popup_center_bright;
879 bottomBright = R.drawable.popup_bottom_bright;
880 bottomMedium = R.drawable.popup_bottom_medium;
881 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -0700882
Vinod Krishnan119ba2c2014-05-05 14:58:15 -0700883 topBright = a.getResourceId(R.styleable.AlertDialog_topBright, topBright);
Vinod Krishnan4a3735d2014-05-09 12:04:35 -0700884 topDark = a.getResourceId(R.styleable.AlertDialog_topDark, topDark);
Vinod Krishnan119ba2c2014-05-05 14:58:15 -0700885 centerBright = a.getResourceId(R.styleable.AlertDialog_centerBright, centerBright);
Vinod Krishnan4a3735d2014-05-09 12:04:35 -0700886 centerDark = a.getResourceId(R.styleable.AlertDialog_centerDark, centerDark);
Vinod Krishnan119ba2c2014-05-05 14:58:15 -0700887
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800888 /* We now set the background of all of the sections of the alert.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 * First collect together each section that is being displayed along
890 * with whether it is on a light or dark background, then run through
891 * them setting their backgrounds. This is complicated because we need
892 * to correctly use the full, top, middle, and bottom graphics depending
893 * on how many views they are and where they appear.
894 */
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800895
896 final View[] views = new View[4];
897 final boolean[] light = new boolean[4];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 View lastView = null;
899 boolean lastLight = false;
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 int pos = 0;
902 if (hasTitle) {
903 views[pos] = topPanel;
904 light[pos] = false;
905 pos++;
906 }
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 /* The contentPanel displays either a custom text message or
909 * a ListView. If it's text we should use the dark background
910 * for ListView we should use the light background. If neither
911 * are there the contentPanel will be hidden so set it as null.
912 */
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800913 views[pos] = contentPanel.getVisibility() == View.GONE ? null : contentPanel;
Romain Guy6fe2b222010-02-22 14:11:40 -0800914 light[pos] = mListView != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 pos++;
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800916
917 if (hasCustomView) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 views[pos] = customPanel;
919 light[pos] = mForceInverseBackground;
920 pos++;
921 }
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 if (hasButtons) {
924 views[pos] = buttonPanel;
925 light[pos] = true;
926 }
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 boolean setView = false;
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800929 for (pos = 0; pos < views.length; pos++) {
930 final View v = views[pos];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 if (v == null) {
932 continue;
933 }
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 if (lastView != null) {
936 if (!setView) {
937 lastView.setBackgroundResource(lastLight ? topBright : topDark);
938 } else {
939 lastView.setBackgroundResource(lastLight ? centerBright : centerDark);
940 }
941 setView = true;
942 }
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800943
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 lastView = v;
945 lastLight = light[pos];
946 }
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800947
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 if (lastView != null) {
949 if (setView) {
Vinod Krishnan4a3735d2014-05-09 12:04:35 -0700950 bottomBright = a.getResourceId(R.styleable.AlertDialog_bottomBright, bottomBright);
951 bottomMedium = a.getResourceId(R.styleable.AlertDialog_bottomMedium, bottomMedium);
952 bottomDark = a.getResourceId(R.styleable.AlertDialog_bottomDark, bottomDark);
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800953
954 // ListViews will use the Bright background, but buttons use the
955 // Medium background.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 lastView.setBackgroundResource(
957 lastLight ? (hasButtons ? bottomMedium : bottomBright) : bottomDark);
958 } else {
Vinod Krishnan4a3735d2014-05-09 12:04:35 -0700959 fullBright = a.getResourceId(R.styleable.AlertDialog_fullBright, fullBright);
960 fullDark = a.getResourceId(R.styleable.AlertDialog_fullDark, fullDark);
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 lastView.setBackgroundResource(lastLight ? fullBright : fullDark);
963 }
964 }
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800965
Alan Viverettec3cf19a2014-02-18 18:29:11 -0800966 final ListView listView = mListView;
967 if (listView != null && mAdapter != null) {
968 listView.setAdapter(mAdapter);
969 final int checkedItem = mCheckedItem;
970 if (checkedItem > -1) {
Michael Kwan55e40302016-07-22 12:17:04 -0700971 listView.setItemChecked(checkedItem, true);
Michael Kwan44f854a2016-08-18 15:15:26 -0700972 listView.setSelectionFromTop(checkedItem,
973 a.getDimensionPixelSize(R.styleable.AlertDialog_selectionScrollOffset, 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 }
975 }
976 }
Romain Guy9c802c12009-03-25 15:07:31 -0700977
978 public static class RecycleListView extends ListView {
Alan Viveretted6bfb822016-03-30 20:56:30 -0400979 private final int mPaddingTopNoTitle;
980 private final int mPaddingBottomNoButtons;
981
Romain Guy9c802c12009-03-25 15:07:31 -0700982 boolean mRecycleOnMeasure = true;
983
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100984 @UnsupportedAppUsage
Romain Guy9c802c12009-03-25 15:07:31 -0700985 public RecycleListView(Context context) {
Alan Viveretted6bfb822016-03-30 20:56:30 -0400986 this(context, null);
Romain Guy9c802c12009-03-25 15:07:31 -0700987 }
988
Mathew Inwoodaf972c82018-08-20 14:13:20 +0100989 @UnsupportedAppUsage
Romain Guy9c802c12009-03-25 15:07:31 -0700990 public RecycleListView(Context context, AttributeSet attrs) {
991 super(context, attrs);
Alan Viveretted6bfb822016-03-30 20:56:30 -0400992
993 final TypedArray ta = context.obtainStyledAttributes(
994 attrs, R.styleable.RecycleListView);
995 mPaddingBottomNoButtons = ta.getDimensionPixelOffset(
996 R.styleable.RecycleListView_paddingBottomNoButtons, -1);
997 mPaddingTopNoTitle = ta.getDimensionPixelOffset(
998 R.styleable.RecycleListView_paddingTopNoTitle, -1);
Romain Guy9c802c12009-03-25 15:07:31 -0700999 }
1000
Alan Viveretted6bfb822016-03-30 20:56:30 -04001001 public void setHasDecor(boolean hasTitle, boolean hasButtons) {
1002 if (!hasButtons || !hasTitle) {
1003 final int paddingLeft = getPaddingLeft();
1004 final int paddingTop = hasTitle ? getPaddingTop() : mPaddingTopNoTitle;
1005 final int paddingRight = getPaddingRight();
1006 final int paddingBottom = hasButtons ? getPaddingBottom() : mPaddingBottomNoButtons;
1007 setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
1008 }
Romain Guy9c802c12009-03-25 15:07:31 -07001009 }
1010
1011 @Override
1012 protected boolean recycleOnMeasure() {
1013 return mRecycleOnMeasure;
1014 }
1015 }
1016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 public static class AlertParams {
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001018 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 public final Context mContext;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001020 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 public final LayoutInflater mInflater;
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001022
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001023 @UnsupportedAppUsage
Gilles Debunne076c7fb2010-10-04 12:00:02 -07001024 public int mIconId = 0;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001025 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 public Drawable mIcon;
blunden576e1df2012-09-10 23:29:04 +02001027 public int mIconAttrId = 0;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001028 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 public CharSequence mTitle;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001030 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 public View mCustomTitleView;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001032 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 public CharSequence mMessage;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001034 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 public CharSequence mPositiveButtonText;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001036 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 public DialogInterface.OnClickListener mPositiveButtonListener;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001038 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 public CharSequence mNegativeButtonText;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001040 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 public DialogInterface.OnClickListener mNegativeButtonListener;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001042 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 public CharSequence mNeutralButtonText;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001044 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 public DialogInterface.OnClickListener mNeutralButtonListener;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001046 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 public boolean mCancelable;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001048 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 public DialogInterface.OnCancelListener mOnCancelListener;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001050 @UnsupportedAppUsage
Adam Powell7f02dc52012-08-27 13:35:16 -07001051 public DialogInterface.OnDismissListener mOnDismissListener;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001052 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 public DialogInterface.OnKeyListener mOnKeyListener;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001054 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 public CharSequence[] mItems;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001056 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 public ListAdapter mAdapter;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001058 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 public DialogInterface.OnClickListener mOnClickListener;
Alan Viveretteec186702013-12-05 11:10:31 -08001060 public int mViewLayoutResId;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001061 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 public View mView;
1063 public int mViewSpacingLeft;
1064 public int mViewSpacingTop;
1065 public int mViewSpacingRight;
1066 public int mViewSpacingBottom;
1067 public boolean mViewSpacingSpecified = false;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001068 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 public boolean[] mCheckedItems;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001070 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 public boolean mIsMultiChoice;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001072 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 public boolean mIsSingleChoice;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001074 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 public int mCheckedItem = -1;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001076 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 public DialogInterface.OnMultiChoiceClickListener mOnCheckboxClickListener;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001078 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 public Cursor mCursor;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001080 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 public String mLabelColumn;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001082 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 public String mIsCheckedColumn;
1084 public boolean mForceInverseBackground;
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001085 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 public AdapterView.OnItemSelectedListener mOnItemSelectedListener;
1087 public OnPrepareListViewListener mOnPrepareListViewListener;
Romain Guy9c802c12009-03-25 15:07:31 -07001088 public boolean mRecycleOnMeasure = true;
1089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 /**
1091 * Interface definition for a callback to be invoked before the ListView
1092 * will be bound to an adapter.
1093 */
1094 public interface OnPrepareListViewListener {
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001095
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 /**
1097 * Called before the ListView is bound to an adapter.
1098 * @param listView The ListView that will be shown in the dialog.
1099 */
1100 void onPrepareListView(ListView listView);
1101 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001102
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001103 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 public AlertParams(Context context) {
1105 mContext = context;
1106 mCancelable = true;
1107 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
1108 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001109
Mathew Inwoodaf972c82018-08-20 14:13:20 +01001110 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 public void apply(AlertController dialog) {
1112 if (mCustomTitleView != null) {
1113 dialog.setCustomTitle(mCustomTitleView);
1114 } else {
1115 if (mTitle != null) {
1116 dialog.setTitle(mTitle);
1117 }
1118 if (mIcon != null) {
1119 dialog.setIcon(mIcon);
1120 }
Alan Viverette5c2d8f72015-01-05 12:56:45 -08001121 if (mIconId != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122 dialog.setIcon(mIconId);
1123 }
Alan Viverette5c2d8f72015-01-05 12:56:45 -08001124 if (mIconAttrId != 0) {
blunden576e1df2012-09-10 23:29:04 +02001125 dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
1126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 }
1128 if (mMessage != null) {
1129 dialog.setMessage(mMessage);
1130 }
1131 if (mPositiveButtonText != null) {
1132 dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
1133 mPositiveButtonListener, null);
1134 }
1135 if (mNegativeButtonText != null) {
1136 dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
1137 mNegativeButtonListener, null);
1138 }
1139 if (mNeutralButtonText != null) {
1140 dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
1141 mNeutralButtonListener, null);
1142 }
1143 if (mForceInverseBackground) {
1144 dialog.setInverseBackgroundForced(true);
1145 }
1146 // For a list, the client can either supply an array of items or an
1147 // adapter or a cursor
1148 if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
1149 createListView(dialog);
1150 }
1151 if (mView != null) {
1152 if (mViewSpacingSpecified) {
1153 dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
1154 mViewSpacingBottom);
1155 } else {
1156 dialog.setView(mView);
1157 }
Alan Viveretteec186702013-12-05 11:10:31 -08001158 } else if (mViewLayoutResId != 0) {
1159 dialog.setView(mViewLayoutResId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 }
Alan Viveretteec186702013-12-05 11:10:31 -08001161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 /*
1163 dialog.setCancelable(mCancelable);
1164 dialog.setOnCancelListener(mOnCancelListener);
1165 if (mOnKeyListener != null) {
1166 dialog.setOnKeyListener(mOnKeyListener);
1167 }
1168 */
1169 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 private void createListView(final AlertController dialog) {
Alan Viverette89900832015-04-08 12:45:54 -07001172 final RecycleListView listView =
1173 (RecycleListView) mInflater.inflate(dialog.mListLayout, null);
1174 final ListAdapter adapter;
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 if (mIsMultiChoice) {
1177 if (mCursor == null) {
1178 adapter = new ArrayAdapter<CharSequence>(
Adam Powellfcca00a2010-11-30 21:26:29 -08001179 mContext, dialog.mMultiChoiceItemLayout, R.id.text1, mItems) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 @Override
1181 public View getView(int position, View convertView, ViewGroup parent) {
1182 View view = super.getView(position, convertView, parent);
1183 if (mCheckedItems != null) {
1184 boolean isItemChecked = mCheckedItems[position];
1185 if (isItemChecked) {
Michael Kwan55e40302016-07-22 12:17:04 -07001186 listView.setItemChecked(position, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 }
1188 }
1189 return view;
1190 }
1191 };
1192 } else {
1193 adapter = new CursorAdapter(mContext, mCursor, false) {
1194 private final int mLabelIndex;
1195 private final int mIsCheckedIndex;
1196
1197 {
1198 final Cursor cursor = getCursor();
1199 mLabelIndex = cursor.getColumnIndexOrThrow(mLabelColumn);
1200 mIsCheckedIndex = cursor.getColumnIndexOrThrow(mIsCheckedColumn);
1201 }
1202
1203 @Override
1204 public void bindView(View view, Context context, Cursor cursor) {
1205 CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1);
1206 text.setText(cursor.getString(mLabelIndex));
Michael Kwan55e40302016-07-22 12:17:04 -07001207 listView.setItemChecked(
1208 cursor.getPosition(),
1209 cursor.getInt(mIsCheckedIndex) == 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 @Override
1213 public View newView(Context context, Cursor cursor, ViewGroup parent) {
Adam Powellfcca00a2010-11-30 21:26:29 -08001214 return mInflater.inflate(dialog.mMultiChoiceItemLayout,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 parent, false);
1216 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 };
1219 }
1220 } else {
Alan Viverette89900832015-04-08 12:45:54 -07001221 final int layout;
1222 if (mIsSingleChoice) {
1223 layout = dialog.mSingleChoiceItemLayout;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 } else {
Alan Viverette89900832015-04-08 12:45:54 -07001225 layout = dialog.mListItemLayout;
1226 }
1227
1228 if (mCursor != null) {
1229 adapter = new SimpleCursorAdapter(mContext, layout, mCursor,
1230 new String[] { mLabelColumn }, new int[] { R.id.text1 });
1231 } else if (mAdapter != null) {
1232 adapter = mAdapter;
1233 } else {
1234 adapter = new CheckedItemAdapter(mContext, layout, R.id.text1, mItems);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 }
1236 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 if (mOnPrepareListViewListener != null) {
1239 mOnPrepareListViewListener.onPrepareListView(listView);
1240 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 /* Don't directly set the adapter on the ListView as we might
1243 * want to add a footer to the ListView later.
1244 */
1245 dialog.mAdapter = adapter;
1246 dialog.mCheckedItem = mCheckedItem;
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 if (mOnClickListener != null) {
1249 listView.setOnItemClickListener(new OnItemClickListener() {
Alan Viverettec3cf19a2014-02-18 18:29:11 -08001250 @Override
1251 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 mOnClickListener.onClick(dialog.mDialogInterface, position);
1253 if (!mIsSingleChoice) {
1254 dialog.mDialogInterface.dismiss();
1255 }
1256 }
1257 });
1258 } else if (mOnCheckboxClickListener != null) {
1259 listView.setOnItemClickListener(new OnItemClickListener() {
Alan Viverettec3cf19a2014-02-18 18:29:11 -08001260 @Override
1261 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 if (mCheckedItems != null) {
1263 mCheckedItems[position] = listView.isItemChecked(position);
1264 }
1265 mOnCheckboxClickListener.onClick(
1266 dialog.mDialogInterface, position, listView.isItemChecked(position));
1267 }
1268 });
1269 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001270
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 // Attach a given OnItemSelectedListener to the ListView
1272 if (mOnItemSelectedListener != null) {
1273 listView.setOnItemSelectedListener(mOnItemSelectedListener);
1274 }
Alan Viveretteb17c6c12014-09-03 16:27:51 -07001275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 if (mIsSingleChoice) {
1277 listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
1278 } else if (mIsMultiChoice) {
1279 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
1280 }
Romain Guy9c802c12009-03-25 15:07:31 -07001281 listView.mRecycleOnMeasure = mRecycleOnMeasure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 dialog.mListView = listView;
1283 }
1284 }
1285
Alan Viverette2356c5e2014-05-22 22:43:59 -07001286 private static class CheckedItemAdapter extends ArrayAdapter<CharSequence> {
1287 public CheckedItemAdapter(Context context, int resource, int textViewResourceId,
1288 CharSequence[] objects) {
1289 super(context, resource, textViewResourceId, objects);
1290 }
1291
1292 @Override
1293 public boolean hasStableIds() {
1294 return true;
1295 }
1296
1297 @Override
1298 public long getItemId(int position) {
1299 return position;
1300 }
1301 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302}