Source: manager/notificationManager.js

  1. define(['mmirf/resources', 'mmirf/mediaManager', 'mmirf/logger', 'module'],
  2. /**
  3. *
  4. * @name NotificationManager
  5. * @memberOf mmir
  6. * @static
  7. * @class
  8. * @hideconstructor
  9. *
  10. * @requires mmir.MediaManager
  11. */
  12. function(
  13. res, mediaManager, Logger, module
  14. ){
  15. //the next comment enables JSDoc2 to map all functions etc. to the correct class description
  16. /** @scope mmir.NotificationManager.prototype *///for jsdoc2
  17. //private members
  18. /**
  19. *
  20. * @private
  21. * @memberOf NotificationManager#
  22. */
  23. var isCordovaEnv = res.isCordovaEnv();
  24. /**
  25. * @private
  26. * @memberOf NotificationManager#
  27. */
  28. var instance = null;
  29. /**
  30. * @private
  31. * @memberOf NotificationManager#
  32. */
  33. var logger = Logger.create(module);
  34. //private methods
  35. /**
  36. * Constructor-Method of Singleton mmir.NotificationManager.<br>
  37. *
  38. * @constructs NotificationManager
  39. * @memberOf NotificationManager#
  40. * @ignore
  41. */
  42. function constructor(){
  43. /**
  44. * @private
  45. * @memberOf NotificationManager.prototype
  46. */
  47. var INIT = 'init';
  48. /**
  49. * VIBRATE initialization status
  50. * @private
  51. * @memberOf NotificationManager.prototype
  52. */
  53. var isHapticEnabled = true;
  54. /**
  55. * Implementation for vibrate-function:
  56. * platform-dependent (if platform/device does not support it: as stub-function)
  57. *
  58. * @private
  59. * @type {Function}
  60. * @memberOf NotificationManager.prototype
  61. */
  62. var doVibrate = null;
  63. /**
  64. * Implementation for confirm-function:
  65. * shows "native" platform-specific confirm-dialog.
  66. *
  67. * <code>function(message, confirmCallback, title, buttonLabels)</code>
  68. *
  69. * @private
  70. * @type {Function}
  71. * @memberOf NotificationManager.prototype
  72. */
  73. var doConfirm = null;
  74. /**
  75. * Implementation for confirm-function:
  76. * shows "native" platform-specific alert-dialog.
  77. *
  78. * <code>(message, alertCallback, title, buttonName)</code>
  79. *
  80. * @private
  81. * @type {Function}
  82. * @memberOf NotificationManager.prototype
  83. */
  84. var doAlert = null;
  85. /**
  86. * Initialize the NotificationManager.
  87. *
  88. * At the moment this set the internal vibrate-function,
  89. * if available in the current execution environment
  90. * (or with a dummy function, if not).
  91. *
  92. * In addition, the alert-, and confirm-functions are set to their
  93. * platform-specific implementation.
  94. *
  95. * @memberOf NotificationManager.prototype
  96. * @private
  97. * @function
  98. */
  99. var _init = function(){
  100. var isNavigator = typeof navigator !== 'undefined';
  101. if(isCordovaEnv){
  102. if(navigator.vibrate){
  103. // logger.debug('Vibrate: navigator (API)');
  104. /** @ignore */
  105. doVibrate = function vibrate(n){ navigator.vibrate(n); };
  106. }
  107. else if(navigator.notification && navigator.notification.vibrate){
  108. // logger.debug('Vibrate: navigator.notification');
  109. /** @ignore */
  110. doVibrate = function vibrate(n){ navigator.notification.vibrate(n); };
  111. }
  112. else {
  113. logger.warn('INIT: could not detect navigator.notification.vibrate, using NOOP dummy instead.');
  114. /** @ignore */
  115. doVibrate = function dummyVibrate(n){ logger.warn('NotificationManager.vibrate('+n+') triggered in CORDOVA environment, but no VIBRATE functionality available.'); };
  116. }
  117. }
  118. else if (isNavigator && navigator.vibrate){
  119. // logger.debug('Vibrate API');
  120. /** @ignore */
  121. doVibrate = function vibrate(n){ navigator.vibrate(n); };
  122. }
  123. else if (isNavigator && navigator.webkitVibrate){
  124. // logger.debug('Vibrate: webkit');
  125. /** @ignore */
  126. doVibrate = function vibrate(n){ navigator.webkitVibrate(n); };
  127. }
  128. //set confirm-implementation
  129. if(isNavigator && navigator.notification && navigator.notification.confirm){
  130. // logger.debug('Confirm: navigator.notification');
  131. /** @ignore */
  132. doConfirm = function confirm(message, confirmCallback, title, buttonLabels){
  133. var cbWrapper = confirmCallback;
  134. if(confirmCallback){
  135. var self = this;
  136. cbWrapper = function(result){
  137. //need to convert NUMBER result to BOOLEAN:
  138. // result = [1,2,..]
  139. // -> default is: OK = 1, CANCEL = 2, close-the-dialog = 0
  140. var res = result === 1 ? true : false;
  141. confirmCallback.call(self, res);
  142. };
  143. }
  144. navigator.notification.confirm(message, cbWrapper, title, buttonLabels);
  145. };
  146. }
  147. else if(typeof window !== 'undefined' && window && window.confirm) {
  148. /** @ignore */
  149. doConfirm = function confirmWindow(message, confirmCallback, _title, _buttonLabels){
  150. //TODO use setTimeout here to "simulate" async execution?
  151. var result = window.confirm(message);
  152. if(confirmCallback){
  153. confirmCallback.call(this, result);
  154. }
  155. };
  156. }
  157. //set alert-implementation
  158. if(isNavigator && navigator.notification && navigator.notification.alert){
  159. // logger.debug('Alert: navigator.notification');
  160. /** @ignore */
  161. doAlert = function confirm(message, alertCallback, title, buttonLabels){
  162. navigator.notification.alert(message, alertCallback, title, buttonLabels);
  163. };
  164. }
  165. else if(typeof window !== 'undefined' && window && window.alert){
  166. /** @ignore */
  167. doAlert = function confirmWindow(message, alertCallback, _title, _buttonLabels){
  168. //TODO use setTimeout here to "simulate" async execution?
  169. window.alert(message);
  170. if(alertCallback){
  171. alertCallback.call(this);
  172. }
  173. };
  174. }
  175. };
  176. //SOUND / BEEP initialization:
  177. /**
  178. * @private
  179. * @type Number
  180. *
  181. * @memberOf NotificationManager.prototype
  182. */
  183. var beepVolume = 1.0;
  184. /**
  185. * The Audio object for the <em>beep</em> sound.
  186. *
  187. * @private
  188. * @type AudioObject
  189. *
  190. * @memberOf NotificationManager.prototype
  191. */
  192. var beepAudio = null;
  193. /**
  194. * Map for managing the currently loaded sounds
  195. *
  196. * @private
  197. * @type Map
  198. *
  199. * @memberOf NotificationManager.prototype
  200. */
  201. //TODO add option for limiting size of soundMap (-> e.g. how many resources are max. cached/occupied for Android)
  202. var soundMap = new Map();
  203. /**
  204. * Factory function for creating "sounds objects",
  205. * i.e. extend the basic Audio objects with needed functions/properties
  206. *
  207. * @private
  208. * @function
  209. *
  210. * @param {mmir.env.media.IAudio} audioObj
  211. * @param {String} name
  212. *
  213. * @returns {mmir.env.media.INotificationSound} the extended audio object, i.e. a NotificationSound
  214. *
  215. * @memberOf NotificationManager.prototype
  216. */
  217. function initNotificationSound(audioObj, name){
  218. audioObj.name = name;
  219. audioObj.setVolume(beepVolume);
  220. audioObj.isNotificationPlaying = false;
  221. audioObj.repeatNotification = 0;
  222. audioObj.playNotification = function(repeatNTimes){
  223. // logger.debug('isPlaying: '+this.isNotificationPlaying+', repeat: '+this.repeatNotification+', args: '+repeatNTimes+'');
  224. //"blocking mode": only re-start, if not already playing
  225. if(!this.isNotificationPlaying){
  226. this.repeatNotification = repeatNTimes ? repeatNTimes : 0;
  227. }
  228. if( this.repeatNotification < 1){
  229. //end recurusion
  230. this.isNotificationPlaying = false;
  231. this.repeatNotification = 0;
  232. }
  233. else {
  234. this.isNotificationPlaying = true;
  235. --this.repeatNotification;
  236. // this.stop();
  237. this.play();
  238. }
  239. };
  240. audioObj.setCallbacks = function(onFinished, onError){
  241. this.onFinishedListener = onFinished;
  242. this.onErrorListener = onError;
  243. };
  244. audioObj.clearCallbacks = function(){
  245. this.onFinishedListener = null;
  246. this.onErrorListener = null;
  247. };
  248. audioObj.fireFinished = function(){
  249. var tempOnFinishedListener = this.onFinishedListener;
  250. //clear callbacks
  251. // NOTE: do this before triggering callback, in case the callback re-plays the notification with new callbacks!
  252. // (if we would clear callbacks after invocation, we would delete the new callbacks!)
  253. this.clearCallbacks();
  254. if(tempOnFinishedListener){
  255. tempOnFinishedListener();
  256. }
  257. };
  258. audioObj.fireError = function(error){
  259. var tempOnErrorListener = this.onErrorListener;
  260. //clear callbacks
  261. // NOTE: do this before triggering callback, in case the callback re-plays the notification with new callbacks!
  262. // (if we would clear callbacks after invocation, we would delete the new callbacks!)
  263. this.clearCallbacks();
  264. //create error message with details
  265. var id;
  266. if(this.name){
  267. var entry = soundMap.get(this.name);
  268. id = '"' + this.name + '" -> ' + (entry? '"'+entry.url+'"' : 'UNDEF');
  269. }
  270. else {
  271. id = '"BEEP" -> "'+res.getBeepUrl()+'"';
  272. }
  273. var msg = 'Notification: Error playing the sound for notification '+id;
  274. //create Error object if necessary
  275. if(!error){
  276. error = new Error(msg);
  277. msg = null;
  278. }
  279. if(tempOnErrorListener){
  280. tempOnErrorListener(error, msg);
  281. }
  282. else {
  283. //if no callback: print debug output in error stream:
  284. logger.error( (msg? msg + ': ' : '') + error, error);
  285. }
  286. };
  287. return audioObj;
  288. };
  289. /**
  290. * Helper for creating an Audio object
  291. *
  292. * @private
  293. * @function
  294. *
  295. * @param {String} url
  296. * @param {Function} success
  297. * @param {Function} fail
  298. * @param {Function} init
  299. *
  300. * @returns {AudioObject} audio object
  301. *
  302. * @memberOf NotificationManager.prototype
  303. */
  304. function createAudio(url, success, fail, init){
  305. return mediaManager.getURLAsAudio(url, success, fail, init);
  306. }
  307. /**
  308. * Helper for "registering" a NotificationSound.
  309. *
  310. * Stores the sound object in {@link #soundMap}
  311. * with the ID <code>name</code>.
  312. *
  313. * The sound object will be initialized on first
  314. * retrieval, ie. {@link #doGetSoundFromMap}
  315. *
  316. * @private
  317. * @function
  318. *
  319. * @param {String} name
  320. * @param {String} theUrl
  321. * @param {Boolean} isKeepOnPause
  322. *
  323. * @memberOf NotificationManager.prototype
  324. */
  325. function initAudioSoundEntry(name, theUrl, isKeepOnPause){
  326. var config = {url: theUrl, audio: null};
  327. if(isKeepOnPause){
  328. config.isKeepOnPause = true;
  329. }
  330. soundMap.set(name, config);
  331. }
  332. /**
  333. * Helper for retrieving an existing sound from
  334. * the {@link #soundMap}.
  335. *
  336. * Initializes the sound if necessary.
  337. *
  338. * @private
  339. * @function
  340. *
  341. * @param {String} name
  342. * @param {Function} onErrorCallback
  343. *
  344. * @memberOf NotificationManager.prototype
  345. */
  346. function doGetSoundFromMap(name, onErrorCallback){
  347. var audioObj = null;
  348. var audioUrl = null;
  349. var keepOnPause = false;
  350. //if no name: use default beep
  351. if(!name){
  352. audioObj = beepAudio;
  353. audioUrl = res.getBeepUrl();
  354. }
  355. else {
  356. //retrieve information for sound
  357. var soundEntry = soundMap.get(name);
  358. if(soundEntry === INIT){
  359. //TODO set repeat-times?
  360. //sound is still initializing -> return
  361. return null; ////////////////////// EARLY EXIT //////////////////////
  362. }
  363. if(!soundEntry){
  364. var errMsg = 'NotificationManager: no sound "'+name+'" initialized!';
  365. if(onErrorCallback){
  366. onErrorCallback(errMsg);
  367. }
  368. else {
  369. logger.error(errMsg);
  370. }
  371. // throw new Error(errMsg);
  372. return null; ////////////////////// EARLY EXIT //////////////////////
  373. }
  374. audioObj = soundEntry.audio;//<- may be null
  375. audioUrl = soundEntry.url;//<- must NOT be null
  376. keepOnPause = soundEntry.isKeepOnPause? true : false;
  377. }
  378. return {
  379. sound: audioObj,
  380. url: audioUrl,
  381. isKeepOnPause: keepOnPause
  382. };
  383. }
  384. /**
  385. * Helper for playing a registered notification sound.
  386. *
  387. * Initializes the sound if necessary.
  388. *
  389. * @private
  390. * @function
  391. *
  392. * @param {String} name
  393. * ID of the sound
  394. * @param {Number} times
  395. * @param {Function} onFinishedCallback
  396. * @param {Function} onErrorCallback
  397. *
  398. * @memberOf NotificationManager.prototype
  399. */
  400. function playAudioSound(name, times, onFinishedCallback, onErrorCallback){
  401. var soundEntry = doGetSoundFromMap(name, onErrorCallback);
  402. if(soundEntry === null){
  403. //could not retrieve sound-object
  404. // (error callback will already have been invoked, so just return)
  405. return;/////////////////////// EARYL EXIT ///////////
  406. }
  407. var audioObj = soundEntry.sound;
  408. var audioUrl = soundEntry.url;
  409. var isKeepOnPause = soundEntry.isKeepOnPause;
  410. //create audio-object, if not existing yet
  411. if(audioObj === null){
  412. if(name){
  413. soundMap.set(name, INIT);
  414. }
  415. audioObj = createAudio(
  416. audioUrl,
  417. function onFinished(){
  418. this.playNotification();
  419. audioObj.fireFinished();
  420. },
  421. function onError(e){
  422. if(name) {
  423. soundMap.delete(name);
  424. };
  425. if(audioObj && audioObj.fireError){
  426. audioObj.fireError(e);
  427. }
  428. else {
  429. if(onErrorCallback){
  430. onErrorCallback(e);
  431. }
  432. else {
  433. logger.error('Error playing the sound from "'+audioUrl+'": '+ (e && typeof e.code !== 'undefined'? 'code '+e.code : e), e);
  434. }
  435. }
  436. },
  437. function onInit(){
  438. //FIX for Android/Cordova: return-value of createAudio will not set audioObj "fast enough"
  439. // (i.e. may not use async-initialization, depending on where the audio-file is located)
  440. // ... in order to be able to use keep variable audioObj useful -> do assignment now/here
  441. audioObj = this;
  442. initNotificationSound(audioObj, name);
  443. audioObj.setCallbacks(onFinishedCallback, onErrorCallback);
  444. //if no name: assume default beep
  445. if(!name){
  446. beepAudio = audioObj;
  447. }
  448. else {
  449. var theEntry = {url: audioUrl, audio: audioObj};
  450. if(isKeepOnPause){
  451. theEntry.isKeepOnPause = true;
  452. }
  453. soundMap.set(name, theEntry);
  454. }
  455. audioObj.playNotification(times);
  456. }
  457. );
  458. // //FIXME this is a QUICK-FIX:
  459. // // Android needs invocation of a media-method, before it triggers the on-init callback.
  460. // // We need to do this here, not within the
  461. // if(isCordovaEnv){
  462. // audioObj.init();
  463. // }
  464. }
  465. else {
  466. audioObj.setCallbacks(onFinishedCallback, onErrorCallback);
  467. audioObj.playNotification(times);
  468. }
  469. }
  470. /**
  471. * Helper for stop playing a registered notification sound.
  472. *
  473. * Initializes the sound if necessary.
  474. *
  475. * @private
  476. * @function
  477. *
  478. * @param {String} name
  479. * ID of the sound
  480. * @param {Function} onFinishedCallback
  481. * @param {Function} onErrorCallback
  482. *
  483. * @memberOf NotificationManager.prototype
  484. */
  485. function stopAudioSound(name, onFinishedCallback, onErrorCallback){
  486. var soundEntry = doGetSoundFromMap(name, onErrorCallback);
  487. // logger.error('Notification: invoked stop on notification-sound '+name+' -> '+JSON.stringify(soundEntry));//FIXM debug
  488. if(soundEntry === null){
  489. //could not retrieve sound-object
  490. // (error callback will already have been invoked, so just return)
  491. return;/////////////////////// EARYL EXIT ///////////
  492. }
  493. var audioObj = soundEntry.sound;
  494. //NOTE audioObj may be null, e.g. if sound is still initializing.
  495. if(audioObj != null){
  496. if(audioObj.repeatNotification > 0)
  497. audioObj.repeatNotification = 0;
  498. if(audioObj.isNotificationPlaying === true)
  499. audioObj.isNotificationPlaying = false;
  500. if(audioObj.stop){
  501. // logger.verbose('Notification: stopping notification-sound -> '+name);
  502. audioObj.stop();
  503. }
  504. }
  505. if(onFinishedCallback){
  506. onFinishedCallback.call(audioObj);
  507. }
  508. };
  509. //on Android: release resources on pause/exit, since they are limited
  510. if(isCordovaEnv){
  511. document.addEventListener("resume", function(_event){
  512. //initialize beep sound:
  513. playAudioSound(null, 0);
  514. });
  515. document.addEventListener(
  516. "pause",
  517. function(_event){
  518. //use temporal variable for minimizing concurrency problems
  519. var temp;
  520. if(beepAudio !== null){
  521. temp = beepAudio;
  522. beepAudio = null;
  523. temp.release();
  524. logger.debug('released media resources for beep.');
  525. }
  526. soundMap.forEach(function(entry){
  527. if(entry !== null && entry != INIT && ! entry.isKeepOnPause){
  528. temp = entry.audio;
  529. //audio may not be initialized yet:
  530. if(temp != null){
  531. entry.audio = null;
  532. temp.release();
  533. }
  534. if(logger.isd()) logger.debug('released media resources for '+entry.url);
  535. }
  536. });
  537. },
  538. false
  539. );
  540. }
  541. /** @lends mmir.NotificationManager.prototype */
  542. return { //public members and methods
  543. /** @scope mmir.NotificationManager.prototype */
  544. /**
  545. * Trigger a haptic vibration feedback.
  546. *
  547. * <p>Note: The device / execution environment may not support haptic vibration feedback
  548. *
  549. * @function
  550. * @param {Number} milliseconds
  551. * duration for vibration in milliseconds. Must be <code>> 0</code>
  552. * @public
  553. *
  554. * @memberOf mmir.NotificationManager.prototype
  555. */
  556. vibrate: function(milliseconds){
  557. if (isHapticEnabled && doVibrate){
  558. doVibrate(milliseconds);
  559. }
  560. },
  561. /**
  562. * Check if {@link #vibrate} is functional and enabled.
  563. *
  564. * <p>
  565. * If <code>false</code> is returned, calling the <code>vibrate()</code>
  566. * function will have no effect.
  567. *
  568. * @function
  569. * @returns {Boolean} <code>true</code> if {@link #vibrate} is functional
  570. * @public
  571. *
  572. * @memberOf mmir.NotificationManager.prototype
  573. */
  574. isVibrateEnabled: function(){
  575. if (isHapticEnabled && doVibrate){
  576. return true;
  577. }
  578. else {
  579. return false;
  580. }
  581. },
  582. /**
  583. * Check if the execution environment supports {@link #vibrate}.
  584. *
  585. * <p>
  586. * If <code>false</code> is returned, calling the <code>vibrate()</code>
  587. * function will have no effect.
  588. *
  589. * @function
  590. * @returns {Boolean} <code>true</code> if {@link #vibrate} is functional
  591. * @public
  592. *
  593. * @memberOf mmir.NotificationManager.prototype
  594. */
  595. isVibrateAvailable: function(){
  596. if (doVibrate){
  597. return true;
  598. }
  599. else {
  600. return false;
  601. }
  602. },
  603. /**
  604. * Enable or disable {@link #vibrate}.
  605. * <p>
  606. * NOTE: If {@ #isVibrateAvailable} returns <code>false</code>, enabling will have no effect.
  607. *
  608. * @function
  609. * @public
  610. *
  611. * @param {Boolean} enabled
  612. * set vibrate function to <code>enable</code>
  613. *
  614. * @memberOf mmir.NotificationManager.prototype
  615. */
  616. setVibrateEnabled: function(enabled){
  617. isHapticEnabled = enabled;
  618. },
  619. /**
  620. * Opens a (native) alert-notification dialog.
  621. *
  622. * @param {String} message
  623. * the alert message
  624. * @param {Function} [alertCallback]
  625. * callback that is triggered, after dialog was closed
  626. * @param {String} [title] OPTIONAL
  627. * the title for the alert dialog
  628. * (may not be provided / settable in all execution environments)
  629. * @param {String} [buttonName] OPTIONAL
  630. * the label for the close button in the alert dialog
  631. * (may not be provided / settable in all execution environments)
  632. * @function
  633. * @public
  634. *
  635. * @memberOf mmir.NotificationManager.prototype
  636. */
  637. alert: function(message, alertCallback, title, buttonName){
  638. if(doAlert){
  639. doAlert.call(this, message, alertCallback, title, buttonName);
  640. }
  641. else if(logger.isw()) {
  642. logger.warn('No alert dialog implementation available: (' + message + ', ' + alertCallback + ', ' + title + ', ' + buttonName + ')');
  643. }
  644. },
  645. /**
  646. * Opens a (native) confirm-notification dialog.
  647. *
  648. * @param {String} message
  649. * the confirm message
  650. * @param {Function} [alertCallback]
  651. * callback that is triggered, after dialog was closed.
  652. * The callback will be invoked with 1 argument:<br>
  653. * <code>callback(wasConfirmed : Boolean)</code><br>
  654. * if the OK/CONFIRM button was pressed, <code>wasConfirmed</code>
  655. * will be <code>true</code>, otherwise <code>false</code>.
  656. * @param {String} [title] OPTIONAL
  657. * the title for the confirm dialog
  658. * (may not be provided / settable in all execution environments)
  659. * @param {Array<String>} [buttonLabels] OPTIONAL
  660. * the labels for the buttons of the confirm dialog
  661. * (may not be provided / settable in all execution environments)
  662. *
  663. * @function
  664. * @public
  665. *
  666. * @memberOf mmir.NotificationManager.prototype
  667. */
  668. confirm: function(message, confirmCallback, title, buttonLabels){
  669. if(doConfirm){
  670. doConfirm.call(this, message, confirmCallback, title, buttonLabels);
  671. }
  672. else if(logger.isw()) {
  673. logger.warn('NotificationManager.confirm: No confirm dialog implementation available (' + message + ', ' + confirmCallback + ', ' + title + ', ' + (buttonLabels? JSON.stringify(buttonLabels) : buttonLabels) + ')');
  674. }
  675. },
  676. /**
  677. * Trigger a beep notification sound.
  678. *
  679. * @function
  680. * @param {Number} times
  681. * how many times should to beep repeated
  682. * @public
  683. *
  684. * @memberOf mmir.NotificationManager.prototype
  685. */
  686. beep: function(times){
  687. if (times>0){
  688. playAudioSound(null, times);
  689. }
  690. },
  691. /**
  692. * @memberOf mmir.NotificationManager.prototype
  693. */
  694. getVolume: function(){
  695. return beepVolume;
  696. },
  697. /**
  698. * Set the volume for sound notifications.
  699. *
  700. * @param {Number} vol
  701. * the new volume: a number between [0, 1]
  702. *
  703. * @see mmir.env.media.IAudio#setVolume
  704. *
  705. * @memberOf mmir.NotificationManager.prototype
  706. */
  707. setVolume: function(vol){
  708. if(typeof vol !== 'number'){
  709. throw new TypeError('argument vol (value: '+vol+') must be a number, but is instead: '+(typeof vol));
  710. }
  711. if(vol !== beepVolume){
  712. //set volume for beep notification
  713. beepVolume = vol;
  714. if(beepAudio){
  715. beepAudio.setVolume(beepVolume);
  716. }
  717. //set volume for notification sounds
  718. soundMap.forEach(function(entry){
  719. if(entry.audio !== null){
  720. entry.audio.setVolume(vol);
  721. }
  722. });
  723. }
  724. }
  725. /**
  726. * Trigger a sound notification by NAME (needs to be created first).
  727. *
  728. * @function
  729. * @param {String} name
  730. * the name / identifier for the sound (if <code>null</code>, beep notification is used)
  731. * @param {Number} times
  732. * how many times should to beep repeated
  733. * @public
  734. *
  735. * @see #createSound
  736. *
  737. * @memberOf mmir.NotificationManager.prototype
  738. */
  739. ,playSound: function(name, times, onFinished, onError){
  740. if (times>0){
  741. playAudioSound(name, times, onFinished, onError);
  742. }
  743. },
  744. /**
  745. * Create a sound notification.
  746. *
  747. * <p>
  748. * After creation, the sound "theSoundId" can be played via
  749. * <code>playSound("theSoundId", 1)</code>
  750. *
  751. * @function
  752. * @param {String} name
  753. * the name / identifier for the sound
  754. * @param {String} url
  755. * the URL for the audio of the sound
  756. * @param {Boolean} [isKeepOnPause] OPTIONAL
  757. * flag indicating, if the audio resources should be keept
  758. * when the device goes into <em>pause mode</em>
  759. * (may not apply to all execution environments;
  760. * e.g. relevant for Android environment)
  761. * <br>
  762. * DEFAULT: <code>false</code>
  763. * @public
  764. *
  765. * @memberOf mmir.NotificationManager.prototype
  766. */
  767. createSound: function(name, url, isKeepOnPause){ // TODO add callbacks? this would make the impl. more complex ..., successCallback, errorCallback){
  768. initAudioSoundEntry(name, url, isKeepOnPause);
  769. //DISABLED this triggers an error if MediaManager / LanguageManager etc. are not initialized yet!
  770. // logger.error('created sound "'+name+'" for url "'+url+'", calling from: ' + new Error().stack);
  771. // //immediately initialize the sound (but do not play it yet);
  772. // playAudioSound(name, 0);
  773. }
  774. /**
  775. * Stop a sound notification, if it is playing.
  776. *
  777. * Has no effect, if the notification is not playing.
  778. *
  779. * @function
  780. * @param {String} name
  781. * the name / identifier for the sound
  782. *
  783. * @memberOf mmir.NotificationManager.prototype
  784. */
  785. ,stopSound: function(name){
  786. stopAudioSound(name);
  787. }
  788. /**
  789. * <em>used by framework to initialize the default beep-sound</em>
  790. * @private
  791. * @memberOf mmir.NotificationManager.prototype
  792. */
  793. , initBeep: function(){
  794. //initialize beep sound:
  795. playAudioSound(null, 0);
  796. }
  797. /**
  798. * Initialize a sound notification.
  799. *
  800. * <p>
  801. * NOTE a sound does not need to be explicitly initialized, <code>playSound</code> will
  802. * automatically initialize the sound if necessary.
  803. *
  804. * <p>
  805. * Initializing a sound prepares all resources, so that the sound can be immediately played.
  806. *
  807. * For instance, a sound that needs to loaded from a remote server first, may take some time
  808. * before it can be played.
  809. *
  810. * <p>
  811. * NOTE the sound must be {@link #createSound|created} first, before initializing it.
  812. *
  813. * @function
  814. * @param {String} name
  815. * the name / identifier for the sound
  816. * @public
  817. *
  818. * @see #createSound
  819. *
  820. * @memberOf mmir.NotificationManager.prototype
  821. */
  822. , initSound: function(name){
  823. //initialize sound (identified by its name):
  824. playAudioSound(name, 0);
  825. }
  826. /**
  827. * <em>used by framework to initialize the NotificationManager</em>
  828. *
  829. * @memberOf mmir.NotificationManager.prototype
  830. */
  831. , init: function(){//<- used by framework to initialize the NotificationManager
  832. _init();
  833. this.init = function(){ return this; };
  834. return this;
  835. }
  836. };
  837. }
  838. instance = new constructor();
  839. return instance;
  840. });//END: define(..., function(){...