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

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

Issue 2617663002: WIP: run clang-format-js on lots of things (Closed)
Patch Set: merge Created 3 years, 11 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
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.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 var INITIAL_RETRY_DISMISS_PERIOD_SECONDS = 60; // 1 minute 69 var INITIAL_RETRY_DISMISS_PERIOD_SECONDS = 60; // 1 minute
70 70
71 /** 71 /**
72 * Maximum period for retrying the server request for dismissing cards. 72 * Maximum period for retrying the server request for dismissing cards.
73 */ 73 */
74 var MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS = 60 * 60; // 1 hour 74 var MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS = 60 * 60; // 1 hour
75 75
76 /** 76 /**
77 * Time we keep retrying dismissals. 77 * Time we keep retrying dismissals.
78 */ 78 */
79 var MAXIMUM_DISMISSAL_AGE_MS = 24 * 60 * 60 * 1000; // 1 day 79 var MAXIMUM_DISMISSAL_AGE_MS = 24 * 60 * 60 * 1000; // 1 day
80 80
81 /** 81 /**
82 * Time we keep dismissals after successful server dismiss requests. 82 * Time we keep dismissals after successful server dismiss requests.
83 */ 83 */
84 var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000; // 20 minutes 84 var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000; // 20 minutes
85 85
86 /** 86 /**
87 * Default period for checking whether the user is opted in to Google Now. 87 * Default period for checking whether the user is opted in to Google Now.
88 */ 88 */
89 var DEFAULT_OPTIN_CHECK_PERIOD_SECONDS = 60 * 60 * 24 * 7; // 1 week 89 var DEFAULT_OPTIN_CHECK_PERIOD_SECONDS = 60 * 60 * 24 * 7; // 1 week
90 90
91 /** 91 /**
92 * URL to open when the user clicked on a link for the our notification 92 * URL to open when the user clicked on a link for the our notification
93 * settings. 93 * settings.
94 */ 94 */
95 var SETTINGS_URL = 'https://support.google.com/chrome/?p=ib_google_now_welcome'; 95 var SETTINGS_URL = 'https://support.google.com/chrome/?p=ib_google_now_welcome';
96 96
97 /** 97 /**
98 * GCM registration URL. 98 * GCM registration URL.
99 */ 99 */
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 'notifications.onPermissionLevelChanged.addListener', 0); 217 'notifications.onPermissionLevelChanged.addListener', 0);
218 wrapper.instrumentChromeApiFunction( 218 wrapper.instrumentChromeApiFunction(
219 'notifications.onShowSettings.addListener', 0); 219 'notifications.onShowSettings.addListener', 0);
220 wrapper.instrumentChromeApiFunction('permissions.contains', 1); 220 wrapper.instrumentChromeApiFunction('permissions.contains', 1);
221 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0); 221 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0);
222 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0); 222 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0);
223 wrapper.instrumentChromeApiFunction('storage.onChanged.addListener', 0); 223 wrapper.instrumentChromeApiFunction('storage.onChanged.addListener', 0);
224 wrapper.instrumentChromeApiFunction('tabs.create', 1); 224 wrapper.instrumentChromeApiFunction('tabs.create', 1);
225 225
226 var updateCardsAttempts = buildAttemptManager( 226 var updateCardsAttempts = buildAttemptManager(
227 'cards-update', 227 'cards-update', requestCards, INITIAL_POLLING_PERIOD_SECONDS,
228 requestCards,
229 INITIAL_POLLING_PERIOD_SECONDS,
230 MAXIMUM_POLLING_PERIOD_SECONDS); 228 MAXIMUM_POLLING_PERIOD_SECONDS);
231 var optInPollAttempts = buildAttemptManager( 229 var optInPollAttempts = buildAttemptManager(
232 'optin', 230 'optin', pollOptedInNoImmediateRecheck, INITIAL_POLLING_PERIOD_SECONDS,
233 pollOptedInNoImmediateRecheck,
234 INITIAL_POLLING_PERIOD_SECONDS,
235 MAXIMUM_POLLING_PERIOD_SECONDS); 231 MAXIMUM_POLLING_PERIOD_SECONDS);
236 var optInRecheckAttempts = buildAttemptManager( 232 var optInRecheckAttempts = buildAttemptManager(
237 'optin-recheck', 233 'optin-recheck', pollOptedInWithRecheck,
238 pollOptedInWithRecheck, 234 INITIAL_OPTIN_RECHECK_PERIOD_SECONDS, MAXIMUM_OPTIN_RECHECK_PERIOD_SECONDS);
239 INITIAL_OPTIN_RECHECK_PERIOD_SECONDS,
240 MAXIMUM_OPTIN_RECHECK_PERIOD_SECONDS);
241 var dismissalAttempts = buildAttemptManager( 235 var dismissalAttempts = buildAttemptManager(
242 'dismiss', 236 'dismiss', retryPendingDismissals, INITIAL_RETRY_DISMISS_PERIOD_SECONDS,
243 retryPendingDismissals,
244 INITIAL_RETRY_DISMISS_PERIOD_SECONDS,
245 MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS); 237 MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS);
246 var cardSet = buildCardSet(); 238 var cardSet = buildCardSet();
247 239
248 var authenticationManager = buildAuthenticationManager(); 240 var authenticationManager = buildAuthenticationManager();
249 241
250 /** 242 /**
251 * Google Now UMA event identifier. 243 * Google Now UMA event identifier.
252 * @enum {number} 244 * @enum {number}
253 */ 245 */
254 var GoogleNowEvent = { 246 var GoogleNowEvent = {
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 * called when each card is shown. 353 * called when each card is shown.
362 * @return {Promise} A promise to show the notification groups as cards. 354 * @return {Promise} A promise to show the notification groups as cards.
363 */ 355 */
364 function showNotificationGroups(notificationGroups, opt_onCardShown) { 356 function showNotificationGroups(notificationGroups, opt_onCardShown) {
365 /** @type {Object<ChromeNotificationId, CombinedCard>} */ 357 /** @type {Object<ChromeNotificationId, CombinedCard>} */
366 var cards = combineCardsFromGroups(notificationGroups); 358 var cards = combineCardsFromGroups(notificationGroups);
367 console.log('showNotificationGroups ' + JSON.stringify(cards)); 359 console.log('showNotificationGroups ' + JSON.stringify(cards));
368 360
369 return new Promise(function(resolve) { 361 return new Promise(function(resolve) {
370 instrumented.notifications.getAll(function(notifications) { 362 instrumented.notifications.getAll(function(notifications) {
371 console.log('showNotificationGroups-getAll ' + 363 console.log(
372 JSON.stringify(notifications)); 364 'showNotificationGroups-getAll ' + JSON.stringify(notifications));
373 notifications = notifications || {}; 365 notifications = notifications || {};
374 366
375 // Mark notifications that didn't receive an update as having received 367 // Mark notifications that didn't receive an update as having received
376 // an empty update. 368 // an empty update.
377 for (var chromeNotificationId in notifications) { 369 for (var chromeNotificationId in notifications) {
378 cards[chromeNotificationId] = cards[chromeNotificationId] || []; 370 cards[chromeNotificationId] = cards[chromeNotificationId] || [];
379 } 371 }
380 372
381 /** @type {Object<ChromeNotificationId, NotificationDataEntry>} */ 373 /** @type {Object<ChromeNotificationId, NotificationDataEntry>} */
382 var notificationsData = {}; 374 var notificationsData = {};
383 375
384 // Create/update/delete notifications. 376 // Create/update/delete notifications.
385 for (var chromeNotificationId in cards) { 377 for (var chromeNotificationId in cards) {
386 notificationsData[chromeNotificationId] = cardSet.update( 378 notificationsData[chromeNotificationId] = cardSet.update(
387 chromeNotificationId, 379 chromeNotificationId, cards[chromeNotificationId],
388 cards[chromeNotificationId], 380 notificationGroups, opt_onCardShown);
389 notificationGroups,
390 opt_onCardShown);
391 } 381 }
392 chrome.storage.local.set({notificationsData: notificationsData}); 382 chrome.storage.local.set({notificationsData: notificationsData});
393 resolve(); 383 resolve();
394 }); 384 });
395 }); 385 });
396 } 386 }
397 387
398 /** 388 /**
399 * Removes all cards and card state on Google Now close down. 389 * Removes all cards and card state on Google Now close down.
400 */ 390 */
(...skipping 22 matching lines...) Expand all
423 */ 413 */
424 function combineGroup(combinedCards, storedGroup) { 414 function combineGroup(combinedCards, storedGroup) {
425 for (var i = 0; i < storedGroup.cards.length; i++) { 415 for (var i = 0; i < storedGroup.cards.length; i++) {
426 /** @type {ReceivedNotification} */ 416 /** @type {ReceivedNotification} */
427 var receivedNotification = storedGroup.cards[i]; 417 var receivedNotification = storedGroup.cards[i];
428 418
429 /** @type {UncombinedNotification} */ 419 /** @type {UncombinedNotification} */
430 var uncombinedNotification = { 420 var uncombinedNotification = {
431 receivedNotification: receivedNotification, 421 receivedNotification: receivedNotification,
432 showTime: receivedNotification.trigger.showTimeSec && 422 showTime: receivedNotification.trigger.showTimeSec &&
433 (storedGroup.cardsTimestamp + 423 (storedGroup.cardsTimestamp +
434 receivedNotification.trigger.showTimeSec * MS_IN_SECOND), 424 receivedNotification.trigger.showTimeSec * MS_IN_SECOND),
435 hideTime: storedGroup.cardsTimestamp + 425 hideTime: storedGroup.cardsTimestamp +
436 receivedNotification.trigger.hideTimeSec * MS_IN_SECOND 426 receivedNotification.trigger.hideTimeSec * MS_IN_SECOND
437 }; 427 };
438 428
439 var combinedCard = 429 var combinedCard =
440 combinedCards[receivedNotification.chromeNotificationId] || []; 430 combinedCards[receivedNotification.chromeNotificationId] || [];
441 combinedCard.push(uncombinedNotification); 431 combinedCard.push(uncombinedNotification);
442 combinedCards[receivedNotification.chromeNotificationId] = combinedCard; 432 combinedCards[receivedNotification.chromeNotificationId] = combinedCard;
443 } 433 }
444 } 434 }
445 435
446 /** 436 /**
447 * Calculates the soonest poll time from a map of groups as an absolute time. 437 * Calculates the soonest poll time from a map of groups as an absolute time.
448 * @param {Object<StoredNotificationGroup>} groups Map from group name to group 438 * @param {Object<StoredNotificationGroup>} groups Map from group name to group
449 * information. 439 * information.
450 * @return {number} The next poll time based off of the groups. 440 * @return {number} The next poll time based off of the groups.
451 */ 441 */
452 function calculateNextPollTimeMilliseconds(groups) { 442 function calculateNextPollTimeMilliseconds(groups) {
453 var nextPollTime = null; 443 var nextPollTime = null;
454 444
455 for (var groupName in groups) { 445 for (var groupName in groups) {
456 var group = groups[groupName]; 446 var group = groups[groupName];
457 if (group.nextPollTime !== undefined) { 447 if (group.nextPollTime !== undefined) {
458 nextPollTime = nextPollTime == null ? 448 nextPollTime = nextPollTime == null ?
459 group.nextPollTime : Math.min(group.nextPollTime, nextPollTime); 449 group.nextPollTime :
450 Math.min(group.nextPollTime, nextPollTime);
460 } 451 }
461 } 452 }
462 453
463 // At least one of the groups must have nextPollTime. 454 // At least one of the groups must have nextPollTime.
464 verify(nextPollTime != null, 'calculateNextPollTime: nextPollTime is null'); 455 verify(nextPollTime != null, 'calculateNextPollTime: nextPollTime is null');
465 return nextPollTime; 456 return nextPollTime;
466 } 457 }
467 458
468 /** 459 /**
469 * Schedules next cards poll. 460 * Schedules next cards poll.
470 * @param {Object<StoredNotificationGroup>} groups Map from group name to group 461 * @param {Object<StoredNotificationGroup>} groups Map from group name to group
471 * information. 462 * information.
472 */ 463 */
473 function scheduleNextCardsPoll(groups) { 464 function scheduleNextCardsPoll(groups) {
474 var nextPollTimeMs = calculateNextPollTimeMilliseconds(groups); 465 var nextPollTimeMs = calculateNextPollTimeMilliseconds(groups);
475 466
476 var nextPollDelaySeconds = Math.max( 467 var nextPollDelaySeconds = Math.max(
477 (nextPollTimeMs - Date.now()) / MS_IN_SECOND, 468 (nextPollTimeMs - Date.now()) / MS_IN_SECOND,
478 MINIMUM_POLLING_PERIOD_SECONDS); 469 MINIMUM_POLLING_PERIOD_SECONDS);
479 updateCardsAttempts.start(nextPollDelaySeconds); 470 updateCardsAttempts.start(nextPollDelaySeconds);
480 } 471 }
481 472
482 /** 473 /**
483 * Schedules the next opt-in check poll. 474 * Schedules the next opt-in check poll.
484 */ 475 */
485 function scheduleOptInCheckPoll() { 476 function scheduleOptInCheckPoll() {
486 instrumented.metricsPrivate.getVariationParams( 477 instrumented.metricsPrivate.getVariationParams('GoogleNow', function(params) {
487 'GoogleNow', function(params) {
488 var optinPollPeriodSeconds = 478 var optinPollPeriodSeconds =
489 parseInt(params && params.optinPollPeriodSeconds, 10) || 479 parseInt(params && params.optinPollPeriodSeconds, 10) ||
490 DEFAULT_OPTIN_CHECK_PERIOD_SECONDS; 480 DEFAULT_OPTIN_CHECK_PERIOD_SECONDS;
491 optInPollAttempts.start(optinPollPeriodSeconds); 481 optInPollAttempts.start(optinPollPeriodSeconds);
492 }); 482 });
493 } 483 }
494 484
495 /** 485 /**
496 * Combines notification groups into a set of Chrome notifications. 486 * Combines notification groups into a set of Chrome notifications.
497 * @param {Object<StoredNotificationGroup>} notificationGroups Map from group 487 * @param {Object<StoredNotificationGroup>} notificationGroups Map from group
(...skipping 22 matching lines...) Expand all
520 510
521 if (response.googleNowDisabled) { 511 if (response.googleNowDisabled) {
522 chrome.storage.local.set({googleNowEnabled: false}); 512 chrome.storage.local.set({googleNowEnabled: false});
523 // Stop processing now. The state change will clear the cards. 513 // Stop processing now. The state change will clear the cards.
524 return Promise.reject(); 514 return Promise.reject();
525 } 515 }
526 516
527 var receivedGroups = response.groups; 517 var receivedGroups = response.groups;
528 518
529 return fillFromChromeLocalStorage({ 519 return fillFromChromeLocalStorage({
530 /** @type {Object<StoredNotificationGroup>} */ 520 /** @type {Object<StoredNotificationGroup>} */
531 notificationGroups: {}, 521 notificationGroups: {},
532 /** @type {Object<ServerNotificationId, number>} */ 522 /** @type {Object<ServerNotificationId, number>} */
533 recentDismissals: {} 523 recentDismissals: {}
534 }).then(function(items) { 524 })
535 console.log('processServerResponse-get ' + JSON.stringify(items)); 525 .then(function(items) {
526 console.log('processServerResponse-get ' + JSON.stringify(items));
536 527
537 // Build a set of non-expired recent dismissals. It will be used for 528 // Build a set of non-expired recent dismissals. It will be used for
538 // client-side filtering of cards. 529 // client-side filtering of cards.
539 /** @type {Object<ServerNotificationId, number>} */ 530 /** @type {Object<ServerNotificationId, number>} */
540 var updatedRecentDismissals = {}; 531 var updatedRecentDismissals = {};
541 var now = Date.now(); 532 var now = Date.now();
542 for (var serverNotificationId in items.recentDismissals) { 533 for (var serverNotificationId in items.recentDismissals) {
543 var dismissalAge = now - items.recentDismissals[serverNotificationId]; 534 var dismissalAge = now - items.recentDismissals[serverNotificationId];
544 if (dismissalAge < DISMISS_RETENTION_TIME_MS) { 535 if (dismissalAge < DISMISS_RETENTION_TIME_MS) {
545 updatedRecentDismissals[serverNotificationId] = 536 updatedRecentDismissals[serverNotificationId] =
546 items.recentDismissals[serverNotificationId]; 537 items.recentDismissals[serverNotificationId];
547 } 538 }
548 } 539 }
549 540
550 // Populate groups with corresponding cards. 541 // Populate groups with corresponding cards.
551 if (response.notifications) { 542 if (response.notifications) {
552 for (var i = 0; i < response.notifications.length; ++i) { 543 for (var i = 0; i < response.notifications.length; ++i) {
553 /** @type {ReceivedNotification} */ 544 /** @type {ReceivedNotification} */
554 var card = response.notifications[i]; 545 var card = response.notifications[i];
555 if (!(card.notificationId in updatedRecentDismissals)) { 546 if (!(card.notificationId in updatedRecentDismissals)) {
556 var group = receivedGroups[card.groupName]; 547 var group = receivedGroups[card.groupName];
557 group.cards = group.cards || []; 548 group.cards = group.cards || [];
558 group.cards.push(card); 549 group.cards.push(card);
550 }
551 }
559 } 552 }
560 }
561 }
562 553
563 // Build updated set of groups. 554 // Build updated set of groups.
564 var updatedGroups = {}; 555 var updatedGroups = {};
565 556
566 for (var groupName in receivedGroups) { 557 for (var groupName in receivedGroups) {
567 var receivedGroup = receivedGroups[groupName]; 558 var receivedGroup = receivedGroups[groupName];
568 var storedGroup = items.notificationGroups[groupName] || { 559 var storedGroup = items.notificationGroups[groupName] || {
569 cards: [], 560 cards: [],
570 cardsTimestamp: undefined, 561 cardsTimestamp: undefined,
571 nextPollTime: undefined, 562 nextPollTime: undefined,
572 rank: undefined 563 rank: undefined
573 }; 564 };
574 565
575 if (receivedGroup.requested) 566 if (receivedGroup.requested)
576 receivedGroup.cards = receivedGroup.cards || []; 567 receivedGroup.cards = receivedGroup.cards || [];
577 568
578 if (receivedGroup.cards) { 569 if (receivedGroup.cards) {
579 // If the group contains a cards update, all its fields will get new 570 // If the group contains a cards update, all its fields will get new
580 // values. 571 // values.
581 storedGroup.cards = receivedGroup.cards; 572 storedGroup.cards = receivedGroup.cards;
582 storedGroup.cardsTimestamp = now; 573 storedGroup.cardsTimestamp = now;
583 storedGroup.rank = receivedGroup.rank; 574 storedGroup.rank = receivedGroup.rank;
584 storedGroup.nextPollTime = undefined; 575 storedGroup.nextPollTime = undefined;
585 // The code below assigns nextPollTime a defined value if 576 // The code below assigns nextPollTime a defined value if
586 // nextPollSeconds is specified in the received group. 577 // nextPollSeconds is specified in the received group.
587 // If the group's cards are not updated, and nextPollSeconds is 578 // If the group's cards are not updated, and nextPollSeconds is
588 // unspecified, this method doesn't change group's nextPollTime. 579 // unspecified, this method doesn't change group's nextPollTime.
589 } 580 }
590 581
591 // 'nextPollSeconds' may be sent even for groups that don't contain 582 // 'nextPollSeconds' may be sent even for groups that don't contain
592 // cards updates. 583 // cards updates.
593 if (receivedGroup.nextPollSeconds !== undefined) { 584 if (receivedGroup.nextPollSeconds !== undefined) {
594 storedGroup.nextPollTime = 585 storedGroup.nextPollTime =
595 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; 586 now + receivedGroup.nextPollSeconds * MS_IN_SECOND;
596 } 587 }
597 588
598 updatedGroups[groupName] = storedGroup; 589 updatedGroups[groupName] = storedGroup;
599 } 590 }
600 591
601 scheduleNextCardsPoll(updatedGroups); 592 scheduleNextCardsPoll(updatedGroups);
602 return { 593 return {
603 updatedGroups: updatedGroups, 594 updatedGroups: updatedGroups,
604 recentDismissals: updatedRecentDismissals 595 recentDismissals: updatedRecentDismissals
605 }; 596 };
606 }); 597 });
607 } 598 }
608 599
609 /** 600 /**
610 * Update the Explanatory Total Cards Shown Count. 601 * Update the Explanatory Total Cards Shown Count.
611 */ 602 */
612 function countExplanatoryCard() { 603 function countExplanatoryCard() {
613 localStorage['explanatoryCardsShown']++; 604 localStorage['explanatoryCardsShown']++;
614 } 605 }
615 606
616 /** 607 /**
(...skipping 11 matching lines...) Expand all
628 * @param {Array<string>} groupNames Names of groups that need to be refreshed. 619 * @param {Array<string>} groupNames Names of groups that need to be refreshed.
629 * @return {Promise} A promise to request the specified notification groups. 620 * @return {Promise} A promise to request the specified notification groups.
630 */ 621 */
631 function requestNotificationGroupsFromServer(groupNames) { 622 function requestNotificationGroupsFromServer(groupNames) {
632 console.log( 623 console.log(
633 'requestNotificationGroupsFromServer from ' + NOTIFICATION_CARDS_URL + 624 'requestNotificationGroupsFromServer from ' + NOTIFICATION_CARDS_URL +
634 ', groupNames=' + JSON.stringify(groupNames)); 625 ', groupNames=' + JSON.stringify(groupNames));
635 626
636 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL); 627 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);
637 628
638 var requestParameters = '?timeZoneOffsetMs=' + 629 var requestParameters =
639 (-new Date().getTimezoneOffset() * MS_IN_MINUTE); 630 '?timeZoneOffsetMs=' + (-new Date().getTimezoneOffset() * MS_IN_MINUTE);
640 631
641 if (shouldShowExplanatoryCard()) { 632 if (shouldShowExplanatoryCard()) {
642 requestParameters += '&cardExplanation=true'; 633 requestParameters += '&cardExplanation=true';
643 } 634 }
644 635
645 groupNames.forEach(function(groupName) { 636 groupNames.forEach(function(groupName) {
646 requestParameters += ('&requestTypes=' + groupName); 637 requestParameters += ('&requestTypes=' + groupName);
647 }); 638 });
648 639
649 requestParameters += '&uiLocale=' + navigator.language; 640 requestParameters += '&uiLocale=' + navigator.language;
650 641
651 console.log( 642 console.log(
652 'requestNotificationGroupsFromServer: request=' + requestParameters); 643 'requestNotificationGroupsFromServer: request=' + requestParameters);
653 644
654 return requestFromServer('GET', 'notifications' + requestParameters).then( 645 return requestFromServer('GET', 'notifications' + requestParameters)
655 function(request) { 646 .then(function(request) {
656 console.log( 647 console.log(
657 'requestNotificationGroupsFromServer-received ' + request.status); 648 'requestNotificationGroupsFromServer-received ' + request.status);
658 if (request.status == HTTP_OK) { 649 if (request.status == HTTP_OK) {
659 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); 650 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
660 return JSON.parse(request.responseText); 651 return JSON.parse(request.responseText);
661 } 652 }
662 }); 653 });
663 } 654 }
664 655
665 /** 656 /**
666 * Performs an opt-in poll without an immediate recheck. 657 * Performs an opt-in poll without an immediate recheck.
667 * If the response is not opted-in, schedule an opt-in check poll. 658 * If the response is not opted-in, schedule an opt-in check poll.
668 */ 659 */
669 function pollOptedInNoImmediateRecheck() { 660 function pollOptedInNoImmediateRecheck() {
670 requestAndUpdateOptedIn() 661 requestAndUpdateOptedIn()
671 .then(function(optedIn) { 662 .then(function(optedIn) {
672 if (!optedIn) { 663 if (!optedIn) {
673 // Request a repoll if we're not opted in. 664 // Request a repoll if we're not opted in.
674 return Promise.reject(); 665 return Promise.reject();
675 } 666 }
676 }) 667 })
677 .catch(function() { 668 .catch(function() {
678 scheduleOptInCheckPoll(); 669 scheduleOptInCheckPoll();
679 }); 670 });
680 } 671 }
681 672
682 /** 673 /**
683 * Requests the account opted-in state from the server and updates any 674 * Requests the account opted-in state from the server and updates any
684 * state as necessary. 675 * state as necessary.
685 * @return {Promise} A promise to request and update the opted-in state. 676 * @return {Promise} A promise to request and update the opted-in state.
686 * The promise resolves with the opt-in state. 677 * The promise resolves with the opt-in state.
687 */ 678 */
688 function requestAndUpdateOptedIn() { 679 function requestAndUpdateOptedIn() {
689 console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL); 680 console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL);
690 681
691 return requestFromServer('GET', 'settings/optin').then(function(request) { 682 return requestFromServer('GET', 'settings/optin')
692 console.log( 683 .then(function(request) {
693 'requestOptedIn-received ' + request.status + ' ' + request.response); 684 console.log(
694 if (request.status == HTTP_OK) { 685 'requestOptedIn-received ' + request.status + ' ' +
695 var parsedResponse = JSON.parse(request.responseText); 686 request.response);
696 return parsedResponse.value; 687 if (request.status == HTTP_OK) {
697 } 688 var parsedResponse = JSON.parse(request.responseText);
698 }).then(function(optedIn) { 689 return parsedResponse.value;
699 chrome.storage.local.set({googleNowEnabled: optedIn}); 690 }
700 return optedIn; 691 })
701 }); 692 .then(function(optedIn) {
693 chrome.storage.local.set({googleNowEnabled: optedIn});
694 return optedIn;
695 });
702 } 696 }
703 697
704 /** 698 /**
705 * Determines the groups that need to be requested right now. 699 * Determines the groups that need to be requested right now.
706 * @return {Promise} A promise to determine the groups to request. 700 * @return {Promise} A promise to determine the groups to request.
707 */ 701 */
708 function getGroupsToRequest() { 702 function getGroupsToRequest() {
709 return fillFromChromeLocalStorage({ 703 return fillFromChromeLocalStorage({
710 /** @type {Object<StoredNotificationGroup>} */ 704 /** @type {Object<StoredNotificationGroup>} */
711 notificationGroups: {} 705 notificationGroups: {}
712 }).then(function(items) { 706 })
713 console.log('getGroupsToRequest-storage-get ' + JSON.stringify(items)); 707 .then(function(items) {
714 var groupsToRequest = []; 708 console.log('getGroupsToRequest-storage-get ' + JSON.stringify(items));
715 var now = Date.now(); 709 var groupsToRequest = [];
710 var now = Date.now();
716 711
717 for (var groupName in items.notificationGroups) { 712 for (var groupName in items.notificationGroups) {
718 var group = items.notificationGroups[groupName]; 713 var group = items.notificationGroups[groupName];
719 if (group.nextPollTime !== undefined && group.nextPollTime <= now) 714 if (group.nextPollTime !== undefined && group.nextPollTime <= now)
720 groupsToRequest.push(groupName); 715 groupsToRequest.push(groupName);
721 } 716 }
722 return groupsToRequest; 717 return groupsToRequest;
723 }); 718 });
724 } 719 }
725 720
726 /** 721 /**
727 * Requests notification cards from the server. 722 * Requests notification cards from the server.
728 * @return {Promise} A promise to request the notification cards. 723 * @return {Promise} A promise to request the notification cards.
729 * Rejects if the cards won't be requested. 724 * Rejects if the cards won't be requested.
730 */ 725 */
731 function requestNotificationCards() { 726 function requestNotificationCards() {
732 console.log('requestNotificationCards'); 727 console.log('requestNotificationCards');
733 return getGroupsToRequest() 728 return getGroupsToRequest()
734 .then(requestNotificationGroupsFromServer) 729 .then(requestNotificationGroupsFromServer)
735 .then(processServerResponse) 730 .then(processServerResponse)
736 .then(function(processedResponse) { 731 .then(function(processedResponse) {
737 var onCardShown = 732 var onCardShown =
738 shouldShowExplanatoryCard() ? countExplanatoryCard : undefined; 733 shouldShowExplanatoryCard() ? countExplanatoryCard : undefined;
739 return showNotificationGroups( 734 return showNotificationGroups(
740 processedResponse.updatedGroups, onCardShown).then(function() { 735 processedResponse.updatedGroups, onCardShown)
736 .then(function() {
741 chrome.storage.local.set({ 737 chrome.storage.local.set({
742 notificationGroups: processedResponse.updatedGroups, 738 notificationGroups: processedResponse.updatedGroups,
743 recentDismissals: processedResponse.updatedRecentDismissals 739 recentDismissals: processedResponse.updatedRecentDismissals
744 }); 740 });
745 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); 741 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS);
746 } 742 });
747 );
748 }); 743 });
749 } 744 }
750 745
751 /** 746 /**
752 * Determines if an immediate retry should occur based off of the given groups. 747 * Determines if an immediate retry should occur based off of the given groups.
753 * The NOR group is expected most often and less latency sensitive, so we will 748 * The NOR group is expected most often and less latency sensitive, so we will
754 * simply wait MAXIMUM_POLLING_PERIOD_SECONDS before trying again. 749 * simply wait MAXIMUM_POLLING_PERIOD_SECONDS before trying again.
755 * @param {Array<string>} groupNames Names of groups that need to be refreshed. 750 * @param {Array<string>} groupNames Names of groups that need to be refreshed.
756 * @return {boolean} Whether a retry should occur. 751 * @return {boolean} Whether a retry should occur.
757 */ 752 */
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 * Sends a server request to dismiss a card. 786 * Sends a server request to dismiss a card.
792 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of 787 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of
793 * the card. 788 * the card.
794 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in 789 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in
795 * milliseconds since epoch. 790 * milliseconds since epoch.
796 * @param {DismissalData} dismissalData Data to build a dismissal request. 791 * @param {DismissalData} dismissalData Data to build a dismissal request.
797 * @return {Promise} A promise to request the card dismissal, rejects on error. 792 * @return {Promise} A promise to request the card dismissal, rejects on error.
798 */ 793 */
799 function requestCardDismissal( 794 function requestCardDismissal(
800 chromeNotificationId, dismissalTimeMs, dismissalData) { 795 chromeNotificationId, dismissalTimeMs, dismissalData) {
801 console.log('requestDismissingCard ' + chromeNotificationId + 796 console.log(
802 ' from ' + NOTIFICATION_CARDS_URL + 797 'requestDismissingCard ' + chromeNotificationId + ' from ' +
803 ', dismissalData=' + JSON.stringify(dismissalData)); 798 NOTIFICATION_CARDS_URL + ', dismissalData=' +
799 JSON.stringify(dismissalData));
804 800
805 var dismissalAge = Date.now() - dismissalTimeMs; 801 var dismissalAge = Date.now() - dismissalTimeMs;
806 802
807 if (dismissalAge > MAXIMUM_DISMISSAL_AGE_MS) { 803 if (dismissalAge > MAXIMUM_DISMISSAL_AGE_MS) {
808 return Promise.resolve(); 804 return Promise.resolve();
809 } 805 }
810 806
811 recordEvent(GoogleNowEvent.DISMISS_REQUEST_TOTAL); 807 recordEvent(GoogleNowEvent.DISMISS_REQUEST_TOTAL);
812 808
813 var requestParameters = 'notifications/' + dismissalData.notificationId + 809 var requestParameters = 'notifications/' + dismissalData.notificationId +
814 '?age=' + dismissalAge + 810 '?age=' + dismissalAge + '&chromeNotificationId=' + chromeNotificationId;
815 '&chromeNotificationId=' + chromeNotificationId;
816 811
817 for (var paramField in dismissalData.parameters) 812 for (var paramField in dismissalData.parameters)
818 requestParameters += ('&' + paramField + 813 requestParameters +=
819 '=' + dismissalData.parameters[paramField]); 814 ('&' + paramField + '=' + dismissalData.parameters[paramField]);
820 815
821 console.log('requestCardDismissal: requestParameters=' + requestParameters); 816 console.log('requestCardDismissal: requestParameters=' + requestParameters);
822 817
823 return requestFromServer('DELETE', requestParameters).then(function(request) { 818 return requestFromServer('DELETE', requestParameters)
824 console.log('requestDismissingCard-onloadend ' + request.status); 819 .then(function(request) {
825 if (request.status == HTTP_NOCONTENT) 820 console.log('requestDismissingCard-onloadend ' + request.status);
826 recordEvent(GoogleNowEvent.DISMISS_REQUEST_SUCCESS); 821 if (request.status == HTTP_NOCONTENT)
822 recordEvent(GoogleNowEvent.DISMISS_REQUEST_SUCCESS);
827 823
828 // A dismissal doesn't require further retries if it was successful or 824 // A dismissal doesn't require further retries if it was successful or
829 // doesn't have a chance for successful completion. 825 // doesn't have a chance for successful completion.
830 return (request.status == HTTP_NOCONTENT) ? 826 return (request.status == HTTP_NOCONTENT) ? Promise.resolve() :
831 Promise.resolve() : 827 Promise.reject();
832 Promise.reject(); 828 })
833 }).catch(function(request) { 829 .catch(function(request) {
834 request = (typeof request === 'object') ? request : {}; 830 request = (typeof request === 'object') ? request : {};
835 return (request.status == HTTP_BAD_REQUEST || 831 return (request.status == HTTP_BAD_REQUEST ||
836 request.status == HTTP_METHOD_NOT_ALLOWED) ? 832 request.status == HTTP_METHOD_NOT_ALLOWED) ?
837 Promise.resolve() : 833 Promise.resolve() :
838 Promise.reject(); 834 Promise.reject();
839 }); 835 });
840 } 836 }
841 837
842 /** 838 /**
843 * Tries to send dismiss requests for all pending dismissals. 839 * Tries to send dismiss requests for all pending dismissals.
844 * @return {Promise} A promise to process the pending dismissals. 840 * @return {Promise} A promise to process the pending dismissals.
845 * The promise is rejected if a problem was encountered. 841 * The promise is rejected if a problem was encountered.
846 */ 842 */
847 function processPendingDismissals() { 843 function processPendingDismissals() {
848 return fillFromChromeLocalStorage({ 844 return fillFromChromeLocalStorage({
849 /** @type {Array<PendingDismissal>} */ 845 /** @type {Array<PendingDismissal>} */
850 pendingDismissals: [], 846 pendingDismissals: [],
851 /** @type {Object<ServerNotificationId, number>} */ 847 /** @type {Object<ServerNotificationId, number>} */
852 recentDismissals: {} 848 recentDismissals: {}
853 }).then(function(items) { 849 })
854 console.log( 850 .then(function(items) {
855 'processPendingDismissals-storage-get ' + JSON.stringify(items)); 851 console.log(
852 'processPendingDismissals-storage-get ' + JSON.stringify(items));
856 853
857 var dismissalsChanged = false; 854 var dismissalsChanged = false;
858 855
859 function onFinish(success) { 856 function onFinish(success) {
860 if (dismissalsChanged) { 857 if (dismissalsChanged) {
861 chrome.storage.local.set({ 858 chrome.storage.local.set({
862 pendingDismissals: items.pendingDismissals, 859 pendingDismissals: items.pendingDismissals,
863 recentDismissals: items.recentDismissals 860 recentDismissals: items.recentDismissals
864 }); 861 });
865 } 862 }
866 return success ? Promise.resolve() : Promise.reject(); 863 return success ? Promise.resolve() : Promise.reject();
867 } 864 }
868 865
869 function doProcessDismissals() { 866 function doProcessDismissals() {
870 if (items.pendingDismissals.length == 0) { 867 if (items.pendingDismissals.length == 0) {
871 dismissalAttempts.stop(); 868 dismissalAttempts.stop();
872 return onFinish(true); 869 return onFinish(true);
873 } 870 }
874 871
875 // Send dismissal for the first card, and if successful, repeat 872 // Send dismissal for the first card, and if successful, repeat
876 // recursively with the rest. 873 // recursively with the rest.
877 /** @type {PendingDismissal} */ 874 /** @type {PendingDismissal} */
878 var dismissal = items.pendingDismissals[0]; 875 var dismissal = items.pendingDismissals[0];
879 return requestCardDismissal( 876 return requestCardDismissal(
880 dismissal.chromeNotificationId, 877 dismissal.chromeNotificationId, dismissal.time,
881 dismissal.time, 878 dismissal.dismissalData)
882 dismissal.dismissalData).then(function() { 879 .then(function() {
883 dismissalsChanged = true; 880 dismissalsChanged = true;
884 items.pendingDismissals.splice(0, 1); 881 items.pendingDismissals.splice(0, 1);
885 items.recentDismissals[dismissal.dismissalData.notificationId] = 882 items.recentDismissals[dismissal.dismissalData.notificationId] =
886 Date.now(); 883 Date.now();
887 return doProcessDismissals(); 884 return doProcessDismissals();
888 }).catch(function() { 885 })
889 return onFinish(false); 886 .catch(function() {
890 }); 887 return onFinish(false);
891 } 888 });
889 }
892 890
893 return doProcessDismissals(); 891 return doProcessDismissals();
894 }); 892 });
895 } 893 }
896 894
897 /** 895 /**
898 * Submits a task to send pending dismissals. 896 * Submits a task to send pending dismissals.
899 */ 897 */
900 function retryPendingDismissals() { 898 function retryPendingDismissals() {
901 tasks.add(RETRY_DISMISS_TASK_NAME, function() { 899 tasks.add(RETRY_DISMISS_TASK_NAME, function() {
902 processPendingDismissals().catch(dismissalAttempts.scheduleRetry); 900 processPendingDismissals().catch(dismissalAttempts.scheduleRetry);
903 }); 901 });
904 } 902 }
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
960 958
961 fillFromChromeLocalStorage({ 959 fillFromChromeLocalStorage({
962 /** @type {Array<PendingDismissal>} */ 960 /** @type {Array<PendingDismissal>} */
963 pendingDismissals: [], 961 pendingDismissals: [],
964 /** @type {Object<ChromeNotificationId, NotificationDataEntry>} */ 962 /** @type {Object<ChromeNotificationId, NotificationDataEntry>} */
965 notificationsData: {}, 963 notificationsData: {},
966 /** @type {Object<StoredNotificationGroup>} */ 964 /** @type {Object<StoredNotificationGroup>} */
967 notificationGroups: {} 965 notificationGroups: {}
968 }).then(function(items) { 966 }).then(function(items) {
969 /** @type {NotificationDataEntry} */ 967 /** @type {NotificationDataEntry} */
970 var notificationData = 968 var notificationData = items.notificationsData[chromeNotificationId] ||
971 items.notificationsData[chromeNotificationId] || 969 {timestamp: Date.now(), combinedCard: []};
972 {
973 timestamp: Date.now(),
974 combinedCard: []
975 };
976 970
977 var dismissalResult = 971 var dismissalResult = cardSet.onDismissal(
978 cardSet.onDismissal( 972 chromeNotificationId, notificationData, items.notificationGroups);
979 chromeNotificationId,
980 notificationData,
981 items.notificationGroups);
982 973
983 for (var i = 0; i < dismissalResult.dismissals.length; i++) { 974 for (var i = 0; i < dismissalResult.dismissals.length; i++) {
984 /** @type {PendingDismissal} */ 975 /** @type {PendingDismissal} */
985 var dismissal = { 976 var dismissal = {
986 chromeNotificationId: chromeNotificationId, 977 chromeNotificationId: chromeNotificationId,
987 time: Date.now(), 978 time: Date.now(),
988 dismissalData: dismissalResult.dismissals[i] 979 dismissalData: dismissalResult.dismissals[i]
989 }; 980 };
990 items.pendingDismissals.push(dismissal); 981 items.pendingDismissals.push(dismissal);
991 } 982 }
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1079 unregisterFromGcm(); 1070 unregisterFromGcm();
1080 } 1071 }
1081 } 1072 }
1082 1073
1083 /** 1074 /**
1084 * Enables or disables the Google Now background permission. 1075 * Enables or disables the Google Now background permission.
1085 * @param {boolean} backgroundEnable true to run in the background. 1076 * @param {boolean} backgroundEnable true to run in the background.
1086 * false to not run in the background. 1077 * false to not run in the background.
1087 */ 1078 */
1088 function setBackgroundEnable(backgroundEnable) { 1079 function setBackgroundEnable(backgroundEnable) {
1089 instrumented.permissions.contains({permissions: ['background']}, 1080 instrumented.permissions.contains(
1090 function(hasPermission) { 1081 {permissions: ['background']}, function(hasPermission) {
1091 if (backgroundEnable != hasPermission) { 1082 if (backgroundEnable != hasPermission) {
1092 console.log('Action Taken setBackgroundEnable=' + backgroundEnable); 1083 console.log('Action Taken setBackgroundEnable=' + backgroundEnable);
1093 if (backgroundEnable) 1084 if (backgroundEnable)
1094 chrome.permissions.request({permissions: ['background']}); 1085 chrome.permissions.request({permissions: ['background']});
1095 else 1086 else
1096 chrome.permissions.remove({permissions: ['background']}); 1087 chrome.permissions.remove({permissions: ['background']});
1097 } else { 1088 } else {
1098 console.log('Action Ignored setBackgroundEnable=' + backgroundEnable); 1089 console.log('Action Ignored setBackgroundEnable=' + backgroundEnable);
1099 } 1090 }
1100 }); 1091 });
(...skipping 22 matching lines...) Expand all
1123 * based off of the current state of Chrome. 1114 * based off of the current state of Chrome.
1124 * @param {boolean} signedIn true if the user is signed in. 1115 * @param {boolean} signedIn true if the user is signed in.
1125 * @param {boolean} canEnableBackground true if 1116 * @param {boolean} canEnableBackground true if
1126 * the background permission can be requested. 1117 * the background permission can be requested.
1127 * @param {boolean} notificationEnabled true if 1118 * @param {boolean} notificationEnabled true if
1128 * Google Now for Chrome is allowed to show notifications. 1119 * Google Now for Chrome is allowed to show notifications.
1129 * @param {boolean} googleNowEnabled true if 1120 * @param {boolean} googleNowEnabled true if
1130 * the Google Now is enabled for the user. 1121 * the Google Now is enabled for the user.
1131 */ 1122 */
1132 function updateRunningState( 1123 function updateRunningState(
1133 signedIn, 1124 signedIn, canEnableBackground, notificationEnabled, googleNowEnabled) {
1134 canEnableBackground,
1135 notificationEnabled,
1136 googleNowEnabled) {
1137 console.log( 1125 console.log(
1138 'State Update signedIn=' + signedIn + ' ' + 1126 'State Update signedIn=' + signedIn + ' ' +
1139 'canEnableBackground=' + canEnableBackground + ' ' + 1127 'canEnableBackground=' + canEnableBackground + ' ' +
1140 'notificationEnabled=' + notificationEnabled + ' ' + 1128 'notificationEnabled=' + notificationEnabled + ' ' +
1141 'googleNowEnabled=' + googleNowEnabled); 1129 'googleNowEnabled=' + googleNowEnabled);
1142 1130
1143 var shouldPollCards = false; 1131 var shouldPollCards = false;
1144 var shouldPollOptInStatus = false; 1132 var shouldPollOptInStatus = false;
1145 var shouldSetBackground = false; 1133 var shouldSetBackground = false;
1146 1134
(...skipping 19 matching lines...) Expand all
1166 removeAllCards(); 1154 removeAllCards();
1167 } 1155 }
1168 } 1156 }
1169 1157
1170 /** 1158 /**
1171 * Coordinates the behavior of Google Now for Chrome depending on 1159 * Coordinates the behavior of Google Now for Chrome depending on
1172 * Chrome and extension state. 1160 * Chrome and extension state.
1173 */ 1161 */
1174 function onStateChange() { 1162 function onStateChange() {
1175 tasks.add(STATE_CHANGED_TASK_NAME, function() { 1163 tasks.add(STATE_CHANGED_TASK_NAME, function() {
1176 Promise.all([ 1164 Promise
1177 authenticationManager.isSignedIn(), 1165 .all([
1178 canEnableBackground(), 1166 authenticationManager.isSignedIn(), canEnableBackground(),
1179 isNotificationsEnabled(), 1167 isNotificationsEnabled(), isGoogleNowEnabled()
1180 isGoogleNowEnabled()]) 1168 ])
1181 .then(function(results) { 1169 .then(function(results) {
1182 updateRunningState.apply(null, results); 1170 updateRunningState.apply(null, results);
1183 }); 1171 });
1184 }); 1172 });
1185 } 1173 }
1186 1174
1187 /** 1175 /**
1188 * Determines if background mode should be requested. 1176 * Determines if background mode should be requested.
1189 * @return {Promise} A promise to determine if background can be enabled. 1177 * @return {Promise} A promise to determine if background can be enabled.
1190 */ 1178 */
1191 function canEnableBackground() { 1179 function canEnableBackground() {
1192 return new Promise(function(resolve) { 1180 return new Promise(function(resolve) {
1193 instrumented.metricsPrivate.getVariationParams( 1181 instrumented.metricsPrivate.getVariationParams(
1194 'GoogleNow', 1182 'GoogleNow', function(response) {
1195 function(response) {
1196 resolve(!response || (response.canEnableBackground != 'false')); 1183 resolve(!response || (response.canEnableBackground != 'false'));
1197 }); 1184 });
1198 }); 1185 });
1199 } 1186 }
1200 1187
1201 /** 1188 /**
1202 * Checks if Google Now is enabled in the notifications center. 1189 * Checks if Google Now is enabled in the notifications center.
1203 * @return {Promise} A promise to determine if Google Now is enabled 1190 * @return {Promise} A promise to determine if Google Now is enabled
1204 * in the notifications center. 1191 * in the notifications center.
1205 */ 1192 */
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1247 }); 1234 });
1248 } 1235 }
1249 1236
1250 /** 1237 /**
1251 * Returns a promise resolving to a GCM Notificaiton Key. May call 1238 * Returns a promise resolving to a GCM Notificaiton Key. May call
1252 * chrome.gcm.register() first if required. Rejects on registration failure. 1239 * chrome.gcm.register() first if required. Rejects on registration failure.
1253 * @return {Promise} A Promise that resolves to a fresh GCM Notification key. 1240 * @return {Promise} A Promise that resolves to a fresh GCM Notification key.
1254 */ 1241 */
1255 function requestNewGcmNotificationKey() { 1242 function requestNewGcmNotificationKey() {
1256 return getGcmRegistrationId().then(function(gcmId) { 1243 return getGcmRegistrationId().then(function(gcmId) {
1257 authenticationManager.getAuthToken().then(function(token) { 1244 authenticationManager.getAuthToken()
1258 authenticationManager.getLogin().then(function(username) { 1245 .then(function(token) {
1259 return new Promise(function(resolve, reject) { 1246 authenticationManager.getLogin().then(function(username) {
1260 var xhr = new XMLHttpRequest(); 1247 return new Promise(function(resolve, reject) {
1261 xhr.responseType = 'application/json'; 1248 var xhr = new XMLHttpRequest();
1262 xhr.open('POST', GCM_REGISTRATION_URL, true); 1249 xhr.responseType = 'application/json';
1263 xhr.setRequestHeader('Content-Type', 'application/json'); 1250 xhr.open('POST', GCM_REGISTRATION_URL, true);
1264 xhr.setRequestHeader('Authorization', 'Bearer ' + token); 1251 xhr.setRequestHeader('Content-Type', 'application/json');
1265 xhr.setRequestHeader('project_id', GCM_PROJECT_ID); 1252 xhr.setRequestHeader('Authorization', 'Bearer ' + token);
1266 var payload = { 1253 xhr.setRequestHeader('project_id', GCM_PROJECT_ID);
1267 'operation': 'add', 1254 var payload = {
1268 'notification_key_name': username, 1255 'operation': 'add',
1269 'registration_ids': [gcmId] 1256 'notification_key_name': username,
1270 }; 1257 'registration_ids': [gcmId]
1271 xhr.onloadend = function() { 1258 };
1272 if (xhr.status != 200) { 1259 xhr.onloadend = function() {
1273 reject(); 1260 if (xhr.status != 200) {
1274 } 1261 reject();
1275 var obj = JSON.parse(xhr.responseText); 1262 }
1276 var key = obj && obj.notification_key; 1263 var obj = JSON.parse(xhr.responseText);
1277 if (!key) { 1264 var key = obj && obj.notification_key;
1278 reject(); 1265 if (!key) {
1279 } 1266 reject();
1280 console.log('gcm notification key POST: ' + key); 1267 }
1281 chrome.storage.local.set({gcmNotificationKey: key}); 1268 console.log('gcm notification key POST: ' + key);
1282 resolve(key); 1269 chrome.storage.local.set({gcmNotificationKey: key});
1283 }; 1270 resolve(key);
1284 xhr.send(JSON.stringify(payload)); 1271 };
1272 xhr.send(JSON.stringify(payload));
1273 });
1274 });
1275 })
1276 .catch(function() {
1277 // Couldn't obtain a GCM ID. Ignore and fallback to polling.
1285 }); 1278 });
1286 });
1287 }).catch(function() {
1288 // Couldn't obtain a GCM ID. Ignore and fallback to polling.
1289 });
1290 }); 1279 });
1291 } 1280 }
1292 1281
1293 /** 1282 /**
1294 * Returns a promise resolving to either a cached or new GCM registration ID. 1283 * Returns a promise resolving to either a cached or new GCM registration ID.
1295 * Rejects if registration fails. 1284 * Rejects if registration fails.
1296 * @return {Promise} A Promise that resolves to a GCM registration ID. 1285 * @return {Promise} A Promise that resolves to a GCM registration ID.
1297 */ 1286 */
1298 function getGcmRegistrationId() { 1287 function getGcmRegistrationId() {
1299 return fillFromChromeLocalStorage({gcmRegistrationId: undefined}) 1288 return fillFromChromeLocalStorage({gcmRegistrationId: undefined})
(...skipping 14 matching lines...) Expand all
1314 } 1303 }
1315 }); 1304 });
1316 }); 1305 });
1317 }); 1306 });
1318 } 1307 }
1319 1308
1320 /** 1309 /**
1321 * Unregisters from GCM if previously registered. 1310 * Unregisters from GCM if previously registered.
1322 */ 1311 */
1323 function unregisterFromGcm() { 1312 function unregisterFromGcm() {
1324 fillFromChromeLocalStorage({gcmRegistrationId: undefined}) 1313 fillFromChromeLocalStorage({
1325 .then(function(items) { 1314 gcmRegistrationId: undefined
1326 if (items.gcmRegistrationId) { 1315 }).then(function(items) {
1327 console.log('Unregistering from gcm.'); 1316 if (items.gcmRegistrationId) {
1328 instrumented.gcm.unregister(function() { 1317 console.log('Unregistering from gcm.');
1329 if (!chrome.runtime.lastError) { 1318 instrumented.gcm.unregister(function() {
1330 chrome.storage.local.remove( 1319 if (!chrome.runtime.lastError) {
1331 ['gcmNotificationKey', 'gcmRegistrationId']); 1320 chrome.storage.local.remove(
1332 } 1321 ['gcmNotificationKey', 'gcmRegistrationId']);
1333 });
1334 } 1322 }
1335 }); 1323 });
1324 }
1325 });
1336 } 1326 }
1337 1327
1338 /** 1328 /**
1339 * Polls the optin state. 1329 * Polls the optin state.
1340 * Sometimes we get the response to the opted in result too soon during 1330 * Sometimes we get the response to the opted in result too soon during
1341 * push messaging. We'll recheck the optin state a few times before giving up. 1331 * push messaging. We'll recheck the optin state a few times before giving up.
1342 */ 1332 */
1343 function pollOptedInWithRecheck() { 1333 function pollOptedInWithRecheck() {
1344 /** 1334 /**
1345 * Cleans up any state used to recheck the opt-in poll. 1335 * Cleans up any state used to recheck the opt-in poll.
1346 */ 1336 */
1347 function clearPollingState() { 1337 function clearPollingState() {
1348 localStorage.removeItem('optedInCheckCount'); 1338 localStorage.removeItem('optedInCheckCount');
1349 optInRecheckAttempts.stop(); 1339 optInRecheckAttempts.stop();
1350 } 1340 }
1351 1341
1352 if (localStorage.optedInCheckCount === undefined) { 1342 if (localStorage.optedInCheckCount === undefined) {
1353 localStorage.optedInCheckCount = 0; 1343 localStorage.optedInCheckCount = 0;
1354 optInRecheckAttempts.start(); 1344 optInRecheckAttempts.start();
1355 } 1345 }
1356 1346
1357 console.log(new Date() + 1347 console.log(
1358 ' checkOptedIn Attempt ' + localStorage.optedInCheckCount); 1348 new Date() + ' checkOptedIn Attempt ' + localStorage.optedInCheckCount);
1359 1349
1360 requestAndUpdateOptedIn().then(function(optedIn) { 1350 requestAndUpdateOptedIn()
1361 if (optedIn) { 1351 .then(function(optedIn) {
1362 clearPollingState(); 1352 if (optedIn) {
1363 return Promise.resolve(); 1353 clearPollingState();
1364 } else { 1354 return Promise.resolve();
1365 // If we're not opted in, reject to retry. 1355 } else {
1366 return Promise.reject(); 1356 // If we're not opted in, reject to retry.
1367 } 1357 return Promise.reject();
1368 }).catch(function() { 1358 }
1369 if (localStorage.optedInCheckCount < 5) { 1359 })
1370 localStorage.optedInCheckCount++; 1360 .catch(function() {
1371 optInRecheckAttempts.scheduleRetry(); 1361 if (localStorage.optedInCheckCount < 5) {
1372 } else { 1362 localStorage.optedInCheckCount++;
1373 clearPollingState(); 1363 optInRecheckAttempts.scheduleRetry();
1374 } 1364 } else {
1375 }); 1365 clearPollingState();
1366 }
1367 });
1376 } 1368 }
1377 1369
1378 instrumented.runtime.onInstalled.addListener(function(details) { 1370 instrumented.runtime.onInstalled.addListener(function(details) {
1379 console.log('onInstalled ' + JSON.stringify(details)); 1371 console.log('onInstalled ' + JSON.stringify(details));
1380 if (details.reason != 'chrome_update') { 1372 if (details.reason != 'chrome_update') {
1381 initialize(); 1373 initialize();
1382 } 1374 }
1383 }); 1375 });
1384 1376
1385 instrumented.runtime.onStartup.addListener(function() { 1377 instrumented.runtime.onStartup.addListener(function() {
(...skipping 16 matching lines...) Expand all
1402 }); 1394 });
1403 1395
1404 initialize(); 1396 initialize();
1405 }); 1397 });
1406 1398
1407 authenticationManager.addListener(function() { 1399 authenticationManager.addListener(function() {
1408 console.log('signIn State Change'); 1400 console.log('signIn State Change');
1409 onStateChange(); 1401 onStateChange();
1410 }); 1402 });
1411 1403
1412 instrumented.notifications.onClicked.addListener( 1404 instrumented.notifications.onClicked.addListener(function(
1413 function(chromeNotificationId) { 1405 chromeNotificationId) {
1414 chrome.metricsPrivate.recordUserAction('GoogleNow.MessageClicked'); 1406 chrome.metricsPrivate.recordUserAction('GoogleNow.MessageClicked');
1415 onNotificationClicked(chromeNotificationId, 1407 onNotificationClicked(chromeNotificationId, function(notificationDataEntry) {
1416 function(notificationDataEntry) { 1408 var actionUrls = notificationDataEntry.actionUrls;
1417 var actionUrls = notificationDataEntry.actionUrls; 1409 var url = actionUrls && actionUrls.messageUrl;
1418 var url = actionUrls && actionUrls.messageUrl; 1410 if (url) {
1419 if (url) { 1411 recordNotificationClick(notificationDataEntry.cardTypeId);
1420 recordNotificationClick(notificationDataEntry.cardTypeId); 1412 }
1421 } 1413 return url;
1422 return url; 1414 });
1423 }); 1415 });
1424 });
1425 1416
1426 instrumented.notifications.onButtonClicked.addListener( 1417 instrumented.notifications.onButtonClicked.addListener(function(
1427 function(chromeNotificationId, buttonIndex) { 1418 chromeNotificationId, buttonIndex) {
1428 chrome.metricsPrivate.recordUserAction( 1419 chrome.metricsPrivate.recordUserAction(
1429 'GoogleNow.ButtonClicked' + buttonIndex); 1420 'GoogleNow.ButtonClicked' + buttonIndex);
1430 onNotificationClicked(chromeNotificationId, 1421 onNotificationClicked(chromeNotificationId, function(notificationDataEntry) {
1431 function(notificationDataEntry) { 1422 var actionUrls = notificationDataEntry.actionUrls;
1432 var actionUrls = notificationDataEntry.actionUrls; 1423 var url = actionUrls.buttonUrls[buttonIndex];
1433 var url = actionUrls.buttonUrls[buttonIndex]; 1424 if (url) {
1434 if (url) { 1425 recordButtonClick(notificationDataEntry.cardTypeId, buttonIndex);
1435 recordButtonClick(notificationDataEntry.cardTypeId, buttonIndex); 1426 } else {
1436 } else { 1427 verify(false, 'onButtonClicked: no url for a button');
1437 verify(false, 'onButtonClicked: no url for a button'); 1428 console.log(
1438 console.log( 1429 'buttonIndex=' + buttonIndex + ' ' +
1439 'buttonIndex=' + buttonIndex + ' ' + 1430 'chromeNotificationId=' + chromeNotificationId + ' ' +
1440 'chromeNotificationId=' + chromeNotificationId + ' ' + 1431 'notificationDataEntry=' + JSON.stringify(notificationDataEntry));
1441 'notificationDataEntry=' + 1432 }
1442 JSON.stringify(notificationDataEntry)); 1433 return url;
1443 } 1434 });
1444 return url; 1435 });
1445 });
1446 });
1447 1436
1448 instrumented.notifications.onClosed.addListener(onNotificationClosed); 1437 instrumented.notifications.onClosed.addListener(onNotificationClosed);
1449 1438
1450 instrumented.notifications.onPermissionLevelChanged.addListener( 1439 instrumented.notifications.onPermissionLevelChanged.addListener(function(
1451 function(permissionLevel) { 1440 permissionLevel) {
1452 console.log('Notifications permissionLevel Change'); 1441 console.log('Notifications permissionLevel Change');
1453 onStateChange(); 1442 onStateChange();
1454 }); 1443 });
1455 1444
1456 instrumented.notifications.onShowSettings.addListener(function() { 1445 instrumented.notifications.onShowSettings.addListener(function() {
1457 openUrl(SETTINGS_URL); 1446 openUrl(SETTINGS_URL);
1458 }); 1447 });
1459 1448
1460 // Handles state change notifications for the Google Now enabled bit. 1449 // Handles state change notifications for the Google Now enabled bit.
1461 instrumented.storage.onChanged.addListener(function(changes, areaName) { 1450 instrumented.storage.onChanged.addListener(function(changes, areaName) {
1462 if (areaName === 'local') { 1451 if (areaName === 'local') {
1463 if ('googleNowEnabled' in changes) { 1452 if ('googleNowEnabled' in changes) {
1464 onStateChange(); 1453 onStateChange();
1465 } 1454 }
1466 } 1455 }
1467 }); 1456 });
1468 1457
1469 instrumented.gcm.onMessage.addListener(function(message) { 1458 instrumented.gcm.onMessage.addListener(function(message) {
1470 console.log('gcm.onMessage ' + JSON.stringify(message)); 1459 console.log('gcm.onMessage ' + JSON.stringify(message));
1471 if (!message || !message.data) { 1460 if (!message || !message.data) {
1472 return; 1461 return;
1473 } 1462 }
1474 1463
1475 var payload = message.data.payload; 1464 var payload = message.data.payload;
1476 var tag = message.data.tag; 1465 var tag = message.data.tag;
1477 if (payload.startsWith('REQUEST_CARDS')) { 1466 if (payload.startsWith('REQUEST_CARDS')) {
1478 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() { 1467 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() {
1479 // Accept promise rejection on failure since it's safer to do nothing, 1468 // Accept promise rejection on failure since it's safer to do nothing,
1480 // preventing polling the server when the payload really didn't change. 1469 // preventing polling the server when the payload really didn't change.
1481 fillFromChromeLocalStorage({ 1470 fillFromChromeLocalStorage(
1482 lastPollNowPayloads: {}, 1471 {
1483 /** @type {Object<StoredNotificationGroup>} */ 1472 lastPollNowPayloads: {},
1484 notificationGroups: {} 1473 /** @type {Object<StoredNotificationGroup>} */
1485 }, PromiseRejection.ALLOW).then(function(items) { 1474 notificationGroups: {}
1486 if (items.lastPollNowPayloads[tag] != payload) { 1475 },
1487 items.lastPollNowPayloads[tag] = payload; 1476 PromiseRejection.ALLOW)
1477 .then(function(items) {
1478 if (items.lastPollNowPayloads[tag] != payload) {
1479 items.lastPollNowPayloads[tag] = payload;
1488 1480
1489 items.notificationGroups['PUSH' + tag] = { 1481 items.notificationGroups['PUSH' + tag] = {
1490 cards: [], 1482 cards: [],
1491 nextPollTime: Date.now() 1483 nextPollTime: Date.now()
1492 }; 1484 };
1493 1485
1494 chrome.storage.local.set({ 1486 chrome.storage.local.set({
1495 lastPollNowPayloads: items.lastPollNowPayloads, 1487 lastPollNowPayloads: items.lastPollNowPayloads,
1496 notificationGroups: items.notificationGroups 1488 notificationGroups: items.notificationGroups
1489 });
1490
1491 pollOptedInWithRecheck();
1492 }
1497 }); 1493 });
1498
1499 pollOptedInWithRecheck();
1500 }
1501 });
1502 }); 1494 });
1503 } 1495 }
1504 }); 1496 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698