local-notification.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /*
  2. Copyright 2013-2014 appPlant UG
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing,
  12. software distributed under the License is distributed on an
  13. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. KIND, either express or implied. See the License for the
  15. specific language governing permissions and limitations
  16. under the License.
  17. */
  18. var exec = require('cordova/exec'),
  19. channel = require('cordova/channel');
  20. // Called after 'deviceready' event
  21. channel.deviceready.subscribe( function () {
  22. // Device is ready now, the listeners are registered
  23. // and all queued events can be executed.
  24. exec(null, null, 'LocalNotification', 'deviceready', []);
  25. });
  26. // Called before 'deviceready' event
  27. channel.onCordovaReady.subscribe( function () {
  28. // The cordova device plugin is ready now
  29. channel.onCordovaInfoReady.subscribe( function () {
  30. if (device.platform == 'Android') {
  31. channel.onPause.subscribe( function () {
  32. // Necessary to set the state to `background`
  33. exec(null, null, 'LocalNotification', 'pause', []);
  34. });
  35. channel.onResume.subscribe( function () {
  36. // Necessary to set the state to `foreground`
  37. exec(null, null, 'LocalNotification', 'resume', []);
  38. });
  39. // Necessary to set the state to `foreground`
  40. exec(null, null, 'LocalNotification', 'resume', []);
  41. }
  42. // Merges the platform specific properties into the default properties
  43. exports.applyPlatformSpecificOptions();
  44. });
  45. });
  46. /**
  47. * @private
  48. *
  49. * Default values.
  50. */
  51. exports._defaults = {
  52. message: '',
  53. title: '',
  54. autoCancel: false,
  55. badge: -1,
  56. id: '0',
  57. json: '',
  58. repeat: ''
  59. };
  60. /**
  61. * Returns the default settings
  62. *
  63. * @return {Object}
  64. */
  65. exports.getDefaults = function () {
  66. return this._defaults;
  67. };
  68. /**
  69. * Overwrite default settings
  70. *
  71. * @param {Object} defaults
  72. */
  73. exports.setDefaults = function (newDefaults) {
  74. var defaults = this.getDefaults();
  75. for (var key in defaults) {
  76. if (newDefaults[key] !== undefined) {
  77. defaults[key] = newDefaults[key];
  78. }
  79. }
  80. };
  81. /**
  82. * Add a new entry to the registry
  83. *
  84. * @param {Object} props
  85. * The notification properties
  86. * @param {Function} callback
  87. * A function to be called after the notification has been canceled
  88. * @param {Object} scope
  89. * The scope for the callback function
  90. */
  91. exports.add = function (props, callback, scope) {
  92. this.registerPermission(function(granted) {
  93. if (!granted)
  94. return;
  95. var notifications = Array.isArray(props) ? props : [props];
  96. for (var i = 0; i < notifications.length; i++) {
  97. var properties = notifications[i];
  98. this.mergeWithDefaults(properties);
  99. this.convertProperties(properties);
  100. }
  101. if (device.platform != 'iOS') {
  102. notifications = notifications[0];
  103. }
  104. this.exec('add', notifications, callback, scope);
  105. }, this);
  106. };
  107. /**
  108. * Update existing notification specified by ID in options.
  109. *
  110. * @param {Object} options
  111. * The notification properties to update
  112. * @param {Function} callback
  113. * A function to be called after the notification has been updated
  114. * @param {Object} scope
  115. * The scope for the callback function
  116. */
  117. exports.update = function (options, callback, scope) {
  118. this.exec('update', options, callback, scope);
  119. };
  120. /**
  121. * Clears the specified notification.
  122. *
  123. * @param {String} id
  124. * The ID of the notification
  125. * @param {Function} callback
  126. * A function to be called after the notification has been cleared
  127. * @param {Object} scope
  128. * The scope for the callback function
  129. */
  130. exports.clear = function (id, callback, scope) {
  131. var notId = (id || '0').toString();
  132. this.exec('clear', notId, callback, scope);
  133. };
  134. /**
  135. * Clears all previously sheduled notifications.
  136. *
  137. * @param {Function} callback
  138. * A function to be called after all notifications have been cleared
  139. * @param {Object} scope
  140. * The scope for the callback function
  141. */
  142. exports.clearAll = function (callback, scope) {
  143. this.exec('clearAll', null, callback, scope);
  144. };
  145. /**
  146. * Cancels the specified notifications.
  147. *
  148. * @param {String[]} ids
  149. * The IDs of the notifications
  150. * @param {Function} callback
  151. * A function to be called after the notifications has been canceled
  152. * @param {Object} scope
  153. * The scope for the callback function
  154. */
  155. exports.cancel = function (ids, callback, scope) {
  156. ids = Array.isArray(ids) ? ids : [ids];
  157. for (var i = 0; i < ids.length; i++) {
  158. ids[i] = ids[i].toString();
  159. }
  160. if (device.platform != 'iOS') {
  161. ids = ids[0];
  162. }
  163. this.exec('cancel', ids, callback, scope);
  164. };
  165. /**
  166. * Removes all previously registered notifications.
  167. *
  168. * @param {Function} callback
  169. * A function to be called after all notifications have been canceled
  170. * @param {Object} scope
  171. * The scope for the callback function
  172. */
  173. exports.cancelAll = function (callback, scope) {
  174. this.exec('cancelAll', null, callback, scope);
  175. };
  176. /**
  177. * Retrieves a list with all currently pending notifications.
  178. *
  179. * @param {Function} callback
  180. * A callback function to be called with the list
  181. * @param {Object} scope
  182. * The scope for the callback function
  183. */
  184. exports.getScheduledIds = function (callback, scope) {
  185. this.exec('getScheduledIds', null, callback, scope);
  186. };
  187. /**
  188. * Checks wether a notification with an ID is scheduled.
  189. *
  190. * @param {String} id
  191. * The ID of the notification
  192. * @param {Function} callback
  193. * A callback function to be called with the list
  194. * @param {Object} scope
  195. * The scope for the callback function
  196. */
  197. exports.isScheduled = function (id, callback, scope) {
  198. var notId = (id || '0').toString();
  199. this.exec('isScheduled', notId, callback, scope);
  200. };
  201. /**
  202. * Retrieves a list with all triggered notifications.
  203. *
  204. * @param {Function} callback
  205. * A callback function to be called with the list
  206. * @param {Object} scope
  207. * The scope for the callback function
  208. */
  209. exports.getTriggeredIds = function (callback, scope) {
  210. this.exec('getTriggeredIds', null, callback, scope);
  211. };
  212. /**
  213. * Checks wether a notification with an ID was triggered.
  214. *
  215. * @param {String} id
  216. * The ID of the notification
  217. * @param {Function} callback
  218. * A callback function to be called with the list
  219. * @param {Object} scope
  220. * The scope for the callback function
  221. */
  222. exports.isTriggered = function (id, callback, scope) {
  223. var notId = (id || '0').toString();
  224. this.exec('isTriggered', notId, callback, scope);
  225. };
  226. /**
  227. * Informs if the app has the permission to show notifications.
  228. *
  229. * @param {Function} callback
  230. * The function to be exec as the callback
  231. * @param {Object?} scope
  232. * The callback function's scope
  233. */
  234. exports.hasPermission = function (callback, scope) {
  235. var fn = this.createCallbackFn(callback, scope);
  236. if (device.platform != 'iOS') {
  237. fn(true);
  238. return;
  239. }
  240. exec(fn, null, 'LocalNotification', 'hasPermission', []);
  241. };
  242. /**
  243. * Register permission to show notifications if not already granted.
  244. *
  245. * @param {Function} callback
  246. * The function to be exec as the callback
  247. * @param {Object?} scope
  248. * The callback function's scope
  249. */
  250. exports.registerPermission = function (callback, scope) {
  251. var fn = this.createCallbackFn(callback, scope);
  252. if (device.platform != 'iOS') {
  253. fn(true);
  254. return;
  255. }
  256. exec(fn, null, 'LocalNotification', 'registerPermission', []);
  257. };
  258. /**
  259. * @deprecated
  260. *
  261. * Register permission to show notifications if not already granted.
  262. *
  263. * @param {Function} callback
  264. * The function to be exec as the callback
  265. * @param {Object?} scope
  266. * The callback function's scope
  267. */
  268. exports.promptForPermission = function (callback, scope) {
  269. console.warn('Depreated: Please use `notification.local.registerPermission` instead.');
  270. exports.registerPermission.apply(this, arguments);
  271. };
  272. /**
  273. * Add new entries to the registry (more than one)
  274. *
  275. * @param {Object} options
  276. * The notification properties
  277. * @param {Function} callback
  278. * A function to be called after the notification has been added
  279. * @param {Object} scope
  280. * The scope for the callback function
  281. *
  282. * @return {Number}
  283. * The notification's ID
  284. */
  285. exports.addMultiple = function (notifications, callback, scope) {
  286. var length = notifications.length;
  287. var notificationsMerged = new Array(),
  288. callbackFn = this.createCallbackFn(callback, scope);
  289. for (var i=0;i<length;i++){
  290. var options = this.mergeWithDefaults(notifications[i]);
  291. if (options.id) {
  292. options.id = options.id.toString();
  293. }
  294. if (options.date === undefined) {
  295. options.date = new Date();
  296. }
  297. if (options.title) {
  298. options.title = options.title.toString();
  299. }
  300. if (options.message) {
  301. options.message = options.message.toString();
  302. }
  303. if (typeof options.date == 'object') {
  304. options.date = Math.round(options.date.getTime()/1000);
  305. }
  306. if (['WinCE', 'Win32NT'].indexOf(device.platform) > -1) {
  307. callbackFn = function (cmd) {
  308. eval(cmd);
  309. };
  310. }
  311. notificationsMerged.push(options);
  312. }
  313. cordova.exec(callbackFn, null, 'LocalNotification', 'addMultiple', notificationsMerged);
  314. return options.id;
  315. };
  316. /**
  317. * Clear the specified notifications (more than one).
  318. *
  319. * @param {String} id
  320. * The ID of the notification
  321. * @param {Function} callback
  322. * A function to be called after the notifications has been cleared.
  323. * @param {Object} scope
  324. * The scope for the callback function
  325. */
  326. exports.clearMultiple = function (ids, callback, scope) {
  327. var length = ids.length;
  328. var idArray = new Array(),
  329. callbackFn = this.createCallbackFn(callback, scope);
  330. for (var i=0;i<length;i++){
  331. var id = ids[i].toString();
  332. idArray.push(id);
  333. }
  334. var callbackFn = this.createCallbackFn(callback, scope);
  335. cordova.exec(callbackFn, null, 'LocalNotification', 'clearMultiple', [ids]);
  336. };
  337. /**
  338. * Cancel the specified notifications (more than one).
  339. *
  340. * @param {String} id
  341. * The ID of the notification
  342. * @param {Function} callback
  343. * A function to be called after the notifications has been canceled
  344. * @param {Object} scope
  345. * The scope for the callback function
  346. */
  347. exports.cancelMultiple = function (ids, callback, scope) {
  348. var length = ids.length;
  349. var idArray = new Array(),
  350. callbackFn = this.createCallbackFn(callback, scope);
  351. for (var i=0;i<length;i++){
  352. var id = ids[i].toString();
  353. idArray.push(id);
  354. }
  355. var callbackFn = this.createCallbackFn(callback, scope);
  356. cordova.exec(callbackFn, null, 'LocalNotification', 'cancelMultiple', [ids]);
  357. };
  358. /**
  359. * Occurs when a notification was added.
  360. *
  361. * @param {String} id
  362. * The ID of the notification
  363. * @param {String} state
  364. * Either "foreground" or "background"
  365. * @param {String} json
  366. * A custom (JSON) string
  367. * @param {Object} data
  368. * The notification properties
  369. */
  370. exports.onadd = function (id, state, json, data) {};
  371. /**
  372. * Occurs when the notification is triggered.
  373. *
  374. * @param {String} id
  375. * The ID of the notification
  376. * @param {String} state
  377. * Either "foreground" or "background"
  378. * @param {String} json
  379. * A custom (JSON) string
  380. * @param {Object} data
  381. * The notification properties
  382. */
  383. exports.ontrigger = function (id, state, json, data) {};
  384. /**
  385. * Fires after the notification was clicked.
  386. *
  387. * @param {String} id
  388. * The ID of the notification
  389. * @param {String} state
  390. * Either "foreground" or "background"
  391. * @param {String} json
  392. * A custom (JSON) string
  393. * @param {Object} data
  394. * The notification properties
  395. */
  396. exports.onclick = function (id, state, json, data) {};
  397. /**
  398. * Fires if the notification was canceled.
  399. *
  400. * @param {String} id
  401. * The ID of the notification
  402. * @param {String} state
  403. * Either "foreground" or "background"
  404. * @param {String} json
  405. * A custom (JSON) string
  406. * @param {Object} data
  407. * The notification properties
  408. */
  409. exports.oncancel = function (id, state, json, data) {};
  410. /**
  411. * Get fired when the notification was cleared.
  412. *
  413. * @param {String} id
  414. * The ID of the notification
  415. * @param {String} state
  416. * Either "foreground" or "background"
  417. * @param {String} json
  418. * A custom (JSON) string
  419. * @param {Object} data
  420. * The notification properties
  421. */
  422. exports.onclear = function (id, state, json, data) {};
  423. /**
  424. * @private
  425. *
  426. * Merges custom properties with the default values.
  427. *
  428. * @param {Object} options
  429. * Set of custom values
  430. *
  431. * @retrun {Object}
  432. * The merged property list
  433. */
  434. exports.mergeWithDefaults = function (options) {
  435. var defaults = this.getDefaults();
  436. for (var key in defaults) {
  437. if (options[key] === undefined) {
  438. options[key] = defaults[key];
  439. }
  440. }
  441. return options;
  442. };
  443. /**
  444. * @private
  445. *
  446. * Convert the passed values to their required type.
  447. *
  448. * @param {Object} options
  449. * Set of custom values
  450. *
  451. * @retrun {Object}
  452. * The converted property list
  453. */
  454. exports.convertProperties = function (options) {
  455. if (options.id) {
  456. options.id = options.id.toString();
  457. }
  458. if (options.date === undefined) {
  459. options.date = new Date();
  460. }
  461. if (options.title) {
  462. options.title = options.title.toString();
  463. }
  464. if (options.message) {
  465. options.message = options.message.toString();
  466. }
  467. if (options.text) {
  468. options.message = options.text.toString();
  469. }
  470. if (typeof options.date == 'object') {
  471. options.date = Math.round(options.date.getTime()/1000);
  472. }
  473. if (typeof options.json == 'object') {
  474. options.json = JSON.stringify(options.json);
  475. }
  476. return options;
  477. };
  478. /**
  479. * @private
  480. *
  481. * Merges the platform specific properties into the default properties.
  482. *
  483. * @return {Object}
  484. * The default properties for the platform
  485. */
  486. exports.applyPlatformSpecificOptions = function () {
  487. var defaults = this._defaults;
  488. switch (device.platform) {
  489. case 'Android':
  490. defaults.icon = 'icon';
  491. defaults.smallIcon = null;
  492. defaults.ongoing = false;
  493. defaults.led = 'FFFFFF'; /*RRGGBB*/
  494. defaults.sound = 'TYPE_NOTIFICATION'; break;
  495. case 'iOS':
  496. defaults.sound = ''; break;
  497. case 'WinCE': case 'Win32NT':
  498. defaults.smallImage = null;
  499. defaults.image = null;
  500. defaults.wideImage = null;
  501. }
  502. return defaults;
  503. };
  504. /**
  505. * @private
  506. *
  507. * Creates a callback, which will be executed within a specific scope.
  508. *
  509. * @param {Function} callbackFn
  510. * The callback function
  511. * @param {Object} scope
  512. * The scope for the function
  513. *
  514. * @return {Function}
  515. * The new callback function
  516. */
  517. exports.createCallbackFn = function (callbackFn, scope) {
  518. if (typeof callbackFn != 'function')
  519. return;
  520. return function () {
  521. callbackFn.apply(scope || this, arguments);
  522. };
  523. };
  524. /**
  525. * @private
  526. *
  527. * Executes the native counterpart.
  528. *
  529. * @param {String} action
  530. * The name of the action
  531. * @param args[]
  532. * Array of arguments
  533. * @param {Function} callback
  534. * The callback function
  535. * @param {Object} scope
  536. * The scope for the function
  537. */
  538. exports.exec = function (action, args, callback, scope) {
  539. var fn = this.createCallbackFn(callback, scope),
  540. params = [];
  541. if (Array.isArray(args)) {
  542. params = args;
  543. } else if (args) {
  544. params.push(args);
  545. }
  546. exec(fn, null, 'LocalNotification', action, params);
  547. };