- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / google_now / cards.js
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 /**
8  * Show/hide trigger in a card.
9  *
10  * @typedef {{
11  *   showTime: number=,
12  *   hideTime: number=
13  * }}
14  */
15 var Trigger;
16
17 /**
18  * Data to build a dismissal request for a card from a specific group.
19  *
20  * @typedef {{
21  *   notificationId: string,
22  *   parameters: Object
23  * }}
24  */
25 var DismissalData;
26
27 /**
28  * Card merged from potentially multiple groups.
29  *
30  * @typedef {{
31  *   trigger: Trigger,
32  *   version: number,
33  *   timestamp: number,
34  *   notification: Object,
35  *   actionUrls: Object=,
36  *   groupRank: number,
37  *   dismissals: Array.<DismissalData>,
38  *   locationBased: boolean=
39  * }}
40  */
41 var MergedCard;
42
43 /**
44  * Set of parameters for creating card notification.
45  *
46  * @typedef {{
47  *   notification: Object,
48  *   hideTime: number=,
49  *   version: number,
50  *   previousVersion: number=,
51  *   locationBased: boolean=
52  * }}
53  */
54 var CardCreateInfo;
55
56 /**
57  * Names for tasks that can be created by the this file.
58  */
59 var SHOW_CARD_TASK_NAME = 'show-card';
60 var CLEAR_CARD_TASK_NAME = 'clear-card';
61
62 /**
63  * Builds an object to manage notification card set.
64  * @return {Object} Card set interface.
65  */
66 function buildCardSet() {
67   var cardShowPrefix = 'card-show-';
68   var cardHidePrefix = 'card-hide-';
69
70   /**
71    * Schedules hiding a notification.
72    * @param {string} cardId Card ID.
73    * @param {number=} opt_timeHide If specified, epoch time to hide the card. If
74    *      undefined, the card will be kept shown at least until next update.
75    */
76   function scheduleHiding(cardId, opt_timeHide) {
77     if (opt_timeHide === undefined)
78       return;
79
80     var alarmName = cardHidePrefix + cardId;
81     var alarmInfo = {when: opt_timeHide};
82     chrome.alarms.create(alarmName, alarmInfo);
83   }
84
85   /**
86    * Shows a notification.
87    * @param {string} cardId Card ID.
88    * @param {CardCreateInfo} cardCreateInfo Google Now card represented as a set
89    *     of parameters for showing a Chrome notification.
90    * @param {function(CardCreateInfo)=} onCardShown Optional parameter called
91    *     when each card is shown.
92    */
93   function showNotification(cardId, cardCreateInfo, onCardShown) {
94     console.log('cardManager.showNotification ' + cardId + ' ' +
95                 JSON.stringify(cardCreateInfo));
96
97     if (cardCreateInfo.hideTime <= Date.now()) {
98       console.log('cardManager.showNotification ' + cardId + ': expired');
99       // Card has expired. Schedule hiding to delete asociated information.
100       scheduleHiding(cardId, cardCreateInfo.hideTime);
101       return;
102     }
103
104     if (cardCreateInfo.previousVersion !== cardCreateInfo.version) {
105       // Delete a notification with the specified id if it already exists, and
106       // then create a notification.
107       instrumented.notifications.create(
108           cardId,
109           cardCreateInfo.notification,
110           function(newNotificationId) {
111             if (!newNotificationId || chrome.runtime.lastError) {
112               var errorMessage = chrome.runtime.lastError &&
113                                  chrome.runtime.lastError.message;
114               console.error('notifications.create: ID=' + newNotificationId +
115                             ', ERROR=' + errorMessage);
116               return;
117             }
118
119             if (onCardShown !== undefined)
120               onCardShown(cardCreateInfo);
121
122             scheduleHiding(cardId, cardCreateInfo.hideTime);
123           });
124     } else {
125       // Update existing notification.
126       instrumented.notifications.update(
127           cardId,
128           cardCreateInfo.notification,
129           function(wasUpdated) {
130             if (!wasUpdated || chrome.runtime.lastError) {
131               var errorMessage = chrome.runtime.lastError &&
132                                  chrome.runtime.lastError.message;
133               console.error('notifications.update: UPDATED=' + wasUpdated +
134                             ', ERROR=' + errorMessage);
135               return;
136             }
137
138             scheduleHiding(cardId, cardCreateInfo.hideTime);
139           });
140     }
141   }
142
143   /**
144    * Updates/creates a card notification with new data.
145    * @param {string} cardId Card ID.
146    * @param {MergedCard} card Google Now card from the server.
147    * @param {number=} previousVersion The version of the shown card with
148    *     this id, if it exists, undefined otherwise.
149    * @param {function(CardCreateInfo)=} onCardShown Optional parameter called
150    *     when each card is shown.
151    * @return {Object} Notification data entry for this card.
152    */
153   function update(cardId, card, previousVersion, onCardShown) {
154     console.log('cardManager.update ' + JSON.stringify(card) + ' ' +
155         previousVersion);
156
157     chrome.alarms.clear(cardHidePrefix + cardId);
158
159     var cardCreateInfo = {
160       notification: card.notification,
161       hideTime: card.trigger.hideTime,
162       version: card.version,
163       previousVersion: previousVersion,
164       locationBased: card.locationBased
165     };
166
167     var shownImmediately = false;
168     var cardShowAlarmName = cardShowPrefix + cardId;
169     if (card.trigger.showTime && card.trigger.showTime > Date.now()) {
170       // Card needs to be shown later.
171       console.log('cardManager.update: postponed');
172       var alarmInfo = {
173         when: card.trigger.showTime
174       };
175       chrome.alarms.create(cardShowAlarmName, alarmInfo);
176     } else {
177       // Card needs to be shown immediately.
178       console.log('cardManager.update: immediate');
179       chrome.alarms.clear(cardShowAlarmName);
180       showNotification(cardId, cardCreateInfo, onCardShown);
181     }
182
183     return {
184       actionUrls: card.actionUrls,
185       cardCreateInfo: cardCreateInfo,
186       dismissals: card.dismissals
187     };
188   }
189
190   /**
191    * Removes a card notification.
192    * @param {string} cardId Card ID.
193    * @param {boolean} clearStorage True if the information associated with the
194    *     card should be erased from chrome.storage.
195    */
196   function clear(cardId, clearStorage) {
197     console.log('cardManager.clear ' + cardId);
198
199     chrome.notifications.clear(cardId, function() {});
200     chrome.alarms.clear(cardShowPrefix + cardId);
201     chrome.alarms.clear(cardHidePrefix + cardId);
202
203     if (clearStorage) {
204       instrumented.storage.local.get(
205           ['notificationsData', 'notificationGroups'],
206           function(items) {
207             items = items || {};
208             items.notificationsData = items.notificationsData || {};
209             items.notificationGroups = items.notificationGroups || {};
210
211             delete items.notificationsData[cardId];
212
213             for (var groupName in items.notificationGroups) {
214               var group = items.notificationGroups[groupName];
215               for (var i = 0; i != group.cards.length; ++i) {
216                 if (group.cards[i].chromeNotificationId == cardId) {
217                   group.cards.splice(i, 1);
218                   break;
219                 }
220               }
221             }
222
223             chrome.storage.local.set(items);
224           });
225     }
226   }
227
228   instrumented.alarms.onAlarm.addListener(function(alarm) {
229     console.log('cardManager.onAlarm ' + JSON.stringify(alarm));
230
231     if (alarm.name.indexOf(cardShowPrefix) == 0) {
232       // Alarm to show the card.
233       tasks.add(SHOW_CARD_TASK_NAME, function() {
234         var cardId = alarm.name.substring(cardShowPrefix.length);
235         instrumented.storage.local.get('notificationsData', function(items) {
236           console.log('cardManager.onAlarm.get ' + JSON.stringify(items));
237           if (!items || !items.notificationsData)
238             return;
239           var notificationData = items.notificationsData[cardId];
240           if (!notificationData)
241             return;
242
243           var cardShownCallback = undefined;
244           if (localStorage['locationCardsShown'] <
245               LOCATION_CARDS_LINK_THRESHOLD) {
246              cardShownCallback = countLocationCard;
247           }
248
249           showNotification(
250               cardId, notificationData.cardCreateInfo, cardShownCallback);
251         });
252       });
253     } else if (alarm.name.indexOf(cardHidePrefix) == 0) {
254       // Alarm to hide the card.
255       tasks.add(CLEAR_CARD_TASK_NAME, function() {
256         var cardId = alarm.name.substring(cardHidePrefix.length);
257         clear(cardId, true);
258       });
259     }
260   });
261
262   return {
263     update: update,
264     clear: clear
265   };
266 }