OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 'use strict'; | 5 'use strict'; |
6 | 6 |
7 /** | 7 /** |
8 * @fileoverview The event page for Google Now for Chrome implementation. | 8 * @fileoverview The event page for Google Now for Chrome implementation. |
9 * The Google Now event page gets Google Now cards from the server and shows | 9 * The Google Now event page gets Google Now cards from the server and shows |
10 * them as Chrome notifications. | 10 * them as Chrome notifications. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
95 var UPDATE_CARDS_TASK_NAME = 'update-cards'; | 95 var UPDATE_CARDS_TASK_NAME = 'update-cards'; |
96 var DISMISS_CARD_TASK_NAME = 'dismiss-card'; | 96 var DISMISS_CARD_TASK_NAME = 'dismiss-card'; |
97 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; | 97 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; |
98 var STATE_CHANGED_TASK_NAME = 'state-changed'; | 98 var STATE_CHANGED_TASK_NAME = 'state-changed'; |
99 var SHOW_ON_START_TASK_NAME = 'show-cards-on-start'; | 99 var SHOW_ON_START_TASK_NAME = 'show-cards-on-start'; |
100 var ON_PUSH_MESSAGE_START_TASK_NAME = 'on-push-message'; | 100 var ON_PUSH_MESSAGE_START_TASK_NAME = 'on-push-message'; |
101 | 101 |
102 var LOCATION_WATCH_NAME = 'location-watch'; | 102 var LOCATION_WATCH_NAME = 'location-watch'; |
103 | 103 |
104 /** | 104 /** |
105 * Notification as it's sent by the server. | 105 * Group as it's received from the server. |
106 * | 106 * |
107 * @typedef {{ | 107 * @typedef {{ |
108 * notificationId: string, | 108 * nextPollSeconds: (string|undefined), |
109 * chromeNotificationId: string, | 109 * rank: (number|undefined), |
110 * trigger: Object=, | 110 * requested: (boolean|undefined) |
111 * version: number, | |
112 * chromeNotificationOptions: Object, | |
113 * actionUrls: Object=, | |
114 * dismissal: Object | |
115 * }} | 111 * }} |
116 */ | 112 */ |
117 var UnmergedNotification; | 113 var ReceivedGroup; |
114 | |
115 /** | |
116 * Server response with notifications and groups. | |
117 * | |
118 * @typedef {{ | |
119 * googleNowDisabled: (boolean|undefined), | |
120 * groups: Object.<string, ReceivedGroup>, | |
121 * notifications: Array.<ReceivedNotification> | |
122 * }} | |
123 */ | |
124 var ServerResponse; | |
118 | 125 |
119 /** | 126 /** |
120 * Notification group as the client stores it. |cardsTimestamp| and |rank| are | 127 * Notification group as the client stores it. |cardsTimestamp| and |rank| are |
121 * defined if |cards| is non-empty. |nextPollTime| is undefined if the server | 128 * defined if |cards| is non-empty. |nextPollTime| is undefined if the server |
122 * (1) never sent 'nextPollSeconds' for the group or | 129 * (1) never sent 'nextPollSeconds' for the group or |
123 * (2) didn't send 'nextPollSeconds' with the last group update containing a | 130 * (2) didn't send 'nextPollSeconds' with the last group update containing a |
124 * cards update and all the times after that. | 131 * cards update and all the times after that. |
125 * | 132 * |
126 * @typedef {{ | 133 * @typedef {{ |
127 * cards: Array.<UnmergedNotification>, | 134 * cards: Array.<ReceivedNotification>, |
128 * cardsTimestamp: number=, | 135 * cardsTimestamp: (number|undefined), |
129 * nextPollTime: number=, | 136 * nextPollTime: (number|undefined), |
130 * rank: number= | 137 * rank: (number|undefined) |
131 * }} | 138 * }} |
132 */ | 139 */ |
133 var StorageGroup; | 140 var StorageGroup; |
robliao
2013/12/05 23:27:46
Should this be NotificationGroup?
vadimt
2013/12/06 02:32:38
No. We transform a received group before storing (
robliao
2013/12/06 02:38:38
StoredNotificationGroup would be better then.
On 2
vadimt
2013/12/06 02:49:04
Done.
| |
134 | 141 |
135 /** | 142 /** |
143 * Pending (not yet successfully sent) dismissal for an unmerged notification. | |
rgustafson
2013/12/06 20:01:17
unmerged notification -> received notification to
vadimt
2013/12/06 20:57:14
Done.
| |
144 * |time| is the moment when the user requested dismissal. | |
145 * | |
146 * @typedef {{ | |
147 * chromeNotificationId: string, | |
148 * time: number, | |
149 * dismissalData: DismissalData | |
150 * }} | |
151 */ | |
152 var PendingDismissal; | |
153 | |
154 /** | |
136 * Checks if a new task can't be scheduled when another task is already | 155 * Checks if a new task can't be scheduled when another task is already |
137 * scheduled. | 156 * scheduled. |
138 * @param {string} newTaskName Name of the new task. | 157 * @param {string} newTaskName Name of the new task. |
139 * @param {string} scheduledTaskName Name of the scheduled task. | 158 * @param {string} scheduledTaskName Name of the scheduled task. |
140 * @return {boolean} Whether the new task conflicts with the existing task. | 159 * @return {boolean} Whether the new task conflicts with the existing task. |
141 */ | 160 */ |
142 function areTasksConflicting(newTaskName, scheduledTaskName) { | 161 function areTasksConflicting(newTaskName, scheduledTaskName) { |
143 if (newTaskName == UPDATE_CARDS_TASK_NAME && | 162 if (newTaskName == UPDATE_CARDS_TASK_NAME && |
144 scheduledTaskName == UPDATE_CARDS_TASK_NAME) { | 163 scheduledTaskName == UPDATE_CARDS_TASK_NAME) { |
145 // If a card update is requested while an old update is still scheduled, we | 164 // If a card update is requested while an old update is still scheduled, we |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
266 } else { | 285 } else { |
267 originalOnLoadEnd(event); | 286 originalOnLoadEnd(event); |
268 } | 287 } |
269 }); | 288 }); |
270 | 289 |
271 callbackBoolean(true); | 290 callbackBoolean(true); |
272 }); | 291 }); |
273 } | 292 } |
274 | 293 |
275 /** | 294 /** |
276 * Shows parsed and merged cards as notifications. | 295 * Shows parsed and combined cards as notifications. |
277 * @param {Object.<string, MergedCard>} cards Map from chromeNotificationId to | 296 * @param {Object.<string, CombinedCard>} cards Map from chromeNotificationId to |
robliao
2013/12/05 23:27:46
Does the annotation system work on non-object type
vadimt
2013/12/06 02:32:38
Done.
| |
278 * the merged card, containing cards to show. | 297 * the combined card, containing cards to show. |
279 * @param {function(CardCreateInfo)=} onCardShown Optional parameter called when | 298 * @param {function(ReceivedNotification)=} onCardShown Optional parameter |
280 * each card is shown. | 299 * called when each card is shown. |
281 */ | 300 */ |
282 function showNotificationCards(cards, onCardShown) { | 301 function showNotificationCards(cards, onCardShown) { |
283 console.log('showNotificationCards ' + JSON.stringify(cards)); | 302 console.log('showNotificationCards ' + JSON.stringify(cards)); |
284 | 303 |
285 instrumented.storage.local.get(['notificationsData', 'recentDismissals'], | 304 instrumented.notifications.getAll(function(notifications) { |
286 function(items) { | 305 console.log('showNotificationCards-getAll ' + |
287 console.log('showNotificationCards-get ' + | 306 JSON.stringify(notifications)); |
288 JSON.stringify(items)); | 307 notifications = notifications || {}; |
289 items = items || {}; | |
290 items.notificationsData = items.notificationsData || {}; | |
291 items.recentDismissals = items.recentDismissals || {}; | |
292 | 308 |
293 instrumented.notifications.getAll(function(notifications) { | 309 // Mark notifications that didn't receive an update as having received |
294 console.log('showNotificationCards-getAll ' + | 310 // an empty update. |
295 JSON.stringify(notifications)); | 311 for (var chromeNotificationId in notifications) { |
296 notifications = notifications || {}; | 312 cards[chromeNotificationId] = cards[chromeNotificationId] || []; |
313 } | |
297 | 314 |
298 // Build a set of non-expired recent dismissals. It will be used for | 315 /** @type {Object.<string, NotificationDataEntry>} */ |
299 // client-side filtering of cards. | 316 var notificationsData = {}; |
300 var updatedRecentDismissals = {}; | |
301 var currentTimeMs = Date.now(); | |
302 for (var chromeNotificationId in items.recentDismissals) { | |
303 if (currentTimeMs - items.recentDismissals[chromeNotificationId] < | |
304 DISMISS_RETENTION_TIME_MS) { | |
305 updatedRecentDismissals[chromeNotificationId] = | |
306 items.recentDismissals[chromeNotificationId]; | |
307 delete cards[chromeNotificationId]; | |
308 } | |
309 } | |
310 | 317 |
311 // Delete notifications that didn't receive an update. | 318 // Create/update/delete notifications. |
312 for (var chromeNotificationId in notifications) { | 319 for (var chromeNotificationId in cards) { |
313 console.log('showNotificationCards-delete-check ' + | 320 notificationsData[chromeNotificationId] = cardSet.update( |
314 chromeNotificationId); | 321 chromeNotificationId, |
315 if (!(chromeNotificationId in cards)) { | 322 cards[chromeNotificationId], |
316 console.log( | 323 onCardShown); |
317 'showNotificationCards-delete ' + chromeNotificationId); | 324 } |
318 cardSet.clear(chromeNotificationId, false); | 325 chrome.storage.local.set({notificationsData: notificationsData}); |
319 } | 326 }); |
320 } | |
321 | |
322 // Create/update notifications and store their new properties. | |
323 var newNotificationsData = {}; | |
324 for (var chromeNotificationId in cards) { | |
325 var notificationData = | |
326 items.notificationsData[chromeNotificationId]; | |
327 var previousVersion = notifications[chromeNotificationId] && | |
328 notificationData && | |
329 notificationData.cardCreateInfo && | |
330 notificationData.cardCreateInfo.version; | |
331 newNotificationsData[chromeNotificationId] = cardSet.update( | |
332 chromeNotificationId, | |
333 cards[chromeNotificationId], | |
334 previousVersion, | |
335 onCardShown); | |
336 } | |
337 | |
338 chrome.storage.local.set({ | |
339 notificationsData: newNotificationsData, | |
340 recentDismissals: updatedRecentDismissals | |
341 }); | |
342 }); | |
343 }); | |
344 } | 327 } |
345 | 328 |
346 /** | 329 /** |
347 * Removes all cards and card state on Google Now close down. | 330 * Removes all cards and card state on Google Now close down. |
348 * For example, this occurs when the geolocation preference is unchecked in the | 331 * For example, this occurs when the geolocation preference is unchecked in the |
349 * content settings. | 332 * content settings. |
350 */ | 333 */ |
351 function removeAllCards() { | 334 function removeAllCards() { |
352 console.log('removeAllCards'); | 335 console.log('removeAllCards'); |
353 | 336 |
354 // TODO(robliao): Once Google Now clears its own checkbox in the | 337 // TODO(robliao): Once Google Now clears its own checkbox in the |
355 // notifications center and bug 260376 is fixed, the below clearing | 338 // notifications center and bug 260376 is fixed, the below clearing |
356 // code is no longer necessary. | 339 // code is no longer necessary. |
357 instrumented.notifications.getAll(function(notifications) { | 340 instrumented.notifications.getAll(function(notifications) { |
358 notifications = notifications || {}; | 341 notifications = notifications || {}; |
359 for (var chromeNotificationId in notifications) { | 342 for (var chromeNotificationId in notifications) { |
360 instrumented.notifications.clear(chromeNotificationId, function() {}); | 343 instrumented.notifications.clear(chromeNotificationId, function() {}); |
361 } | 344 } |
362 chrome.storage.local.remove(['notificationsData', 'notificationGroups']); | 345 chrome.storage.local.remove(['notificationsData', 'notificationGroups']); |
363 }); | 346 }); |
364 } | 347 } |
365 | 348 |
366 /** | 349 /** |
367 * Merges an unmerged notification into a merged card with same ID. | 350 * Adds a card group into a set of combined cards. |
368 * @param {MergedCard=} mergedCard Existing merged card or undefined if a merged | 351 * @param {Object.<string, CombinedCard>} combinedCards Map from |
369 * card doesn't exist (i.e. we see this ID for the first time while | 352 * chromeNotificationId to a combined card. |
370 * merging). | 353 * This is an input/output parameter. |
371 * @param {UnmergedNotification} unmergedNotification Notification as it was | 354 * @param {StorageGroup} storageGroup Group to combine into the combined card |
372 * received from the server. | 355 * set. |
373 * @param {number} notificationTimestamp The moment the unmerged card was | |
374 * received. | |
375 * @param {number} notificationGroupRank Rank of the group of the unmerged card. | |
376 * @return {MergedCard} Result of merging |unmergedNotification| into | |
377 * |mergedCard|. | |
378 */ | 356 */ |
379 function mergeCards( | 357 function combineGroup(combinedCards, storageGroup) { |
robliao
2013/12/05 23:27:46
storageGroup -> notificationGroup
vadimt
2013/12/06 02:32:38
See above. It's important that this is StorageGrou
| |
380 mergedCard, | 358 for (var i = 0; i < storageGroup.cards.length; i++) { |
381 unmergedNotification, | 359 /** @type {ReceivedNotification} */ |
382 notificationTimestamp, | 360 var receivedNotification = storageGroup.cards[i]; |
383 notificationGroupRank) { | |
384 var result = mergedCard || {dismissals: []}; | |
385 | 361 |
386 var priority = mergedCard ? | 362 /** @type {UncombinedNotification} */ |
387 Math.max( | 363 var uncombinedNotification = { |
388 mergedCard.notification.priority, | 364 receivedNotification: receivedNotification, |
389 unmergedNotification.chromeNotificationOptions.priority) : | 365 showTime: receivedNotification.trigger.showTimeSec && |
390 unmergedNotification.chromeNotificationOptions.priority; | 366 (storageGroup.cardsTimestamp + |
367 receivedNotification.trigger.showTimeSec * MS_IN_SECOND), | |
368 hideTime: storageGroup.cardsTimestamp + | |
369 receivedNotification.trigger.hideTimeSec * MS_IN_SECOND | |
370 }; | |
391 | 371 |
392 if (!mergedCard || notificationGroupRank > mergedCard.groupRank) { | 372 var combinedCard = |
393 result.groupRank = notificationGroupRank; | 373 combinedCards[receivedNotification.chromeNotificationId] || []; |
394 var showTime = unmergedNotification.trigger && | 374 combinedCard.push(uncombinedNotification); |
395 unmergedNotification.trigger.showTimeSec && | 375 combinedCards[receivedNotification.chromeNotificationId] = combinedCard; |
robliao
2013/12/05 23:27:46
Alternatively for the above lines...
combinedCards
vadimt
2013/12/06 02:32:38
The suggested code is longer, since there are 3 in
robliao
2013/12/06 02:38:38
Only reason I had to suggest a change is I had to
vadimt
2013/12/06 02:49:04
Good point. I changed the order. Hopefully, now it
| |
396 (notificationTimestamp + | |
397 unmergedNotification.trigger.showTimeSec * MS_IN_SECOND); | |
398 var hideTime = unmergedNotification.trigger && | |
399 unmergedNotification.trigger.hideTimeSec && | |
400 (notificationTimestamp + | |
401 unmergedNotification.trigger.hideTimeSec * MS_IN_SECOND); | |
402 result.trigger = { | |
403 showTime: showTime, | |
404 hideTime: hideTime | |
405 }; | |
406 } | |
407 | |
408 if (!mergedCard || notificationTimestamp > mergedCard.timestamp) { | |
409 result.timestamp = notificationTimestamp; | |
410 result.notification = unmergedNotification.chromeNotificationOptions; | |
411 result.actionUrls = unmergedNotification.actionUrls; | |
412 result.version = unmergedNotification.version; | |
413 } | |
414 | |
415 result.locationBased = | |
416 result.locationBased || unmergedNotification.locationBased; | |
417 | |
418 result.notification.priority = priority; | |
419 var dismissalData = { | |
420 notificationId: unmergedNotification.notificationId, | |
421 parameters: unmergedNotification.dismissal | |
422 }; | |
423 result.dismissals.push(dismissalData); | |
424 | |
425 return result; | |
426 } | |
427 | |
428 /** | |
429 * Merges a card group into a set of merged cards. | |
430 * @param {Object.<string, MergedCard>} mergedCards Map from | |
431 * chromeNotificationId to a merged card. | |
432 * This is an input/output parameter. | |
433 * @param {StorageGroup} storageGroup Group to merge into the merged card set. | |
434 */ | |
435 function mergeGroup(mergedCards, storageGroup) { | |
436 for (var i = 0; i < storageGroup.cards.length; i++) { | |
437 var card = storageGroup.cards[i]; | |
438 mergedCards[card.chromeNotificationId] = mergeCards( | |
439 mergedCards[card.chromeNotificationId], | |
440 card, | |
441 storageGroup.cardsTimestamp, | |
442 storageGroup.rank); | |
443 } | 376 } |
444 } | 377 } |
445 | 378 |
446 /** | 379 /** |
447 * Schedules next cards poll. | 380 * Schedules next cards poll. |
448 * @param {Object.<string, StorageGroup>} groups Map from group name to group | 381 * @param {Object.<string, StorageGroup>} groups Map from group name to group |
449 * information. | 382 * information. |
450 * @param {boolean} isOptedIn True if the user is opted in to Google Now. | 383 * @param {boolean} isOptedIn True if the user is opted in to Google Now. |
451 */ | 384 */ |
452 function scheduleNextPoll(groups, isOptedIn) { | 385 function scheduleNextPoll(groups, isOptedIn) { |
(...skipping 20 matching lines...) Expand all Loading... | |
473 'GoogleNow', function(params) { | 406 'GoogleNow', function(params) { |
474 var optinPollPeriodSeconds = | 407 var optinPollPeriodSeconds = |
475 parseInt(params && params.optinPollPeriodSeconds, 10) || | 408 parseInt(params && params.optinPollPeriodSeconds, 10) || |
476 DEFAULT_OPTIN_CHECK_PERIOD_SECONDS; | 409 DEFAULT_OPTIN_CHECK_PERIOD_SECONDS; |
477 updateCardsAttempts.start(optinPollPeriodSeconds); | 410 updateCardsAttempts.start(optinPollPeriodSeconds); |
478 }); | 411 }); |
479 } | 412 } |
480 } | 413 } |
481 | 414 |
482 /** | 415 /** |
483 * Merges notification groups into a set of Chrome notifications and shows them. | 416 * Combines notification groups into a set of Chrome notifications and shows |
417 * them. | |
484 * @param {Object.<string, StorageGroup>} notificationGroups Map from group name | 418 * @param {Object.<string, StorageGroup>} notificationGroups Map from group name |
485 * to group information. | 419 * to group information. |
486 * @param {function(CardCreateInfo)=} onCardShown Optional parameter called when | 420 * @param {function(ReceivedNotification)=} onCardShown Optional parameter |
487 * each card is shown. | 421 * called when each card is shown. |
488 */ | 422 */ |
489 function mergeAndShowNotificationCards(notificationGroups, onCardShown) { | 423 function combineAndShowNotificationCards(notificationGroups, onCardShown) { |
490 var mergedCards = {}; | 424 console.log('combineAndShowNotificationCards ' + |
425 JSON.stringify(notificationGroups)); | |
426 /** @type {Object.<string, CombinedCard>} */ | |
427 var combinedCards = {}; | |
491 | 428 |
492 for (var groupName in notificationGroups) | 429 for (var groupName in notificationGroups) |
493 mergeGroup(mergedCards, notificationGroups[groupName]); | 430 combineGroup(combinedCards, notificationGroups[groupName]); |
494 | 431 |
495 showNotificationCards(mergedCards, onCardShown); | 432 showNotificationCards(combinedCards, onCardShown); |
496 } | 433 } |
497 | 434 |
498 /** | 435 /** |
499 * Parses JSON response from the notification server, shows notifications and | 436 * Parses JSON response from the notification server, shows notifications and |
500 * schedules next update. | 437 * schedules next update. |
501 * @param {string} response Server response. | 438 * @param {string} response Server response. |
502 * @param {function(CardCreateInfo)=} onCardShown Optional parameter called when | 439 * @param {function(ReceivedNotification)=} onCardShown Optional parameter |
503 * each card is shown. | 440 * called when each card is shown. |
504 */ | 441 */ |
505 function parseAndShowNotificationCards(response, onCardShown) { | 442 function parseAndShowNotificationCards(response, onCardShown) { |
robliao
2013/12/05 23:27:46
While we're here, it may be clearer to do somethin
vadimt
2013/12/06 02:32:38
I'd prefer to not do this now. I want to land this
rgustafson
2013/12/06 23:35:16
+1 on this.
vadimt
2013/12/06 23:52:58
Ack
| |
506 console.log('parseAndShowNotificationCards ' + response); | 443 console.log('parseAndShowNotificationCards ' + response); |
444 /** @type {ServerResponse} */ | |
507 var parsedResponse = JSON.parse(response); | 445 var parsedResponse = JSON.parse(response); |
508 | 446 |
509 if (parsedResponse.googleNowDisabled) { | 447 if (parsedResponse.googleNowDisabled) { |
510 chrome.storage.local.set({googleNowEnabled: false}); | 448 chrome.storage.local.set({googleNowEnabled: false}); |
511 // TODO(vadimt): Remove the line below once the server stops sending groups | 449 // TODO(vadimt): Remove the line below once the server stops sending groups |
512 // with 'googleNowDisabled' responses. | 450 // with 'googleNowDisabled' responses. |
513 parsedResponse.groups = {}; | 451 parsedResponse.groups = {}; |
514 // Google Now was enabled; now it's disabled. This is a state change. | 452 // Google Now was enabled; now it's disabled. This is a state change. |
515 onStateChange(); | 453 onStateChange(); |
516 } | 454 } |
517 | 455 |
518 var receivedGroups = parsedResponse.groups; | 456 var receivedGroups = parsedResponse.groups; |
519 | 457 |
520 // Populate groups with corresponding cards. | 458 instrumented.storage.local.get(['notificationGroups', 'recentDismissals'], |
521 if (parsedResponse.notifications) { | 459 function(items) { |
522 for (var i = 0; i != parsedResponse.notifications.length; ++i) { | |
523 var card = parsedResponse.notifications[i]; | |
524 var group = receivedGroups[card.groupName]; | |
525 group.cards = group.cards || []; | |
526 group.cards.push(card); | |
527 } | |
528 } | |
529 | |
530 instrumented.storage.local.get('notificationGroups', function(items) { | |
531 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items)); | 460 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items)); |
532 items = items || {}; | 461 items = items || {}; |
462 /** @type {Object.<string, StorageGroup>} */ | |
533 items.notificationGroups = items.notificationGroups || {}; | 463 items.notificationGroups = items.notificationGroups || {}; |
464 /** @type {Object.<string, number>} */ | |
465 items.recentDismissals = items.recentDismissals || {}; | |
534 | 466 |
467 // Build a set of non-expired recent dismissals. It will be used for | |
468 // client-side filtering of cards. | |
469 /** @type {Object.<string, number>} */ | |
470 var updatedRecentDismissals = {}; | |
535 var now = Date.now(); | 471 var now = Date.now(); |
472 for (var notificationId in items.recentDismissals) { | |
473 if (now - items.recentDismissals[notificationId] < | |
robliao
2013/12/05 23:27:46
Could be clearer to do...
var retentionTimeMs = n
vadimt
2013/12/06 02:32:38
Done.
| |
474 DISMISS_RETENTION_TIME_MS) { | |
475 updatedRecentDismissals[notificationId] = | |
476 items.recentDismissals[notificationId]; | |
477 } | |
478 } | |
479 | |
480 // Populate groups with corresponding cards. | |
481 if (parsedResponse.notifications) { | |
482 for (var i = 0; i != parsedResponse.notifications.length; ++i) { | |
483 /** @type {ReceivedNotification} */ | |
484 var card = parsedResponse.notifications[i]; | |
485 if (!(card.notificationId in updatedRecentDismissals)) { | |
486 var group = receivedGroups[card.groupName]; | |
487 group.cards = group.cards || []; | |
488 group.cards.push(card); | |
489 } | |
490 } | |
491 } | |
536 | 492 |
537 // Build updated set of groups. | 493 // Build updated set of groups. |
538 var updatedGroups = {}; | 494 var updatedGroups = {}; |
539 | 495 |
540 for (var groupName in receivedGroups) { | 496 for (var groupName in receivedGroups) { |
541 var receivedGroup = receivedGroups[groupName]; | 497 var receivedGroup = receivedGroups[groupName]; |
542 var storageGroup = items.notificationGroups[groupName] || { | 498 var storageGroup = items.notificationGroups[groupName] || { |
543 cards: [], | 499 cards: [], |
544 cardsTimestamp: undefined, | 500 cardsTimestamp: undefined, |
545 nextPollTime: undefined, | 501 nextPollTime: undefined, |
(...skipping 20 matching lines...) Expand all Loading... | |
566 // updates. | 522 // updates. |
567 if (receivedGroup.nextPollSeconds !== undefined) { | 523 if (receivedGroup.nextPollSeconds !== undefined) { |
568 storageGroup.nextPollTime = | 524 storageGroup.nextPollTime = |
569 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; | 525 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; |
570 } | 526 } |
571 | 527 |
572 updatedGroups[groupName] = storageGroup; | 528 updatedGroups[groupName] = storageGroup; |
573 } | 529 } |
574 | 530 |
575 scheduleNextPoll(updatedGroups, !parsedResponse.googleNowDisabled); | 531 scheduleNextPoll(updatedGroups, !parsedResponse.googleNowDisabled); |
576 chrome.storage.local.set({notificationGroups: updatedGroups}); | 532 chrome.storage.local.set({ |
577 mergeAndShowNotificationCards(updatedGroups, onCardShown); | 533 notificationGroups: updatedGroups, |
534 recentDismissals: updatedRecentDismissals | |
535 }); | |
536 combineAndShowNotificationCards(updatedGroups, onCardShown); | |
578 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); | 537 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); |
579 }); | 538 }); |
580 } | 539 } |
581 | 540 |
582 /** | 541 /** |
583 * Update Location Cards Shown Count. | 542 * Update Location Cards Shown Count. |
584 * @param {Object} cardCreateInfo Card Create Info | 543 * @param {ReceivedNotification} receivedNotification Notification as it was |
544 * received from the server. | |
585 */ | 545 */ |
586 function countLocationCard(cardCreateInfo) { | 546 function countLocationCard(receivedNotification) { |
587 if (cardCreateInfo.locationBased) { | 547 if (receivedNotification.locationBased) { |
588 localStorage['locationCardsShown']++; | 548 localStorage['locationCardsShown']++; |
589 } | 549 } |
590 } | 550 } |
591 | 551 |
592 /** | 552 /** |
593 * Requests notification cards from the server for specified groups. | 553 * Requests notification cards from the server for specified groups. |
594 * @param {Array.<string>} groupNames Names of groups that need to be refreshed. | 554 * @param {Array.<string>} groupNames Names of groups that need to be refreshed. |
595 */ | 555 */ |
596 function requestNotificationGroups(groupNames) { | 556 function requestNotificationGroups(groupNames) { |
597 console.log('requestNotificationGroups from ' + NOTIFICATION_CARDS_URL + | 557 console.log('requestNotificationGroups from ' + NOTIFICATION_CARDS_URL + |
(...skipping 15 matching lines...) Expand all Loading... | |
613 }); | 573 }); |
614 | 574 |
615 console.log('requestNotificationGroups: request=' + requestParameters); | 575 console.log('requestNotificationGroups: request=' + requestParameters); |
616 | 576 |
617 var request = buildServerRequest('GET', 'notifications' + requestParameters); | 577 var request = buildServerRequest('GET', 'notifications' + requestParameters); |
618 | 578 |
619 request.onloadend = function(event) { | 579 request.onloadend = function(event) { |
620 console.log('requestNotificationGroups-onloadend ' + request.status); | 580 console.log('requestNotificationGroups-onloadend ' + request.status); |
621 if (request.status == HTTP_OK) { | 581 if (request.status == HTTP_OK) { |
622 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); | 582 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); |
623 parseAndShowNotificationCards(request.response, cardShownCallback); | 583 parseAndShowNotificationCards(request.responseText, cardShownCallback); |
624 } | 584 } |
625 }; | 585 }; |
626 | 586 |
627 setAuthorization(request, function(success) { | 587 setAuthorization(request, function(success) { |
628 if (success) | 588 if (success) |
629 request.send(); | 589 request.send(); |
630 }); | 590 }); |
631 } | 591 } |
632 | 592 |
633 /** | 593 /** |
634 * Requests the account opted-in state from the server. | 594 * Requests the account opted-in state from the server. |
635 * @param {function()} optedInCallback Function that will be called if | 595 * @param {function()} optedInCallback Function that will be called if |
636 * opted-in state is 'true'. | 596 * opted-in state is 'true'. |
637 */ | 597 */ |
638 function requestOptedIn(optedInCallback) { | 598 function requestOptedIn(optedInCallback) { |
639 console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL); | 599 console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL); |
640 | 600 |
641 var request = buildServerRequest('GET', 'settings/optin'); | 601 var request = buildServerRequest('GET', 'settings/optin'); |
642 | 602 |
643 request.onloadend = function(event) { | 603 request.onloadend = function(event) { |
644 console.log( | 604 console.log( |
645 'requestOptedIn-onloadend ' + request.status + ' ' + request.response); | 605 'requestOptedIn-onloadend ' + request.status + ' ' + request.response); |
646 if (request.status == HTTP_OK) { | 606 if (request.status == HTTP_OK) { |
647 var parsedResponse = JSON.parse(request.response); | 607 var parsedResponse = JSON.parse(request.responseText); |
648 if (parsedResponse.value) { | 608 if (parsedResponse.value) { |
649 chrome.storage.local.set({googleNowEnabled: true}); | 609 chrome.storage.local.set({googleNowEnabled: true}); |
650 optedInCallback(); | 610 optedInCallback(); |
651 // Google Now was disabled, now it's enabled. This is a state change. | 611 // Google Now was disabled, now it's enabled. This is a state change. |
652 onStateChange(); | 612 onStateChange(); |
653 } else { | 613 } else { |
654 scheduleNextPoll({}, false); | 614 scheduleNextPoll({}, false); |
655 } | 615 } |
656 } | 616 } |
657 }; | 617 }; |
658 | 618 |
659 setAuthorization(request, function(success) { | 619 setAuthorization(request, function(success) { |
660 if (success) | 620 if (success) |
661 request.send(); | 621 request.send(); |
662 }); | 622 }); |
663 } | 623 } |
664 | 624 |
665 /** | 625 /** |
666 * Requests notification cards from the server. | 626 * Requests notification cards from the server. |
667 * @param {Location} position Location of this computer. | 627 * @param {Location=} position Location of this computer. |
668 */ | 628 */ |
669 function requestNotificationCards(position) { | 629 function requestNotificationCards(position) { |
670 console.log('requestNotificationCards ' + JSON.stringify(position)); | 630 console.log('requestNotificationCards ' + JSON.stringify(position)); |
671 | 631 |
672 instrumented.storage.local.get( | 632 instrumented.storage.local.get( |
673 ['notificationGroups', 'googleNowEnabled'], function(items) { | 633 ['notificationGroups', 'googleNowEnabled'], function(items) { |
674 console.log('requestNotificationCards-storage-get ' + | 634 console.log('requestNotificationCards-storage-get ' + |
675 JSON.stringify(items)); | 635 JSON.stringify(items)); |
676 items = items || {}; | 636 items = items || {}; |
637 /** @type {Object.<string, StorageGroup>} */ | |
638 items.notificationGroups = items.notificationGroups || {}; | |
677 | 639 |
678 var groupsToRequest = []; | 640 var groupsToRequest = []; |
679 | 641 |
680 if (items.notificationGroups) { | 642 var now = Date.now(); |
681 var now = Date.now(); | |
682 | 643 |
683 for (var groupName in items.notificationGroups) { | 644 for (var groupName in items.notificationGroups) { |
684 var group = items.notificationGroups[groupName]; | 645 var group = items.notificationGroups[groupName]; |
685 if (group.nextPollTime !== undefined && group.nextPollTime <= now) | 646 if (group.nextPollTime !== undefined && group.nextPollTime <= now) |
686 groupsToRequest.push(groupName); | 647 groupsToRequest.push(groupName); |
687 } | |
688 } | 648 } |
689 | 649 |
690 if (items.googleNowEnabled) { | 650 if (items.googleNowEnabled) { |
691 requestNotificationGroups(groupsToRequest); | 651 requestNotificationGroups(groupsToRequest); |
692 } else { | 652 } else { |
693 requestOptedIn(function() { | 653 requestOptedIn(function() { |
694 requestNotificationGroups(groupsToRequest); | 654 requestNotificationGroups(groupsToRequest); |
695 }); | 655 }); |
696 } | 656 } |
697 }); | 657 }); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
729 * Stops getting the location. | 689 * Stops getting the location. |
730 */ | 690 */ |
731 function stopRequestLocation() { | 691 function stopRequestLocation() { |
732 console.log('stopRequestLocation'); | 692 console.log('stopRequestLocation'); |
733 chrome.location.clearWatch(LOCATION_WATCH_NAME); | 693 chrome.location.clearWatch(LOCATION_WATCH_NAME); |
734 } | 694 } |
735 | 695 |
736 /** | 696 /** |
737 * Obtains new location; requests and shows notification cards based on this | 697 * Obtains new location; requests and shows notification cards based on this |
738 * location. | 698 * location. |
739 * @param {Location} position Location of this computer. | 699 * @param {Location=} position Location of this computer. |
740 */ | 700 */ |
741 function updateNotificationsCards(position) { | 701 function updateNotificationsCards(position) { |
742 console.log('updateNotificationsCards ' + JSON.stringify(position) + | 702 console.log('updateNotificationsCards ' + JSON.stringify(position) + |
743 ' @' + new Date()); | 703 ' @' + new Date()); |
744 tasks.add(UPDATE_CARDS_TASK_NAME, function() { | 704 tasks.add(UPDATE_CARDS_TASK_NAME, function() { |
745 console.log('updateNotificationsCards-task-begin'); | 705 console.log('updateNotificationsCards-task-begin'); |
746 updateCardsAttempts.isRunning(function(running) { | 706 updateCardsAttempts.isRunning(function(running) { |
747 if (running) { | 707 if (running) { |
748 updateCardsAttempts.planForNext(function() { | 708 updateCardsAttempts.planForNext(function() { |
749 processPendingDismissals(function(success) { | 709 processPendingDismissals(function(success) { |
(...skipping 12 matching lines...) Expand all Loading... | |
762 * Sends a server request to dismiss a card. | 722 * Sends a server request to dismiss a card. |
763 * @param {string} chromeNotificationId chrome.notifications ID of the card. | 723 * @param {string} chromeNotificationId chrome.notifications ID of the card. |
764 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in | 724 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in |
765 * milliseconds since epoch. | 725 * milliseconds since epoch. |
766 * @param {DismissalData} dismissalData Data to build a dismissal request. | 726 * @param {DismissalData} dismissalData Data to build a dismissal request. |
767 * @param {function(boolean)} callbackBoolean Completion callback with 'done' | 727 * @param {function(boolean)} callbackBoolean Completion callback with 'done' |
768 * parameter. | 728 * parameter. |
769 */ | 729 */ |
770 function requestCardDismissal( | 730 function requestCardDismissal( |
771 chromeNotificationId, dismissalTimeMs, dismissalData, callbackBoolean) { | 731 chromeNotificationId, dismissalTimeMs, dismissalData, callbackBoolean) { |
772 console.log('requestDismissingCard ' + chromeNotificationId + ' from ' + | 732 console.log('requestDismissingCard ' + chromeNotificationId + |
773 NOTIFICATION_CARDS_URL); | 733 ' from ' + NOTIFICATION_CARDS_URL + |
734 ', dismissalData=' + JSON.stringify(dismissalData)); | |
774 | 735 |
775 var dismissalAge = Date.now() - dismissalTimeMs; | 736 var dismissalAge = Date.now() - dismissalTimeMs; |
776 | 737 |
777 if (dismissalAge > MAXIMUM_DISMISSAL_AGE_MS) { | 738 if (dismissalAge > MAXIMUM_DISMISSAL_AGE_MS) { |
778 callbackBoolean(true); | 739 callbackBoolean(true); |
779 return; | 740 return; |
780 } | 741 } |
781 | 742 |
782 recordEvent(GoogleNowEvent.DISMISS_REQUEST_TOTAL); | 743 recordEvent(GoogleNowEvent.DISMISS_REQUEST_TOTAL); |
783 | 744 |
784 var request = 'notifications/' + dismissalData.notificationId + | 745 var requestParameters = 'notifications/' + dismissalData.notificationId + |
785 '?age=' + dismissalAge + | 746 '?age=' + dismissalAge + |
786 '&chromeNotificationId=' + chromeNotificationId; | 747 '&chromeNotificationId=' + chromeNotificationId; |
787 | 748 |
788 for (var paramField in dismissalData.parameters) | 749 for (var paramField in dismissalData.parameters) |
789 request += ('&' + paramField + '=' + dismissalData.parameters[paramField]); | 750 requestParameters += ('&' + paramField + |
751 '=' + dismissalData.parameters[paramField]); | |
790 | 752 |
791 console.log('requestCardDismissal: request=' + request); | 753 console.log('requestCardDismissal: requestParameters=' + requestParameters); |
792 | 754 |
793 var request = buildServerRequest('DELETE', request); | 755 var request = buildServerRequest('DELETE', requestParameters); |
794 request.onloadend = function(event) { | 756 request.onloadend = function(event) { |
795 console.log('requestDismissingCard-onloadend ' + request.status); | 757 console.log('requestDismissingCard-onloadend ' + request.status); |
796 if (request.status == HTTP_NOCONTENT) | 758 if (request.status == HTTP_NOCONTENT) |
797 recordEvent(GoogleNowEvent.DISMISS_REQUEST_SUCCESS); | 759 recordEvent(GoogleNowEvent.DISMISS_REQUEST_SUCCESS); |
798 | 760 |
799 // A dismissal doesn't require further retries if it was successful or | 761 // A dismissal doesn't require further retries if it was successful or |
800 // doesn't have a chance for successful completion. | 762 // doesn't have a chance for successful completion. |
801 var done = request.status == HTTP_NOCONTENT || | 763 var done = request.status == HTTP_NOCONTENT || |
802 request.status == HTTP_BAD_REQUEST || | 764 request.status == HTTP_BAD_REQUEST || |
803 request.status == HTTP_METHOD_NOT_ALLOWED; | 765 request.status == HTTP_METHOD_NOT_ALLOWED; |
(...skipping 12 matching lines...) Expand all Loading... | |
816 * Tries to send dismiss requests for all pending dismissals. | 778 * Tries to send dismiss requests for all pending dismissals. |
817 * @param {function(boolean)} callbackBoolean Completion callback with 'success' | 779 * @param {function(boolean)} callbackBoolean Completion callback with 'success' |
818 * parameter. Success means that no pending dismissals are left. | 780 * parameter. Success means that no pending dismissals are left. |
819 */ | 781 */ |
820 function processPendingDismissals(callbackBoolean) { | 782 function processPendingDismissals(callbackBoolean) { |
821 instrumented.storage.local.get(['pendingDismissals', 'recentDismissals'], | 783 instrumented.storage.local.get(['pendingDismissals', 'recentDismissals'], |
822 function(items) { | 784 function(items) { |
823 console.log('processPendingDismissals-storage-get ' + | 785 console.log('processPendingDismissals-storage-get ' + |
824 JSON.stringify(items)); | 786 JSON.stringify(items)); |
825 items = items || {}; | 787 items = items || {}; |
788 /** @type {Array.<PendingDismissal>} */ | |
826 items.pendingDismissals = items.pendingDismissals || []; | 789 items.pendingDismissals = items.pendingDismissals || []; |
790 /** @type {Object.<string, number>} */ | |
827 items.recentDismissals = items.recentDismissals || {}; | 791 items.recentDismissals = items.recentDismissals || {}; |
828 | 792 |
829 var dismissalsChanged = false; | 793 var dismissalsChanged = false; |
830 | 794 |
831 function onFinish(success) { | 795 function onFinish(success) { |
832 if (dismissalsChanged) { | 796 if (dismissalsChanged) { |
833 chrome.storage.local.set({ | 797 chrome.storage.local.set({ |
834 pendingDismissals: items.pendingDismissals, | 798 pendingDismissals: items.pendingDismissals, |
835 recentDismissals: items.recentDismissals | 799 recentDismissals: items.recentDismissals |
836 }); | 800 }); |
837 } | 801 } |
838 callbackBoolean(success); | 802 callbackBoolean(success); |
839 } | 803 } |
840 | 804 |
841 function doProcessDismissals() { | 805 function doProcessDismissals() { |
842 if (items.pendingDismissals.length == 0) { | 806 if (items.pendingDismissals.length == 0) { |
843 dismissalAttempts.stop(); | 807 dismissalAttempts.stop(); |
844 onFinish(true); | 808 onFinish(true); |
845 return; | 809 return; |
846 } | 810 } |
847 | 811 |
848 // Send dismissal for the first card, and if successful, repeat | 812 // Send dismissal for the first card, and if successful, repeat |
849 // recursively with the rest. | 813 // recursively with the rest. |
814 /** @type {PendingDismissal} */ | |
850 var dismissal = items.pendingDismissals[0]; | 815 var dismissal = items.pendingDismissals[0]; |
851 requestCardDismissal( | 816 requestCardDismissal( |
852 dismissal.chromeNotificationId, | 817 dismissal.chromeNotificationId, |
853 dismissal.time, | 818 dismissal.time, |
854 dismissal.dismissalData, | 819 dismissal.dismissalData, |
855 function(done) { | 820 function(done) { |
856 if (done) { | 821 if (done) { |
857 dismissalsChanged = true; | 822 dismissalsChanged = true; |
858 items.pendingDismissals.splice(0, 1); | 823 items.pendingDismissals.splice(0, 1); |
859 items.recentDismissals[dismissal.chromeNotificationId] = | 824 items.recentDismissals[ |
825 dismissal.dismissalData.notificationId] = | |
860 Date.now(); | 826 Date.now(); |
861 doProcessDismissals(); | 827 doProcessDismissals(); |
862 } else { | 828 } else { |
863 onFinish(false); | 829 onFinish(false); |
864 } | 830 } |
865 }); | 831 }); |
866 } | 832 } |
867 | 833 |
868 doProcessDismissals(); | 834 doProcessDismissals(); |
869 }); | 835 }); |
(...skipping 19 matching lines...) Expand all Loading... | |
889 if (tab) | 855 if (tab) |
890 chrome.windows.update(tab.windowId, {focused: true}); | 856 chrome.windows.update(tab.windowId, {focused: true}); |
891 else | 857 else |
892 chrome.windows.create({url: url, focused: true}); | 858 chrome.windows.create({url: url, focused: true}); |
893 }); | 859 }); |
894 } | 860 } |
895 | 861 |
896 /** | 862 /** |
897 * Opens URL corresponding to the clicked part of the notification. | 863 * Opens URL corresponding to the clicked part of the notification. |
898 * @param {string} chromeNotificationId chrome.notifications ID of the card. | 864 * @param {string} chromeNotificationId chrome.notifications ID of the card. |
899 * @param {function(Object): string} selector Function that extracts the url for | 865 * @param {function((ActionUrls|undefined)): (string|undefined)} selector |
900 * the clicked area from the button action URLs info. | 866 * Function that extracts the url for the clicked area from the button |
867 * action URLs info. | |
901 */ | 868 */ |
902 function onNotificationClicked(chromeNotificationId, selector) { | 869 function onNotificationClicked(chromeNotificationId, selector) { |
903 instrumented.storage.local.get('notificationsData', function(items) { | 870 instrumented.storage.local.get('notificationsData', function(items) { |
871 /** @type {(NotificationDataEntry|undefined)} */ | |
904 var notificationData = items && | 872 var notificationData = items && |
905 items.notificationsData && | 873 items.notificationsData && |
906 items.notificationsData[chromeNotificationId]; | 874 items.notificationsData[chromeNotificationId]; |
907 | 875 |
908 if (!notificationData) | 876 if (!notificationData) |
909 return; | 877 return; |
910 | 878 |
911 var url = selector(notificationData.actionUrls); | 879 var url = selector(notificationData.actionUrls); |
912 if (!url) | 880 if (!url) |
913 return; | 881 return; |
(...skipping 13 matching lines...) Expand all Loading... | |
927 | 895 |
928 // At this point we are guaranteed that the notification is a now card. | 896 // At this point we are guaranteed that the notification is a now card. |
929 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); | 897 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); |
930 | 898 |
931 tasks.add(DISMISS_CARD_TASK_NAME, function() { | 899 tasks.add(DISMISS_CARD_TASK_NAME, function() { |
932 dismissalAttempts.start(); | 900 dismissalAttempts.start(); |
933 | 901 |
934 instrumented.storage.local.get( | 902 instrumented.storage.local.get( |
935 ['pendingDismissals', 'notificationsData'], function(items) { | 903 ['pendingDismissals', 'notificationsData'], function(items) { |
936 items = items || {}; | 904 items = items || {}; |
905 /** @type {Array.<PendingDismissal>} */ | |
937 items.pendingDismissals = items.pendingDismissals || []; | 906 items.pendingDismissals = items.pendingDismissals || []; |
907 /** @type {Object.<string, NotificationDataEntry>} */ | |
938 items.notificationsData = items.notificationsData || {}; | 908 items.notificationsData = items.notificationsData || {}; |
939 | 909 |
940 // Deleting the notification in case it was re-added while this task was | 910 /** @type {NotificationDataEntry} */ |
941 // scheduled, waiting for execution; also cleaning notification's data | 911 var notificationData = items.notificationsData[chromeNotificationId] || { |
942 // from storage. | 912 timestamp: Date.now(), |
943 cardSet.clear(chromeNotificationId, true); | 913 combinedCard: [] |
914 }; | |
944 | 915 |
945 var notificationData = items.notificationsData[chromeNotificationId]; | 916 var dismissalResult = |
917 cardSet.onDismissal(chromeNotificationId, notificationData); | |
946 | 918 |
947 if (notificationData && notificationData.dismissals) { | 919 for (var i = 0; i < dismissalResult.dismissals.length; i++) { |
948 for (var i = 0; i < notificationData.dismissals.length; i++) { | 920 /** @type {PendingDismissal} */ |
949 var dismissal = { | 921 var dismissal = { |
950 chromeNotificationId: chromeNotificationId, | 922 chromeNotificationId: chromeNotificationId, |
951 time: Date.now(), | 923 time: Date.now(), |
952 dismissalData: notificationData.dismissals[i] | 924 dismissalData: dismissalResult.dismissals[i] |
953 }; | 925 }; |
954 items.pendingDismissals.push(dismissal); | 926 items.pendingDismissals.push(dismissal); |
955 } | 927 } |
956 | 928 |
957 chrome.storage.local.set({pendingDismissals: items.pendingDismissals}); | 929 items.notificationsData[chromeNotificationId] = |
958 } | 930 dismissalResult.notificationData; |
931 | |
932 chrome.storage.local.set({ | |
933 pendingDismissals: items.pendingDismissals, | |
934 notificationsData: items.notificationsData | |
935 }); | |
959 | 936 |
960 processPendingDismissals(function(success) {}); | 937 processPendingDismissals(function(success) {}); |
961 }); | 938 }); |
962 }); | 939 }); |
963 } | 940 } |
964 | 941 |
965 /** | 942 /** |
966 * Initializes the polling system to start monitoring location and fetching | 943 * Initializes the polling system to start monitoring location and fetching |
967 * cards. | 944 * cards. |
968 */ | 945 */ |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1133 instrumented.runtime.onStartup.addListener(function() { | 1110 instrumented.runtime.onStartup.addListener(function() { |
1134 console.log('onStartup'); | 1111 console.log('onStartup'); |
1135 | 1112 |
1136 // Show notifications received by earlier polls. Doing this as early as | 1113 // Show notifications received by earlier polls. Doing this as early as |
1137 // possible to reduce latency of showing first notifications. This mimics how | 1114 // possible to reduce latency of showing first notifications. This mimics how |
1138 // persistent notifications will work. | 1115 // persistent notifications will work. |
1139 tasks.add(SHOW_ON_START_TASK_NAME, function() { | 1116 tasks.add(SHOW_ON_START_TASK_NAME, function() { |
1140 instrumented.storage.local.get('notificationGroups', function(items) { | 1117 instrumented.storage.local.get('notificationGroups', function(items) { |
1141 console.log('onStartup-get ' + JSON.stringify(items)); | 1118 console.log('onStartup-get ' + JSON.stringify(items)); |
1142 items = items || {}; | 1119 items = items || {}; |
1120 /** @type {Object.<string, StorageGroup>} */ | |
1143 items.notificationGroups = items.notificationGroups || {}; | 1121 items.notificationGroups = items.notificationGroups || {}; |
1144 | 1122 |
1145 mergeAndShowNotificationCards(items.notificationGroups); | 1123 combineAndShowNotificationCards(items.notificationGroups); |
1146 }); | 1124 }); |
1147 }); | 1125 }); |
1148 | 1126 |
1149 initialize(); | 1127 initialize(); |
1150 }); | 1128 }); |
1151 | 1129 |
1152 instrumented. | 1130 instrumented. |
1153 preferencesPrivate. | 1131 preferencesPrivate. |
1154 googleGeolocationAccessEnabled. | 1132 googleGeolocationAccessEnabled. |
1155 onChange. | 1133 onChange. |
(...skipping 15 matching lines...) Expand all Loading... | |
1171 return actionUrls && actionUrls.messageUrl; | 1149 return actionUrls && actionUrls.messageUrl; |
1172 }); | 1150 }); |
1173 }); | 1151 }); |
1174 | 1152 |
1175 instrumented.notifications.onButtonClicked.addListener( | 1153 instrumented.notifications.onButtonClicked.addListener( |
1176 function(chromeNotificationId, buttonIndex) { | 1154 function(chromeNotificationId, buttonIndex) { |
1177 chrome.metricsPrivate.recordUserAction( | 1155 chrome.metricsPrivate.recordUserAction( |
1178 'GoogleNow.ButtonClicked' + buttonIndex); | 1156 'GoogleNow.ButtonClicked' + buttonIndex); |
1179 onNotificationClicked(chromeNotificationId, function(actionUrls) { | 1157 onNotificationClicked(chromeNotificationId, function(actionUrls) { |
1180 var url = actionUrls.buttonUrls[buttonIndex]; | 1158 var url = actionUrls.buttonUrls[buttonIndex]; |
1181 verify(url, 'onButtonClicked: no url for a button'); | 1159 verify(url !== undefined, 'onButtonClicked: no url for a button'); |
1182 return url; | 1160 return url; |
1183 }); | 1161 }); |
1184 }); | 1162 }); |
1185 | 1163 |
1186 instrumented.notifications.onClosed.addListener(onNotificationClosed); | 1164 instrumented.notifications.onClosed.addListener(onNotificationClosed); |
1187 | 1165 |
1188 instrumented.notifications.onPermissionLevelChanged.addListener( | 1166 instrumented.notifications.onPermissionLevelChanged.addListener( |
1189 function(permissionLevel) { | 1167 function(permissionLevel) { |
1190 console.log('Notifications permissionLevel Change'); | 1168 console.log('Notifications permissionLevel Change'); |
1191 onStateChange(); | 1169 onStateChange(); |
(...skipping 23 matching lines...) Expand all Loading... | |
1215 if (!items) | 1193 if (!items) |
1216 return; | 1194 return; |
1217 | 1195 |
1218 // If this is the first time we get lastPollNowPayloads, initialize it. | 1196 // If this is the first time we get lastPollNowPayloads, initialize it. |
1219 items.lastPollNowPayloads = items.lastPollNowPayloads || {}; | 1197 items.lastPollNowPayloads = items.lastPollNowPayloads || {}; |
1220 | 1198 |
1221 if (items.lastPollNowPayloads[message.subchannelId] != | 1199 if (items.lastPollNowPayloads[message.subchannelId] != |
1222 message.payload) { | 1200 message.payload) { |
1223 items.lastPollNowPayloads[message.subchannelId] = message.payload; | 1201 items.lastPollNowPayloads[message.subchannelId] = message.payload; |
1224 | 1202 |
1203 /** @type {Object.<string, StorageGroup>} */ | |
1225 items.notificationGroups = items.notificationGroups || {}; | 1204 items.notificationGroups = items.notificationGroups || {}; |
1226 items.notificationGroups['PUSH' + message.subchannelId] = { | 1205 items.notificationGroups['PUSH' + message.subchannelId] = { |
1227 cards: [], | 1206 cards: [], |
1228 nextPollTime: Date.now() | 1207 nextPollTime: Date.now() |
1229 }; | 1208 }; |
1230 | 1209 |
1231 chrome.storage.local.set({ | 1210 chrome.storage.local.set({ |
1232 lastPollNowPayloads: items.lastPollNowPayloads, | 1211 lastPollNowPayloads: items.lastPollNowPayloads, |
1233 notificationGroups: items.notificationGroups | 1212 notificationGroups: items.notificationGroups |
1234 }); | 1213 }); |
1235 | 1214 |
1236 updateNotificationsCards(); | 1215 updateNotificationsCards(); |
1237 } | 1216 } |
1238 }); | 1217 }); |
1239 }); | 1218 }); |
1240 } | 1219 } |
1241 }); | 1220 }); |
OLD | NEW |