Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: chrome/browser/resources/google_now/background.js

Issue 27030012: Restoring notifications on startup (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More rgustafson's comments Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/browser/resources/google_now/background_unittest.gtestjs » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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.
11 * The service performs periodic updating of Google Now cards. 11 * The service performs periodic updating of Google Now cards.
12 * Each updating of the cards includes 4 steps: 12 * Each updating of the cards includes 4 steps:
13 * 1. Obtaining the location of the machine; 13 * 1. Obtaining the location of the machine;
14 * 2. Processing requests for cards dismissals that are not yet sent to the 14 * 2. Processing requests for cards dismissals that are not yet sent to the
15 * server; 15 * server;
16 * 3. Making a server request based on that location; 16 * 3. Making a server request based on that location;
17 * 4. Showing the received cards as notifications. 17 * 4. Showing the received cards as notifications.
18 */ 18 */
19 19
20 // TODO(vadimt): Decide what to do in incognito mode. 20 // TODO(vadimt): Decide what to do in incognito mode.
21 // TODO(vadimt): Figure out the final values of the constants. 21 // TODO(vadimt): Figure out the final values of the constants.
22 // TODO(vadimt): Remove 'console' calls. 22 // TODO(vadimt): Remove 'console' calls.
23 // TODO(vadimt): Consider sending JS stacks for malformed server responses.
24 23
25 /** 24 /**
26 * Standard response code for successful HTTP requests. This is the only success 25 * Standard response code for successful HTTP requests. This is the only success
27 * code the server will send. 26 * code the server will send.
28 */ 27 */
29 var HTTP_OK = 200; 28 var HTTP_OK = 200;
30 var HTTP_NOCONTENT = 204; 29 var HTTP_NOCONTENT = 204;
31 30
32 var HTTP_BAD_REQUEST = 400; 31 var HTTP_BAD_REQUEST = 400;
33 var HTTP_UNAUTHORIZED = 401; 32 var HTTP_UNAUTHORIZED = 401;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 */ 73 */
75 var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000; // 20 minutes 74 var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000; // 20 minutes
76 75
77 /** 76 /**
78 * Names for tasks that can be created by the extension. 77 * Names for tasks that can be created by the extension.
79 */ 78 */
80 var UPDATE_CARDS_TASK_NAME = 'update-cards'; 79 var UPDATE_CARDS_TASK_NAME = 'update-cards';
81 var DISMISS_CARD_TASK_NAME = 'dismiss-card'; 80 var DISMISS_CARD_TASK_NAME = 'dismiss-card';
82 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; 81 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss';
83 var STATE_CHANGED_TASK_NAME = 'state-changed'; 82 var STATE_CHANGED_TASK_NAME = 'state-changed';
83 var SHOW_ON_START_TASK_NAME = 'show-cards-on-start';
84 84
85 var LOCATION_WATCH_NAME = 'location-watch'; 85 var LOCATION_WATCH_NAME = 'location-watch';
86 86
87 var WELCOME_TOAST_NOTIFICATION_ID = 'enable-now-toast'; 87 var WELCOME_TOAST_NOTIFICATION_ID = 'enable-now-toast';
88 88
89 /** 89 /**
90 * The indices of the buttons that are displayed on the welcome toast. 90 * The indices of the buttons that are displayed on the welcome toast.
91 * @enum {number} 91 * @enum {number}
92 */ 92 */
93 var ToastButtonIndex = {YES: 0, NO: 1}; 93 var ToastButtonIndex = {YES: 0, NO: 1};
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 var previousVersion = notifications[chromeNotificationId] && 310 var previousVersion = notifications[chromeNotificationId] &&
311 notificationData && 311 notificationData &&
312 notificationData.cardCreateInfo && 312 notificationData.cardCreateInfo &&
313 notificationData.cardCreateInfo.version; 313 notificationData.cardCreateInfo.version;
314 newNotificationsData[chromeNotificationId] = cardSet.update( 314 newNotificationsData[chromeNotificationId] = cardSet.update(
315 chromeNotificationId, 315 chromeNotificationId,
316 cards[chromeNotificationId], 316 cards[chromeNotificationId],
317 previousVersion); 317 previousVersion);
318 } 318 }
319 319
320 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS);
321
322 chrome.storage.local.set({ 320 chrome.storage.local.set({
323 notificationsData: newNotificationsData, 321 notificationsData: newNotificationsData,
324 recentDismissals: updatedRecentDismissals 322 recentDismissals: updatedRecentDismissals
325 }); 323 });
326 }); 324 });
327 }); 325 });
328 } 326 }
329 327
330 /** 328 /**
331 * Removes all cards and card state on Google Now close down. 329 * Removes all cards and card state on Google Now close down.
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 438
441 verify(nextPollTime != null, 'scheduleNextPoll: nextPollTime is null'); 439 verify(nextPollTime != null, 'scheduleNextPoll: nextPollTime is null');
442 440
443 var nextPollDelaySeconds = Math.max( 441 var nextPollDelaySeconds = Math.max(
444 (nextPollTime - Date.now()) / MS_IN_SECOND, 442 (nextPollTime - Date.now()) / MS_IN_SECOND,
445 MINIMUM_POLLING_PERIOD_SECONDS); 443 MINIMUM_POLLING_PERIOD_SECONDS);
446 updateCardsAttempts.start(nextPollDelaySeconds); 444 updateCardsAttempts.start(nextPollDelaySeconds);
447 } 445 }
448 446
449 /** 447 /**
448 * Merges notification groups into a set of Chrome notifications and shows them.
449 * @param {Object.<string, StorageGroup>} notificationGroups Map from group name
450 * to group information.
451 */
452 function mergeAndShowNotificationCards(notificationGroups) {
453 var mergedCards = {};
454
455 for (var groupName in notificationGroups)
456 mergeGroup(mergedCards, notificationGroups[groupName]);
457
458 showNotificationCards(mergedCards);
459 }
460
461 /**
450 * Parses JSON response from the notification server, shows notifications and 462 * Parses JSON response from the notification server, shows notifications and
451 * schedules next update. 463 * schedules next update.
452 * @param {string} response Server response. 464 * @param {string} response Server response.
453 */ 465 */
454 function parseAndShowNotificationCards(response) { 466 function parseAndShowNotificationCards(response) {
455 console.log('parseAndShowNotificationCards ' + response); 467 console.log('parseAndShowNotificationCards ' + response);
456 var parsedResponse = JSON.parse(response); 468 var parsedResponse = JSON.parse(response);
457 469
458 var groups = parsedResponse.groups; 470 var receivedGroups = parsedResponse.groups;
459 471
460 // Populate groups with corresponding cards. 472 // Populate groups with corresponding cards.
461 if (parsedResponse.notifications) { 473 if (parsedResponse.notifications) {
462 for (var i = 0; i != parsedResponse.notifications.length; ++i) { 474 for (var i = 0; i != parsedResponse.notifications.length; ++i) {
463 var card = parsedResponse.notifications[i]; 475 var card = parsedResponse.notifications[i];
464 var group = groups[card.groupName]; 476 var group = receivedGroups[card.groupName];
465 group.cards = group.cards || []; 477 group.cards = group.cards || [];
466 group.cards.push(card); 478 group.cards.push(card);
467 } 479 }
468 } 480 }
469 481
470 instrumented.storage.local.get('notificationGroups', function(items) { 482 instrumented.storage.local.get('notificationGroups', function(items) {
471 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items)); 483 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items));
472 items = items || {}; 484 items = items || {};
473 items.notificationGroups = items.notificationGroups || {}; 485 items.notificationGroups = items.notificationGroups || {};
474 486
475 var now = Date.now(); 487 var now = Date.now();
476 488
477 // Build updated set of groups and merge cards from all groups into one set. 489 // Build updated set of groups.
478 var updatedGroups = {}; 490 var updatedGroups = {};
479 var mergedCards = {};
480 491
481 for (var groupName in groups) { 492 for (var groupName in receivedGroups) {
482 var receivedGroup = groups[groupName]; 493 var receivedGroup = receivedGroups[groupName];
483 var storageGroup = items.notificationGroups[groupName] || { 494 var storageGroup = items.notificationGroups[groupName] || {
484 cards: [], 495 cards: [],
485 cardsTimestamp: undefined, 496 cardsTimestamp: undefined,
486 nextPollTime: now, 497 nextPollTime: now,
487 rank: undefined 498 rank: undefined
488 }; 499 };
489 500
490 if (receivedGroup.requested) 501 if (receivedGroup.requested)
491 receivedGroup.cards = receivedGroup.cards || []; 502 receivedGroup.cards = receivedGroup.cards || [];
492 503
493 if (receivedGroup.cards) { 504 if (receivedGroup.cards) {
494 storageGroup.cards = receivedGroup.cards; 505 storageGroup.cards = receivedGroup.cards;
495 storageGroup.cardsTimestamp = now; 506 storageGroup.cardsTimestamp = now;
496 storageGroup.rank = receivedGroup.rank; 507 storageGroup.rank = receivedGroup.rank;
497 } 508 }
498 509
499 if (receivedGroup.nextPollSeconds !== undefined) { 510 if (receivedGroup.nextPollSeconds !== undefined) {
500 storageGroup.nextPollTime = 511 storageGroup.nextPollTime =
501 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; 512 now + receivedGroup.nextPollSeconds * MS_IN_SECOND;
502 } 513 }
503 514
504 updatedGroups[groupName] = storageGroup; 515 updatedGroups[groupName] = storageGroup;
505
506 mergeGroup(mergedCards, storageGroup);
507 } 516 }
508 517
509 scheduleNextPoll(updatedGroups); 518 scheduleNextPoll(updatedGroups);
510
511 chrome.storage.local.set({notificationGroups: updatedGroups}); 519 chrome.storage.local.set({notificationGroups: updatedGroups});
512 520 mergeAndShowNotificationCards(updatedGroups);
513 showNotificationCards(mergedCards); 521 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS);
514 }); 522 });
515 } 523 }
516 524
517 /** 525 /**
518 * Requests notification cards from the server. 526 * Requests notification cards from the server.
519 * @param {Location} position Location of this computer. 527 * @param {Location} position Location of this computer.
520 */ 528 */
521 function requestNotificationCards(position) { 529 function requestNotificationCards(position) {
522 console.log('requestNotificationCards ' + JSON.stringify(position) + 530 console.log('requestNotificationCards ' + JSON.stringify(position) +
523 ' from ' + NOTIFICATION_CARDS_URL); 531 ' from ' + NOTIFICATION_CARDS_URL);
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
869 updateCardsAttempts.stop(); 877 updateCardsAttempts.stop();
870 878
871 removeAllCards(); 879 removeAllCards();
872 } 880 }
873 881
874 /** 882 /**
875 * Initializes the event page on install or on browser startup. 883 * Initializes the event page on install or on browser startup.
876 */ 884 */
877 function initialize() { 885 function initialize() {
878 recordEvent(GoogleNowEvent.EXTENSION_START); 886 recordEvent(GoogleNowEvent.EXTENSION_START);
879
880 // Alarms persist across chrome restarts. This is undesirable since it
881 // prevents us from starting up everything (alarms are a heuristic to
882 // determine if we are already running). To mitigate this, we will
883 // shut everything down on initialize before starting everything up.
884 stopPollingCards();
885 onStateChange(); 887 onStateChange();
886 } 888 }
887 889
888 /** 890 /**
889 * Starts or stops the polling of cards. 891 * Starts or stops the polling of cards.
890 * @param {boolean} shouldPollCardsRequest true to start and 892 * @param {boolean} shouldPollCardsRequest true to start and
891 * false to stop polling cards. 893 * false to stop polling cards.
892 */ 894 */
893 function setShouldPollCards(shouldPollCardsRequest) { 895 function setShouldPollCards(shouldPollCardsRequest) {
894 updateCardsAttempts.isRunning(function(currentValue) { 896 updateCardsAttempts.isRunning(function(currentValue) {
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1078 1080
1079 instrumented.runtime.onInstalled.addListener(function(details) { 1081 instrumented.runtime.onInstalled.addListener(function(details) {
1080 console.log('onInstalled ' + JSON.stringify(details)); 1082 console.log('onInstalled ' + JSON.stringify(details));
1081 if (details.reason != 'chrome_update') { 1083 if (details.reason != 'chrome_update') {
1082 initialize(); 1084 initialize();
1083 } 1085 }
1084 }); 1086 });
1085 1087
1086 instrumented.runtime.onStartup.addListener(function() { 1088 instrumented.runtime.onStartup.addListener(function() {
1087 console.log('onStartup'); 1089 console.log('onStartup');
1090
1091 // Show notifications received by earlier polls. Doing this as early as
1092 // possible to reduce latency of showing first notifications. This mimics how
1093 // persistent notifications will work.
1094 tasks.add(SHOW_ON_START_TASK_NAME, function() {
1095 instrumented.storage.local.get('notificationGroups', function(items) {
1096 console.log('onStartup-get ' + JSON.stringify(items));
1097 items = items || {};
1098 items.notificationGroups = items.notificationGroups || {};
1099
1100 mergeAndShowNotificationCards(items.notificationGroups);
1101 });
1102 });
1103
1088 initialize(); 1104 initialize();
1089 }); 1105 });
1090 1106
1091 instrumented. 1107 instrumented.
1092 preferencesPrivate. 1108 preferencesPrivate.
1093 googleGeolocationAccessEnabled. 1109 googleGeolocationAccessEnabled.
1094 onChange. 1110 onChange.
1095 addListener(function(prefValue) { 1111 addListener(function(prefValue) {
1096 console.log('googleGeolocationAccessEnabled Pref onChange ' + 1112 console.log('googleGeolocationAccessEnabled Pref onChange ' +
1097 prefValue.value); 1113 prefValue.value);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1130 1146
1131 instrumented.location.onLocationUpdate.addListener(function(position) { 1147 instrumented.location.onLocationUpdate.addListener(function(position) {
1132 recordEvent(GoogleNowEvent.LOCATION_UPDATE); 1148 recordEvent(GoogleNowEvent.LOCATION_UPDATE);
1133 updateNotificationsCards(position); 1149 updateNotificationsCards(position);
1134 }); 1150 });
1135 1151
1136 instrumented.omnibox.onInputEntered.addListener(function(text) { 1152 instrumented.omnibox.onInputEntered.addListener(function(text) {
1137 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; 1153 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text;
1138 initialize(); 1154 initialize();
1139 }); 1155 });
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/google_now/background_unittest.gtestjs » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698