1 // Copyright 2013 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 'use strict'; 6 7 var MS_IN_SECOND = 1000; 8 9 /** 10 * Builds an object to manage notification card set. 11 * @return {Object} Card set interface. 12 */ 13 function buildCardSet() { 14 var cardShowPrefix = 'card-show-'; 15 var cardHidePrefix = 'card-hide-'; 16 17 /** 18 * Schedules hiding a notification. 19 * @param {string} cardId Card ID. 20 * @param {number=} opt_timeHide If specified, epoch time to hide the card. If 21 * undefined, the card will be kept shown at least until next update. 22 */ 23 function scheduleHiding(cardId, opt_timeHide) { 24 if (opt_timeHide === undefined) 25 return; 26 27 var alarmName = cardHidePrefix + cardId; 28 var alarmInfo = {when: opt_timeHide}; 29 chrome.alarms.create(alarmName, alarmInfo); 30 } 31 32 /** 33 * Shows a notification. 34 * @param {string} cardId Card ID. 35 * @param {Object} cardCreateInfo Google Now card represented as a set of 36 * parameters for showing a Chrome notification. 37 */ 38 function showNotification(cardId, cardCreateInfo) { 39 console.log('cardManager.showNotification ' + cardId + ' ' + 40 JSON.stringify(cardCreateInfo)); 41 42 if (cardCreateInfo.previousVersion !== cardCreateInfo.version) { 43 try { 44 // Delete a notification with the specified id if it already exists, and 45 // then create a notification. 46 instrumented.notifications.create( 47 cardId, 48 cardCreateInfo.notification, 49 function(newNotificationId) { 50 if (!newNotificationId || chrome.runtime.lastError) { 51 var errorMessage = chrome.runtime.lastError && 52 chrome.runtime.lastError.message; 53 console.error('notifications.create: ID=' + newNotificationId + 54 ', ERROR=' + errorMessage); 55 return; 56 } 57 58 scheduleHiding(cardId, cardCreateInfo.timeHide); 59 }); 60 } catch (error) { 61 console.error('Error in notifications.create: ' + error); 62 } 63 } else { 64 try { 65 // Update existing notification. 66 instrumented.notifications.update( 67 cardId, 68 cardCreateInfo.notification, 69 function(wasUpdated) { 70 if (!wasUpdated || chrome.runtime.lastError) { 71 var errorMessage = chrome.runtime.lastError && 72 chrome.runtime.lastError.message; 73 console.error('notifications.update: UPDATED=' + wasUpdated + 74 ', ERROR=' + errorMessage); 75 return; 76 } 77 78 scheduleHiding(cardId, cardCreateInfo.timeHide); 79 }); 80 } catch (error) { 81 console.error('Error in notifications.update: ' + error); 82 } 83 } 84 } 85 86 /** 87 * Updates/creates a card notification with new data. 88 * @param {Object} card Google Now from the server. 89 * @param {number=} previousVersion The version of the shown card with 90 * this id, if it exists, undefined otherwise. 91 * @return {Object} Notification data entry for this card. 92 */ 93 function update(card, previousVersion) { 94 console.log('cardManager.update ' + JSON.stringify(card) + ' ' + 95 previousVersion); 96 97 if (typeof card.version != 'number') { 98 console.log('cardCreateInfo.version is not a number'); 99 // Fix card version. 100 card.version = previousVersion || 0; 101 } 102 103 // TODO(vadimt): Don't clear alarms etc that don't exist. Or make sure doing 104 // this doesn't output an error to console. 105 chrome.alarms.clear(cardHidePrefix + card.notificationId); 106 107 var timeHide = card.trigger && card.trigger.hideTimeSec !== undefined ? 108 Date.now() + card.trigger.hideTimeSec * MS_IN_SECOND : undefined; 109 var cardCreateInfo = { 110 notification: card.notification, 111 timeHide: timeHide, 112 version: card.version, 113 previousVersion: previousVersion 114 }; 115 116 var cardShowAlarmName = cardShowPrefix + card.notificationId; 117 if (card.trigger && card.trigger.showTimeSec) { 118 // Card needs to be shown later. 119 console.log('cardManager.register: postponed'); 120 var alarmInfo = { 121 when: Date.now() + card.trigger.showTimeSec * MS_IN_SECOND 122 }; 123 chrome.alarms.create(cardShowAlarmName, alarmInfo); 124 } else { 125 // Card needs to be shown immediately. 126 console.log('cardManager.register: immediate'); 127 chrome.alarms.clear(cardShowAlarmName); 128 showNotification(card.notificationId, cardCreateInfo); 129 } 130 131 return { 132 actionUrls: card.actionUrls, 133 cardCreateInfo: cardCreateInfo, 134 dismissalParameters: card.dismissal 135 }; 136 } 137 138 /** 139 * Removes a card notification. 140 * @param {string} cardId Card ID. 141 */ 142 function clear(cardId) { 143 console.log('cardManager.unregister ' + cardId); 144 145 chrome.notifications.clear(cardId, function() {}); 146 chrome.alarms.clear(cardShowPrefix + cardId); 147 chrome.alarms.clear(cardHidePrefix + cardId); 148 } 149 150 instrumented.alarms.onAlarm.addListener(function(alarm) { 151 console.log('cardManager.onAlarm ' + JSON.stringify(alarm)); 152 153 if (alarm.name.indexOf(cardShowPrefix) == 0) { 154 // Alarm to show the card. 155 var cardId = alarm.name.substring(cardShowPrefix.length); 156 instrumented.storage.local.get('notificationsData', function(items) { 157 items.notificationsData = items.notificationsData || {}; 158 console.log('cardManager.onAlarm.get ' + JSON.stringify(items)); 159 var notificationData = items.notificationsData[cardId]; 160 if (!notificationData) 161 return; 162 163 showNotification(cardId, notificationData.cardCreateInfo); 164 }); 165 } else if (alarm.name.indexOf(cardHidePrefix) == 0) { 166 // Alarm to hide the card. 167 var cardId = alarm.name.substring(cardHidePrefix.length); 168 chrome.notifications.clear(cardId, function() {}); 169 } 170 }); 171 172 return { 173 update: update, 174 clear: clear 175 }; 176 } 177