1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | package org.chromium.chrome.browser; |
6 | |
7 | import android.app.AlertDialog; |
8 | import android.content.Context; |
9 | import android.content.DialogInterface; |
10 | import android.util.Log; |
11 | import android.view.LayoutInflater; |
12 | import android.view.View; |
13 | import android.view.ViewGroup; |
14 | import android.widget.Button; |
15 | import android.widget.CheckBox; |
16 | import android.widget.EditText; |
17 | import android.widget.TextView; |
18 | |
19 | import com.google.common.annotations.VisibleForTesting; |
20 | |
21 | import org.chromium.base.CalledByNative; |
22 | import org.chromium.chrome.R; |
23 | import org.chromium.ui.WindowAndroid; |
24 | |
25 | public class JavascriptAppModalDialog implements DialogInterface.OnClickListener { |
26 | private static final String TAG = "JavascriptAppModalDialog"; |
27 | |
28 | private String mTitle; |
29 | private String mMessage; |
30 | private boolean mShouldShowSuppressCheckBox; |
31 | private int mNativeDialogPointer; |
32 | private AlertDialog mDialog; |
33 | private CheckBox mSuppressCheckBox; |
34 | private TextView mPrompTextView; |
35 | |
36 | private JavascriptAppModalDialog(String title, String message, |
37 | boolean shouldShowSuppressCheckBox) { |
38 | mTitle = title; |
39 | mMessage = message; |
40 | mShouldShowSuppressCheckBox = shouldShowSuppressCheckBox; |
41 | } |
42 | |
43 | @CalledByNative |
44 | public static JavascriptAppModalDialog createAlertDialog(String title, String message, |
45 | boolean shouldShowSuppressCheckBox) { |
46 | return new JavascriptAppAlertDialog(title, message, shouldShowSuppressCheckBox); |
47 | } |
48 | |
49 | @CalledByNative |
50 | public static JavascriptAppModalDialog createConfirmDialog(String title, String message, |
51 | boolean shouldShowSuppressCheckBox) { |
52 | return new JavascriptAppConfirmDialog(title, message, shouldShowSuppressCheckBox); |
53 | } |
54 | |
55 | @CalledByNative |
56 | public static JavascriptAppModalDialog createBeforeUnloadDialog(String title, String message, |
57 | boolean isReload, boolean shouldShowSuppressCheckBox) { |
58 | return new JavascriptAppBeforeUnloadDialog(title, message, isReload, |
59 | shouldShowSuppressCheckBox); |
60 | } |
61 | |
62 | @CalledByNative |
63 | public static JavascriptAppModalDialog createPromptDialog(String title, String message, |
64 | boolean shouldShowSuppressCheckBox, String defaultPromptText) { |
65 | return new JavascriptAppPromptDialog(title, message, shouldShowSuppressCheckBox, |
66 | defaultPromptText); |
67 | } |
68 | |
69 | @CalledByNative |
70 | void showJavascriptAppModalDialog(WindowAndroid window, int nativeDialogPointer) { |
71 | assert window != null; |
72 | Context context = window.getContext(); |
73 | |
74 | // Cache the native dialog pointer so that we can use it to return the response. |
75 | mNativeDialogPointer = nativeDialogPointer; |
76 | |
77 | LayoutInflater inflater = |
78 | (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
79 | |
80 | ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.js_modal_dialog, null); |
81 | mSuppressCheckBox = (CheckBox) layout.findViewById(R.id.suppress_js_modal_dialogs); |
82 | mPrompTextView = (TextView) layout.findViewById(R.id.js_modal_dialog_prompt); |
83 | |
84 | prepare(layout); |
85 | |
86 | AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context) |
87 | .setView(layout) |
88 | .setTitle(mTitle) |
89 | .setMessage(mMessage) |
90 | .setOnCancelListener(new DialogInterface.OnCancelListener() { |
91 | @Override |
92 | public void onCancel(DialogInterface dialog) { |
93 | cancel(false); |
94 | } |
95 | }); |
96 | if (hasPositiveButton()) { |
97 | dialogBuilder.setPositiveButton(getPositiveButtonText(), this); |
98 | } |
99 | if (hasNegativeButton()) { |
100 | dialogBuilder.setNegativeButton(getNegativeButtonText(), this); |
101 | } |
102 | |
103 | mDialog = dialogBuilder.create(); |
104 | mDialog.setCanceledOnTouchOutside(false); |
105 | mDialog.show(); |
106 | } |
107 | |
108 | @Override |
109 | public void onClick(DialogInterface dialog, int which) { |
110 | switch (which) { |
111 | case DialogInterface.BUTTON_POSITIVE: |
112 | onPositiveButtonClicked(); |
113 | break; |
114 | case DialogInterface.BUTTON_NEGATIVE: |
115 | onNegativeButtonClicked(); |
116 | break; |
117 | default: |
118 | Log.e(TAG, "Unexpected button pressed in dialog: " + which); |
119 | } |
120 | } |
121 | |
122 | @CalledByNative |
123 | void dismiss() { |
124 | mDialog.dismiss(); |
125 | mNativeDialogPointer = 0; |
126 | } |
127 | |
128 | /** |
129 | * Returns the currently showing dialog, null if none is showing. |
130 | */ |
131 | @VisibleForTesting |
132 | public static JavascriptAppModalDialog getCurrentDialogForTest() { |
133 | return nativeGetCurrentModalDialog(); |
134 | } |
135 | |
136 | |
137 | /** |
138 | * Returns the AlertDialog associated with this JavascriptAppPromptDialog. |
139 | */ |
140 | @VisibleForTesting |
141 | public AlertDialog getDialogForTest() { |
142 | return mDialog; |
143 | } |
144 | |
145 | // Methods that subclasses should override to set buttons behavior. |
146 | public boolean hasPositiveButton() { |
147 | return false; |
148 | } |
149 | |
150 | public int getPositiveButtonText() { |
151 | return -1; |
152 | } |
153 | |
154 | public boolean hasNegativeButton() { |
155 | return false; |
156 | } |
157 | |
158 | public int getNegativeButtonText() { |
159 | return -1; |
160 | } |
161 | |
162 | public void onPositiveButtonClicked() { |
163 | confirm(mPrompTextView.getText().toString(), mSuppressCheckBox.isChecked()); |
164 | mDialog.dismiss(); |
165 | } |
166 | |
167 | public void onNegativeButtonClicked() { |
168 | cancel(mSuppressCheckBox.isChecked()); |
169 | mDialog.dismiss(); |
170 | } |
171 | |
172 | void prepare(final ViewGroup layout) { |
173 | // Display the checkbox for supressing dialogs if necessary. |
174 | layout.findViewById(R.id.suppress_js_modal_dialogs).setVisibility( |
175 | mShouldShowSuppressCheckBox ? View.VISIBLE : View.GONE); |
176 | } |
177 | |
178 | public void confirm(String promptResult, boolean suppressDialogs) { |
179 | if (mNativeDialogPointer != 0) { |
180 | nativeDidAcceptAppModalDialog(mNativeDialogPointer, promptResult, suppressDialogs); |
181 | } |
182 | } |
183 | |
184 | public void cancel(boolean suppressDialogs) { |
185 | if (mNativeDialogPointer != 0) { |
186 | nativeDidCancelAppModalDialog(mNativeDialogPointer, suppressDialogs); |
187 | } |
188 | } |
189 | |
190 | private static class JavascriptAppAlertDialog extends JavascriptAppModalDialog { |
191 | public JavascriptAppAlertDialog(String title, String message, |
192 | boolean shouldShowSuppressCheckBox) { |
193 | super(title, message, shouldShowSuppressCheckBox); |
194 | } |
195 | |
196 | @Override |
197 | public boolean hasPositiveButton() { |
198 | return true; |
199 | } |
200 | |
201 | @Override |
202 | public int getPositiveButtonText() { |
203 | return R.string.js_modal_dialog_confirm; |
204 | } |
205 | } |
206 | |
207 | private static class JavascriptAppConfirmDialog extends JavascriptAppAlertDialog { |
208 | public JavascriptAppConfirmDialog(String title, String message, |
209 | boolean shouldShowSuppressCheckBox) { |
210 | super(title, message, shouldShowSuppressCheckBox); |
211 | } |
212 | |
213 | @Override |
214 | public boolean hasNegativeButton() { |
215 | return true; |
216 | } |
217 | |
218 | @Override |
219 | public int getNegativeButtonText() { |
220 | return R.string.js_modal_dialog_cancel; |
221 | } |
222 | } |
223 | |
224 | private static class JavascriptAppBeforeUnloadDialog extends JavascriptAppConfirmDialog { |
225 | private boolean mIsReload; |
226 | |
227 | public JavascriptAppBeforeUnloadDialog(String title, String message, |
228 | boolean isReload, boolean shouldShowSuppressCheckBox) { |
229 | super(title, message, shouldShowSuppressCheckBox); |
230 | mIsReload = isReload; |
231 | } |
232 | |
233 | @Override |
234 | public boolean hasPositiveButton() { |
235 | return true; |
236 | } |
237 | |
238 | @Override |
239 | public int getPositiveButtonText() { |
240 | return mIsReload ? R.string.reload_this_page : R.string.leave_this_page; |
241 | } |
242 | |
243 | @Override |
244 | public boolean hasNegativeButton() { |
245 | return true; |
246 | } |
247 | |
248 | @Override |
249 | public int getNegativeButtonText() { |
250 | return mIsReload ? R.string.dont_reload_this_page : R.string.stay_on_this_page; |
251 | } |
252 | } |
253 | |
254 | private static class JavascriptAppPromptDialog extends JavascriptAppConfirmDialog { |
255 | private String mDefaultPromptText; |
256 | |
257 | public JavascriptAppPromptDialog(String title, String message, |
258 | boolean shouldShowSuppressCheckBox, String defaultPromptText) { |
259 | super(title, message, shouldShowSuppressCheckBox); |
260 | mDefaultPromptText = defaultPromptText; |
261 | } |
262 | |
263 | @Override |
264 | public void prepare(ViewGroup layout) { |
265 | super.prepare(layout); |
266 | EditText prompt = (EditText) layout.findViewById(R.id.js_modal_dialog_prompt); |
267 | prompt.setVisibility(View.VISIBLE); |
268 | |
269 | if (mDefaultPromptText.length() > 0) { |
270 | prompt.setText(mDefaultPromptText); |
271 | prompt.selectAll(); |
272 | } |
273 | } |
274 | } |
275 | |
276 | private native void nativeDidAcceptAppModalDialog(int nativeJavascriptAppModalDialogAndroid, |
277 | String prompt, boolean suppress); |
278 | |
279 | private native void nativeDidCancelAppModalDialog(int nativeJavascriptAppModalDialogAndroid, |
280 | boolean suppress); |
281 | |
282 | private static native JavascriptAppModalDialog nativeGetCurrentModalDialog(); |
283 | } |