LocalNotification.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /*
  2. * Apache 2.0 License
  3. *
  4. * Copyright (c) Sebastian Katzer 2017
  5. *
  6. * This file contains Original Code and/or Modifications of Original Code
  7. * as defined in and that are subject to the Apache License
  8. * Version 2.0 (the 'License'). You may not use this file except in
  9. * compliance with the License. Please obtain a copy of the License at
  10. * http://opensource.org/licenses/Apache-2.0/ and read it before using this
  11. * file.
  12. *
  13. * The Original Code and all software distributed under the License are
  14. * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15. * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16. * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18. * Please see the License for the specific language governing rights and
  19. * limitations under the License.
  20. */
  21. package de.appplant.cordova.plugin.localnotification;
  22. import android.annotation.SuppressLint;
  23. import android.app.Activity;
  24. import android.util.Pair;
  25. import org.apache.cordova.CallbackContext;
  26. import org.apache.cordova.CordovaInterface;
  27. import org.apache.cordova.CordovaPlugin;
  28. import org.apache.cordova.CordovaWebView;
  29. import org.apache.cordova.PluginResult;
  30. import org.json.JSONArray;
  31. import org.json.JSONException;
  32. import org.json.JSONObject;
  33. import java.util.ArrayList;
  34. import java.util.List;
  35. import de.appplant.cordova.plugin.notification.Manager;
  36. import de.appplant.cordova.plugin.notification.Notification;
  37. import de.appplant.cordova.plugin.notification.Options;
  38. import de.appplant.cordova.plugin.notification.Request;
  39. import de.appplant.cordova.plugin.notification.action.ActionGroup;
  40. import static de.appplant.cordova.plugin.notification.Notification.Type.SCHEDULED;
  41. import static de.appplant.cordova.plugin.notification.Notification.Type.TRIGGERED;
  42. /**
  43. * This plugin utilizes the Android AlarmManager in combination with local
  44. * notifications. When a local notification is scheduled the alarm manager takes
  45. * care of firing the event. When the event is processed, a notification is put
  46. * in the Android notification center and status bar.
  47. */
  48. public class LocalNotification extends CordovaPlugin {
  49. // Reference to the web view for static access
  50. private static CordovaWebView webView = null;
  51. // Indicates if the device is ready (to receive events)
  52. private static Boolean deviceready = false;
  53. // To inform the user about the state of the app in callbacks
  54. private static Boolean isInBackground = true;
  55. // Queues all events before deviceready
  56. private static ArrayList<String> eventQueue = new ArrayList<String>();
  57. // Launch details
  58. private static Pair<Integer, String> launchDetails;
  59. /**
  60. * Called after plugin construction and fields have been initialized.
  61. * Prefer to use pluginInitialize instead since there is no value in
  62. * having parameters on the initialize() function.
  63. */
  64. @Override
  65. public void initialize (CordovaInterface cordova, CordovaWebView webView) {
  66. LocalNotification.webView = super.webView;
  67. }
  68. /**
  69. * Called when the system is about to start resuming a previous activity.
  70. *
  71. * @param multitasking Flag indicating if multitasking is turned on for app.
  72. */
  73. @Override
  74. public void onPause(boolean multitasking) {
  75. super.onPause(multitasking);
  76. isInBackground = true;
  77. }
  78. /**
  79. * Called when the activity will start interacting with the user.
  80. *
  81. * @param multitasking
  82. * Flag indicating if multitasking is turned on for app
  83. */
  84. @Override
  85. public void onResume(boolean multitasking) {
  86. super.onResume(multitasking);
  87. isInBackground = false;
  88. deviceready();
  89. }
  90. /**
  91. * The final call you receive before your activity is destroyed.
  92. */
  93. @Override
  94. public void onDestroy() {
  95. deviceready = false;
  96. isInBackground = true;
  97. }
  98. /**
  99. * Executes the request.
  100. *
  101. * This method is called from the WebView thread. To do a non-trivial
  102. * amount of work, use:
  103. * cordova.getThreadPool().execute(runnable);
  104. *
  105. * To run on the UI thread, use:
  106. * cordova.getActivity().runOnUiThread(runnable);
  107. *
  108. * @param action The action to execute.
  109. * @param args The exec() arguments in JSON form.
  110. * @param command The callback context used when calling back into
  111. * JavaScript.
  112. *
  113. * @return Whether the action was valid.
  114. */
  115. @Override
  116. public boolean execute (final String action, final JSONArray args,
  117. final CallbackContext command) throws JSONException {
  118. if (action.equals("launch")) {
  119. launch(command);
  120. return true;
  121. }
  122. cordova.getThreadPool().execute(new Runnable() {
  123. public void run() {
  124. if (action.equals("ready")) {
  125. deviceready();
  126. } else
  127. if (action.equalsIgnoreCase("check")) {
  128. check(command);
  129. } else
  130. if (action.equalsIgnoreCase("request")) {
  131. request(command);
  132. } else
  133. if (action.equalsIgnoreCase("actions")) {
  134. actions(args.optJSONObject(0));
  135. command.success();
  136. } else
  137. if (action.equalsIgnoreCase("schedule")) {
  138. schedule(args);
  139. command.success();
  140. } else
  141. // if (action.equals("update")) {
  142. // update(args);
  143. // command.success();
  144. // } else
  145. if (action.equals("cancel")) {
  146. cancel(args);
  147. command.success();
  148. } else
  149. if (action.equals("cancelAll")) {
  150. cancelAll();
  151. command.success();
  152. } else
  153. if (action.equals("clear")) {
  154. clear(args);
  155. command.success();
  156. } else
  157. if (action.equals("clearAll")) {
  158. clearAll();
  159. command.success();
  160. } else
  161. if (action.equals("type")) {
  162. type(args.optInt(0), command);
  163. } else
  164. if (action.equals("ids")) {
  165. ids(command);
  166. } else
  167. if (action.equals("scheduledIds")) {
  168. scheduledIds(command);
  169. } else
  170. if (action.equals("triggeredIds")) {
  171. triggeredIds(command);
  172. } else
  173. if (action.equals("notification")) {
  174. notification(args.optInt(0), command);
  175. } else
  176. if (action.equals("notifications")) {
  177. notifications(args, command);
  178. } else
  179. if (action.equals("scheduledNotifications")) {
  180. scheduledNotifications(command);
  181. } else
  182. if (action.equals("triggeredNotifications")) {
  183. triggeredNotifications(command);
  184. }
  185. }
  186. });
  187. return true;
  188. }
  189. /**
  190. * Set launchDetails object.
  191. *
  192. * @param command The callback context used when calling back into
  193. * JavaScript.
  194. */
  195. @SuppressLint("DefaultLocale")
  196. private void launch(CallbackContext command) {
  197. if (launchDetails == null)
  198. return;
  199. JSONObject details = new JSONObject();
  200. try {
  201. details.put("id", launchDetails.first);
  202. details.put("action", launchDetails.second);
  203. } catch (JSONException e) {
  204. e.printStackTrace();
  205. }
  206. command.success(details);
  207. launchDetails = null;
  208. }
  209. /**
  210. * Ask if user has enabled permission for local notifications.
  211. *
  212. * @param command The callback context used when calling back into
  213. * JavaScript.
  214. */
  215. private void check (CallbackContext command) {
  216. boolean allowed = getNotMgr().hasPermission();
  217. PluginResult result = new PluginResult(PluginResult.Status.OK, allowed);
  218. command.sendPluginResult(result);
  219. }
  220. /**
  221. * Request permission for local notifications.
  222. *
  223. * @param command The callback context used when calling back into
  224. * JavaScript.
  225. */
  226. private void request (CallbackContext command) {
  227. check(command);
  228. }
  229. /**
  230. * Register action group.
  231. *
  232. * @param args The action group spec.
  233. */
  234. private void actions (JSONObject args) {
  235. ActionGroup group = ActionGroup.parse(cordova.getActivity(), args);
  236. if (group != null) {
  237. ActionGroup.register(group);
  238. }
  239. }
  240. /**
  241. * Schedule multiple local notifications.
  242. *
  243. * @param notifications The notifications to schedule.
  244. */
  245. private void schedule (JSONArray notifications) {
  246. Manager mgr = getNotMgr();
  247. for (int i = 0; i < notifications.length(); i++) {
  248. JSONObject dict = notifications.optJSONObject(i);
  249. Options options = new Options(dict);
  250. Request request = new Request(options);
  251. Notification notification =
  252. mgr.schedule(request, TriggerReceiver.class);
  253. if (notification != null) {
  254. fireEvent("add", notification);
  255. }
  256. }
  257. }
  258. // /**
  259. // * Update multiple local notifications.
  260. // *
  261. // * @param updates
  262. // * Notification properties including their IDs
  263. // */
  264. // private void update (JSONArray updates) {
  265. // for (int i = 0; i < updates.length(); i++) {
  266. // JSONObject update = updates.optJSONObject(i);
  267. // int id = update.optInt("id", 0);
  268. // Notification notification =
  269. // getNotMgr().update(id, update, TriggerReceiver.class);
  270. // if (notification == null)
  271. // continue;
  272. // fireEvent("update", notification);
  273. // }
  274. // }
  275. /**
  276. * Cancel multiple local notifications.
  277. *
  278. * @param ids Set of local notification IDs
  279. */
  280. private void cancel (JSONArray ids) {
  281. for (int i = 0; i < ids.length(); i++) {
  282. int id = ids.optInt(i, 0);
  283. Notification notification =
  284. getNotMgr().cancel(id);
  285. if (notification == null)
  286. continue;
  287. fireEvent("cancel", notification);
  288. }
  289. }
  290. /**
  291. * Cancel all scheduled notifications.
  292. */
  293. private void cancelAll() {
  294. getNotMgr().cancelAll();
  295. fireEvent("cancelall");
  296. }
  297. /**
  298. * Clear multiple local notifications without canceling them.
  299. *
  300. * @param ids Set of local notification IDs
  301. */
  302. private void clear(JSONArray ids){
  303. for (int i = 0; i < ids.length(); i++) {
  304. int id = ids.optInt(i, 0);
  305. Notification notification =
  306. getNotMgr().clear(id);
  307. if (notification == null)
  308. continue;
  309. fireEvent("clear", notification);
  310. }
  311. }
  312. /**
  313. * Clear all triggered notifications without canceling them.
  314. */
  315. private void clearAll() {
  316. getNotMgr().clearAll();
  317. fireEvent("clearall");
  318. }
  319. /**
  320. * Get the type of the notification (unknown, scheduled, triggered).
  321. *
  322. * @param id The ID of the notification to check.
  323. * @param command The callback context used when calling back into
  324. * JavaScript.
  325. */
  326. private void type (int id, CallbackContext command) {
  327. Notification toast = getNotMgr().get(id);
  328. if (toast == null) {
  329. command.success("unknown");
  330. return;
  331. }
  332. switch (toast.getType()) {
  333. case SCHEDULED:
  334. command.success("scheduled");
  335. break;
  336. case TRIGGERED:
  337. command.success("triggered");
  338. break;
  339. default:
  340. command.success("unknown");
  341. break;
  342. }
  343. }
  344. /**
  345. * Set of IDs from all existent notifications.
  346. *
  347. * @param command The callback context used when calling back into
  348. * JavaScript.
  349. */
  350. private void ids (CallbackContext command) {
  351. List<Integer> ids = getNotMgr().getIds();
  352. command.success(new JSONArray(ids));
  353. }
  354. /**
  355. * Set of IDs from all scheduled notifications.
  356. *
  357. * @param command The callback context used when calling back into
  358. * JavaScript.
  359. */
  360. private void scheduledIds (CallbackContext command) {
  361. List<Integer> ids = getNotMgr().getIdsByType(SCHEDULED);
  362. command.success(new JSONArray(ids));
  363. }
  364. /**
  365. * Set of IDs from all triggered notifications.
  366. *
  367. * @param command The callback context used when calling back into
  368. * JavaScript.
  369. */
  370. private void triggeredIds (CallbackContext command) {
  371. List<Integer> ids = getNotMgr().getIdsByType(TRIGGERED);
  372. command.success(new JSONArray(ids));
  373. }
  374. /**
  375. * Options from local notification.
  376. *
  377. * @param id The ID of the notification.
  378. * @param command The callback context used when calling back into
  379. * JavaScript.
  380. */
  381. private void notification (int id, CallbackContext command) {
  382. Options options = getNotMgr().getOptions(id);
  383. if (options != null) {
  384. command.success(options.getDict());
  385. } else {
  386. command.success();
  387. }
  388. }
  389. /**
  390. * Set of options from local notification.
  391. *
  392. * @param ids Set of local notification IDs.
  393. * @param command The callback context used when calling back into
  394. * JavaScript.
  395. */
  396. private void notifications (JSONArray ids, CallbackContext command) {
  397. List<JSONObject> options;
  398. if (ids.length() == 0) {
  399. options = getNotMgr().getOptions();
  400. } else {
  401. options = getNotMgr().getOptionsById(toList(ids));
  402. }
  403. command.success(new JSONArray(options));
  404. }
  405. /**
  406. * Set of options from scheduled notifications.
  407. *
  408. * @param command The callback context used when calling back into
  409. * JavaScript.
  410. */
  411. private void scheduledNotifications (CallbackContext command) {
  412. List<JSONObject> options = getNotMgr().getOptionsByType(SCHEDULED);
  413. command.success(new JSONArray(options));
  414. }
  415. /**
  416. * Set of options from triggered notifications.
  417. *
  418. * @param command The callback context used when calling back into
  419. * JavaScript.
  420. */
  421. private void triggeredNotifications (CallbackContext command) {
  422. List<JSONObject> options = getNotMgr().getOptionsByType(TRIGGERED);
  423. command.success(new JSONArray(options));
  424. }
  425. /**
  426. * Call all pending callbacks after the deviceready event has been fired.
  427. */
  428. private static synchronized void deviceready () {
  429. isInBackground = false;
  430. deviceready = true;
  431. for (String js : eventQueue) {
  432. sendJavascript(js);
  433. }
  434. eventQueue.clear();
  435. }
  436. /**
  437. * Fire given event on JS side. Does inform all event listeners.
  438. *
  439. * @param event The event name.
  440. */
  441. private void fireEvent (String event) {
  442. fireEvent(event, null, new JSONObject());
  443. }
  444. /**
  445. * Fire given event on JS side. Does inform all event listeners.
  446. *
  447. * @param event The event name.
  448. * @param notification Optional notification to pass with.
  449. */
  450. static void fireEvent (String event, Notification notification) {
  451. fireEvent(event, notification, new JSONObject());
  452. }
  453. /**
  454. * Fire given event on JS side. Does inform all event listeners.
  455. *
  456. * @param event The event name.
  457. * @param toast Optional notification to pass with.
  458. * @param data Event object with additional data.
  459. */
  460. static void fireEvent (String event, Notification toast, JSONObject data) {
  461. String params, js;
  462. try {
  463. data.put("event", event);
  464. data.put("foreground", !isInBackground);
  465. data.put("queued", !deviceready);
  466. if (toast != null) {
  467. data.put("notification", toast.getId());
  468. }
  469. } catch (JSONException e) {
  470. e.printStackTrace();
  471. }
  472. if (toast != null) {
  473. params = toast.toString() + "," + data.toString();
  474. } else {
  475. params = data.toString();
  476. }
  477. js = "cordova.plugins.notification.local.core.fireEvent(" +
  478. "\"" + event + "\"," + params + ")";
  479. if (launchDetails == null && !deviceready && toast != null) {
  480. launchDetails = new Pair<Integer, String>(toast.getId(), event);
  481. }
  482. sendJavascript(js);
  483. }
  484. /**
  485. * Use this instead of deprecated sendJavascript
  486. *
  487. * @param js JS code snippet as string.
  488. */
  489. private static synchronized void sendJavascript(final String js) {
  490. if (!deviceready) {
  491. eventQueue.add(js);
  492. return;
  493. }
  494. ((Activity)(webView.getContext())).runOnUiThread(new Runnable() {
  495. public void run() {
  496. webView.loadUrl("javascript:" + js);
  497. }
  498. });
  499. }
  500. /**
  501. * Convert JSON array of integers to List.
  502. *
  503. * @param ary Array of integers.
  504. */
  505. private List<Integer> toList (JSONArray ary) {
  506. List<Integer> list = new ArrayList<Integer>();
  507. for (int i = 0; i < ary.length(); i++) {
  508. list.add(ary.optInt(i));
  509. }
  510. return list;
  511. }
  512. /**
  513. * Notification manager instance.
  514. */
  515. private Manager getNotMgr() {
  516. return Manager.getInstance(cordova.getActivity());
  517. }
  518. }