|
1 /* |
|
2 Licensed to the Apache Software Foundation (ASF) under one |
|
3 or more contributor license agreements. See the NOTICE file |
|
4 distributed with this work for additional information |
|
5 regarding copyright ownership. The ASF licenses this file |
|
6 to you under the Apache License, Version 2.0 (the |
|
7 "License"); you may not use this file except in compliance |
|
8 with the License. You may obtain a copy of the License at |
|
9 |
|
10 http://www.apache.org/licenses/LICENSE-2.0 |
|
11 |
|
12 Unless required by applicable law or agreed to in writing, |
|
13 software distributed under the License is distributed on an |
|
14 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
|
15 KIND, either express or implied. See the License for the |
|
16 specific language governing permissions and limitations |
|
17 under the License. |
|
18 */ |
|
19 package org.apache.cordova.dialogs; |
|
20 |
|
21 import org.apache.cordova.CallbackContext; |
|
22 import org.apache.cordova.CordovaInterface; |
|
23 import org.apache.cordova.CordovaPlugin; |
|
24 import org.apache.cordova.PluginResult; |
|
25 import org.json.JSONArray; |
|
26 import org.json.JSONException; |
|
27 import org.json.JSONObject; |
|
28 |
|
29 import android.annotation.SuppressLint; |
|
30 import android.app.AlertDialog; |
|
31 import android.app.AlertDialog.Builder; |
|
32 import android.app.ProgressDialog; |
|
33 import android.content.DialogInterface; |
|
34 import android.media.Ringtone; |
|
35 import android.media.RingtoneManager; |
|
36 import android.net.Uri; |
|
37 import android.widget.EditText; |
|
38 import android.widget.TextView; |
|
39 |
|
40 |
|
41 /** |
|
42 * This class provides access to notifications on the device. |
|
43 * |
|
44 * Be aware that this implementation gets called on |
|
45 * navigator.notification.{alert|confirm|prompt}, and that there is a separate |
|
46 * implementation in org.apache.cordova.CordovaChromeClient that gets |
|
47 * called on a simple window.{alert|confirm|prompt}. |
|
48 */ |
|
49 public class Notification extends CordovaPlugin { |
|
50 |
|
51 public int confirmResult = -1; |
|
52 public ProgressDialog spinnerDialog = null; |
|
53 public ProgressDialog progressDialog = null; |
|
54 |
|
55 /** |
|
56 * Constructor. |
|
57 */ |
|
58 public Notification() { |
|
59 } |
|
60 |
|
61 /** |
|
62 * Executes the request and returns PluginResult. |
|
63 * |
|
64 * @param action The action to execute. |
|
65 * @param args JSONArray of arguments for the plugin. |
|
66 * @param callbackContext The callback context used when calling back into JavaScript. |
|
67 * @return True when the action was valid, false otherwise. |
|
68 */ |
|
69 public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { |
|
70 /* |
|
71 * Don't run any of these if the current activity is finishing |
|
72 * in order to avoid android.view.WindowManager$BadTokenException |
|
73 * crashing the app. Just return true here since false should only |
|
74 * be returned in the event of an invalid action. |
|
75 */ |
|
76 if(this.cordova.getActivity().isFinishing()) return true; |
|
77 |
|
78 if (action.equals("beep")) { |
|
79 this.beep(args.getLong(0)); |
|
80 } |
|
81 else if (action.equals("alert")) { |
|
82 this.alert(args.getString(0), args.getString(1), args.getString(2), callbackContext); |
|
83 return true; |
|
84 } |
|
85 else if (action.equals("confirm")) { |
|
86 this.confirm(args.getString(0), args.getString(1), args.getJSONArray(2), callbackContext); |
|
87 return true; |
|
88 } |
|
89 else if (action.equals("prompt")) { |
|
90 this.prompt(args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), callbackContext); |
|
91 return true; |
|
92 } |
|
93 else if (action.equals("activityStart")) { |
|
94 this.activityStart(args.getString(0), args.getString(1)); |
|
95 } |
|
96 else if (action.equals("activityStop")) { |
|
97 this.activityStop(); |
|
98 } |
|
99 else if (action.equals("progressStart")) { |
|
100 this.progressStart(args.getString(0), args.getString(1)); |
|
101 } |
|
102 else if (action.equals("progressValue")) { |
|
103 this.progressValue(args.getInt(0)); |
|
104 } |
|
105 else if (action.equals("progressStop")) { |
|
106 this.progressStop(); |
|
107 } |
|
108 else { |
|
109 return false; |
|
110 } |
|
111 |
|
112 // Only alert and confirm are async. |
|
113 callbackContext.success(); |
|
114 return true; |
|
115 } |
|
116 |
|
117 //-------------------------------------------------------------------------- |
|
118 // LOCAL METHODS |
|
119 //-------------------------------------------------------------------------- |
|
120 |
|
121 /** |
|
122 * Beep plays the default notification ringtone. |
|
123 * |
|
124 * @param count Number of times to play notification |
|
125 */ |
|
126 public void beep(final long count) { |
|
127 cordova.getThreadPool().execute(new Runnable() { |
|
128 public void run() { |
|
129 Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); |
|
130 Ringtone notification = RingtoneManager.getRingtone(cordova.getActivity().getBaseContext(), ringtone); |
|
131 |
|
132 // If phone is not set to silent mode |
|
133 if (notification != null) { |
|
134 for (long i = 0; i < count; ++i) { |
|
135 notification.play(); |
|
136 long timeout = 5000; |
|
137 while (notification.isPlaying() && (timeout > 0)) { |
|
138 timeout = timeout - 100; |
|
139 try { |
|
140 Thread.sleep(100); |
|
141 } catch (InterruptedException e) { |
|
142 } |
|
143 } |
|
144 } |
|
145 } |
|
146 } |
|
147 }); |
|
148 } |
|
149 |
|
150 /** |
|
151 * Builds and shows a native Android alert with given Strings |
|
152 * @param message The message the alert should display |
|
153 * @param title The title of the alert |
|
154 * @param buttonLabel The label of the button |
|
155 * @param callbackContext The callback context |
|
156 */ |
|
157 public synchronized void alert(final String message, final String title, final String buttonLabel, final CallbackContext callbackContext) { |
|
158 final CordovaInterface cordova = this.cordova; |
|
159 |
|
160 Runnable runnable = new Runnable() { |
|
161 public void run() { |
|
162 |
|
163 AlertDialog.Builder dlg = createDialog(cordova); // new AlertDialog.Builder(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); |
|
164 dlg.setMessage(message); |
|
165 dlg.setTitle(title); |
|
166 dlg.setCancelable(true); |
|
167 dlg.setPositiveButton(buttonLabel, |
|
168 new AlertDialog.OnClickListener() { |
|
169 public void onClick(DialogInterface dialog, int which) { |
|
170 dialog.dismiss(); |
|
171 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0)); |
|
172 } |
|
173 }); |
|
174 dlg.setOnCancelListener(new AlertDialog.OnCancelListener() { |
|
175 public void onCancel(DialogInterface dialog) |
|
176 { |
|
177 dialog.dismiss(); |
|
178 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0)); |
|
179 } |
|
180 }); |
|
181 |
|
182 changeTextDirection(dlg); |
|
183 }; |
|
184 }; |
|
185 this.cordova.getActivity().runOnUiThread(runnable); |
|
186 } |
|
187 |
|
188 /** |
|
189 * Builds and shows a native Android confirm dialog with given title, message, buttons. |
|
190 * This dialog only shows up to 3 buttons. Any labels after that will be ignored. |
|
191 * The index of the button pressed will be returned to the JavaScript callback identified by callbackId. |
|
192 * |
|
193 * @param message The message the dialog should display |
|
194 * @param title The title of the dialog |
|
195 * @param buttonLabels A comma separated list of button labels (Up to 3 buttons) |
|
196 * @param callbackContext The callback context. |
|
197 */ |
|
198 public synchronized void confirm(final String message, final String title, final JSONArray buttonLabels, final CallbackContext callbackContext) { |
|
199 final CordovaInterface cordova = this.cordova; |
|
200 |
|
201 Runnable runnable = new Runnable() { |
|
202 public void run() { |
|
203 AlertDialog.Builder dlg = createDialog(cordova); // new AlertDialog.Builder(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); |
|
204 dlg.setMessage(message); |
|
205 dlg.setTitle(title); |
|
206 dlg.setCancelable(true); |
|
207 |
|
208 // First button |
|
209 if (buttonLabels.length() > 0) { |
|
210 try { |
|
211 dlg.setNegativeButton(buttonLabels.getString(0), |
|
212 new AlertDialog.OnClickListener() { |
|
213 public void onClick(DialogInterface dialog, int which) { |
|
214 dialog.dismiss(); |
|
215 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 1)); |
|
216 } |
|
217 }); |
|
218 } catch (JSONException e) { } |
|
219 } |
|
220 |
|
221 // Second button |
|
222 if (buttonLabels.length() > 1) { |
|
223 try { |
|
224 dlg.setNeutralButton(buttonLabels.getString(1), |
|
225 new AlertDialog.OnClickListener() { |
|
226 public void onClick(DialogInterface dialog, int which) { |
|
227 dialog.dismiss(); |
|
228 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 2)); |
|
229 } |
|
230 }); |
|
231 } catch (JSONException e) { } |
|
232 } |
|
233 |
|
234 // Third button |
|
235 if (buttonLabels.length() > 2) { |
|
236 try { |
|
237 dlg.setPositiveButton(buttonLabels.getString(2), |
|
238 new AlertDialog.OnClickListener() { |
|
239 public void onClick(DialogInterface dialog, int which) { |
|
240 dialog.dismiss(); |
|
241 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 3)); |
|
242 } |
|
243 }); |
|
244 } catch (JSONException e) { } |
|
245 } |
|
246 dlg.setOnCancelListener(new AlertDialog.OnCancelListener() { |
|
247 public void onCancel(DialogInterface dialog) |
|
248 { |
|
249 dialog.dismiss(); |
|
250 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0)); |
|
251 } |
|
252 }); |
|
253 |
|
254 changeTextDirection(dlg); |
|
255 }; |
|
256 }; |
|
257 this.cordova.getActivity().runOnUiThread(runnable); |
|
258 } |
|
259 |
|
260 /** |
|
261 * Builds and shows a native Android prompt dialog with given title, message, buttons. |
|
262 * This dialog only shows up to 3 buttons. Any labels after that will be ignored. |
|
263 * The following results are returned to the JavaScript callback identified by callbackId: |
|
264 * buttonIndex Index number of the button selected |
|
265 * input1 The text entered in the prompt dialog box |
|
266 * |
|
267 * @param message The message the dialog should display |
|
268 * @param title The title of the dialog |
|
269 * @param buttonLabels A comma separated list of button labels (Up to 3 buttons) |
|
270 * @param callbackContext The callback context. |
|
271 */ |
|
272 public synchronized void prompt(final String message, final String title, final JSONArray buttonLabels, final String defaultText, final CallbackContext callbackContext) { |
|
273 |
|
274 final CordovaInterface cordova = this.cordova; |
|
275 |
|
276 Runnable runnable = new Runnable() { |
|
277 public void run() { |
|
278 final EditText promptInput = new EditText(cordova.getActivity()); |
|
279 promptInput.setHint(defaultText); |
|
280 AlertDialog.Builder dlg = createDialog(cordova); // new AlertDialog.Builder(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); |
|
281 dlg.setMessage(message); |
|
282 dlg.setTitle(title); |
|
283 dlg.setCancelable(true); |
|
284 |
|
285 dlg.setView(promptInput); |
|
286 |
|
287 final JSONObject result = new JSONObject(); |
|
288 |
|
289 // First button |
|
290 if (buttonLabels.length() > 0) { |
|
291 try { |
|
292 dlg.setNegativeButton(buttonLabels.getString(0), |
|
293 new AlertDialog.OnClickListener() { |
|
294 public void onClick(DialogInterface dialog, int which) { |
|
295 dialog.dismiss(); |
|
296 try { |
|
297 result.put("buttonIndex",1); |
|
298 result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText()); |
|
299 } catch (JSONException e) { e.printStackTrace(); } |
|
300 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result)); |
|
301 } |
|
302 }); |
|
303 } catch (JSONException e) { } |
|
304 } |
|
305 |
|
306 // Second button |
|
307 if (buttonLabels.length() > 1) { |
|
308 try { |
|
309 dlg.setNeutralButton(buttonLabels.getString(1), |
|
310 new AlertDialog.OnClickListener() { |
|
311 public void onClick(DialogInterface dialog, int which) { |
|
312 dialog.dismiss(); |
|
313 try { |
|
314 result.put("buttonIndex",2); |
|
315 result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText()); |
|
316 } catch (JSONException e) { e.printStackTrace(); } |
|
317 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result)); |
|
318 } |
|
319 }); |
|
320 } catch (JSONException e) { } |
|
321 } |
|
322 |
|
323 // Third button |
|
324 if (buttonLabels.length() > 2) { |
|
325 try { |
|
326 dlg.setPositiveButton(buttonLabels.getString(2), |
|
327 new AlertDialog.OnClickListener() { |
|
328 public void onClick(DialogInterface dialog, int which) { |
|
329 dialog.dismiss(); |
|
330 try { |
|
331 result.put("buttonIndex",3); |
|
332 result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText()); |
|
333 } catch (JSONException e) { e.printStackTrace(); } |
|
334 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result)); |
|
335 } |
|
336 }); |
|
337 } catch (JSONException e) { } |
|
338 } |
|
339 dlg.setOnCancelListener(new AlertDialog.OnCancelListener() { |
|
340 public void onCancel(DialogInterface dialog){ |
|
341 dialog.dismiss(); |
|
342 try { |
|
343 result.put("buttonIndex",0); |
|
344 result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText()); |
|
345 } catch (JSONException e) { e.printStackTrace(); } |
|
346 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result)); |
|
347 } |
|
348 }); |
|
349 |
|
350 changeTextDirection(dlg); |
|
351 }; |
|
352 }; |
|
353 this.cordova.getActivity().runOnUiThread(runnable); |
|
354 } |
|
355 |
|
356 /** |
|
357 * Show the spinner. |
|
358 * |
|
359 * @param title Title of the dialog |
|
360 * @param message The message of the dialog |
|
361 */ |
|
362 public synchronized void activityStart(final String title, final String message) { |
|
363 if (this.spinnerDialog != null) { |
|
364 this.spinnerDialog.dismiss(); |
|
365 this.spinnerDialog = null; |
|
366 } |
|
367 final Notification notification = this; |
|
368 final CordovaInterface cordova = this.cordova; |
|
369 Runnable runnable = new Runnable() { |
|
370 public void run() { |
|
371 notification.spinnerDialog = createProgressDialog(cordova); // new ProgressDialog(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); |
|
372 notification.spinnerDialog.setTitle(title); |
|
373 notification.spinnerDialog.setMessage(message); |
|
374 notification.spinnerDialog.setCancelable(true); |
|
375 notification.spinnerDialog.setIndeterminate(true); |
|
376 notification.spinnerDialog.setOnCancelListener( |
|
377 new DialogInterface.OnCancelListener() { |
|
378 public void onCancel(DialogInterface dialog) { |
|
379 notification.spinnerDialog = null; |
|
380 } |
|
381 }); |
|
382 notification.spinnerDialog.show(); |
|
383 } |
|
384 }; |
|
385 this.cordova.getActivity().runOnUiThread(runnable); |
|
386 } |
|
387 |
|
388 /** |
|
389 * Stop spinner. |
|
390 */ |
|
391 public synchronized void activityStop() { |
|
392 if (this.spinnerDialog != null) { |
|
393 this.spinnerDialog.dismiss(); |
|
394 this.spinnerDialog = null; |
|
395 } |
|
396 } |
|
397 |
|
398 /** |
|
399 * Show the progress dialog. |
|
400 * |
|
401 * @param title Title of the dialog |
|
402 * @param message The message of the dialog |
|
403 */ |
|
404 public synchronized void progressStart(final String title, final String message) { |
|
405 if (this.progressDialog != null) { |
|
406 this.progressDialog.dismiss(); |
|
407 this.progressDialog = null; |
|
408 } |
|
409 final Notification notification = this; |
|
410 final CordovaInterface cordova = this.cordova; |
|
411 Runnable runnable = new Runnable() { |
|
412 public void run() { |
|
413 notification.progressDialog = createProgressDialog(cordova); // new ProgressDialog(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); |
|
414 notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); |
|
415 notification.progressDialog.setTitle(title); |
|
416 notification.progressDialog.setMessage(message); |
|
417 notification.progressDialog.setCancelable(true); |
|
418 notification.progressDialog.setMax(100); |
|
419 notification.progressDialog.setProgress(0); |
|
420 notification.progressDialog.setOnCancelListener( |
|
421 new DialogInterface.OnCancelListener() { |
|
422 public void onCancel(DialogInterface dialog) { |
|
423 notification.progressDialog = null; |
|
424 } |
|
425 }); |
|
426 notification.progressDialog.show(); |
|
427 } |
|
428 }; |
|
429 this.cordova.getActivity().runOnUiThread(runnable); |
|
430 } |
|
431 |
|
432 /** |
|
433 * Set value of progress bar. |
|
434 * |
|
435 * @param value 0-100 |
|
436 */ |
|
437 public synchronized void progressValue(int value) { |
|
438 if (this.progressDialog != null) { |
|
439 this.progressDialog.setProgress(value); |
|
440 } |
|
441 } |
|
442 |
|
443 /** |
|
444 * Stop progress dialog. |
|
445 */ |
|
446 public synchronized void progressStop() { |
|
447 if (this.progressDialog != null) { |
|
448 this.progressDialog.dismiss(); |
|
449 this.progressDialog = null; |
|
450 } |
|
451 } |
|
452 |
|
453 @SuppressLint("NewApi") |
|
454 private AlertDialog.Builder createDialog(CordovaInterface cordova) { |
|
455 int currentapiVersion = android.os.Build.VERSION.SDK_INT; |
|
456 if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { |
|
457 return new AlertDialog.Builder(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); |
|
458 } else { |
|
459 return new AlertDialog.Builder(cordova.getActivity()); |
|
460 } |
|
461 } |
|
462 |
|
463 @SuppressLint("InlinedApi") |
|
464 private ProgressDialog createProgressDialog(CordovaInterface cordova) { |
|
465 int currentapiVersion = android.os.Build.VERSION.SDK_INT; |
|
466 if (currentapiVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { |
|
467 return new ProgressDialog(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); |
|
468 } else { |
|
469 return new ProgressDialog(cordova.getActivity()); |
|
470 } |
|
471 } |
|
472 |
|
473 @SuppressLint("NewApi") |
|
474 private void changeTextDirection(Builder dlg){ |
|
475 int currentapiVersion = android.os.Build.VERSION.SDK_INT; |
|
476 dlg.create(); |
|
477 AlertDialog dialog = dlg.show(); |
|
478 if (currentapiVersion >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { |
|
479 TextView messageview = (TextView)dialog.findViewById(android.R.id.message); |
|
480 messageview.setTextDirection(android.view.View.TEXT_DIRECTION_LOCALE); |
|
481 } |
|
482 } |
|
483 } |