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

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

Issue 248473003: Attempt Manager Refactor and Opt-In Pipeline Refactor (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Quick Comment Fix Created 6 years, 7 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
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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 /** 47 /**
48 * Maximal period for polling for Google Now Notifications cards to use when the 48 * Maximal period for polling for Google Now Notifications cards to use when the
49 * period from the server is not available. 49 * period from the server is not available.
50 */ 50 */
51 var MAXIMUM_POLLING_PERIOD_SECONDS = 60 * 60; // 1 hour 51 var MAXIMUM_POLLING_PERIOD_SECONDS = 60 * 60; // 1 hour
52 52
53 /** 53 /**
54 * Initial period for polling for Google Now optin notification after push 54 * Initial period for polling for Google Now optin notification after push
55 * messaging indicates Google Now is enabled. 55 * messaging indicates Google Now is enabled.
56 */ 56 */
57 var INITIAL_OPTIN_POLLING_PERIOD_SECONDS = 60; // 1 minute 57 var INITIAL_OPTIN_RECHECK_PERIOD_SECONDS = 60; // 1 minute
58 58
59 /** 59 /**
60 * Maximum period for polling for Google Now optin notification after push 60 * Maximum period for polling for Google Now optin notification after push
61 * messaging indicates Google Now is enabled. It is expected that the alarm 61 * messaging indicates Google Now is enabled. It is expected that the alarm
62 * will be stopped after this. 62 * will be stopped after this.
63 */ 63 */
64 var MAXIMUM_OPTIN_POLLING_PERIOD_SECONDS = 16 * 60; // 16 minutes 64 var MAXIMUM_OPTIN_RECHECK_PERIOD_SECONDS = 16 * 60; // 16 minutes
65 65
66 /** 66 /**
67 * Initial period for retrying the server request for dismissing cards. 67 * Initial period for retrying the server request for dismissing cards.
68 */ 68 */
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
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 wrapper.instrumentChromeApiFunction( 198 wrapper.instrumentChromeApiFunction(
199 'notifications.onButtonClicked.addListener', 0); 199 'notifications.onButtonClicked.addListener', 0);
200 wrapper.instrumentChromeApiFunction('notifications.onClicked.addListener', 0); 200 wrapper.instrumentChromeApiFunction('notifications.onClicked.addListener', 0);
201 wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0); 201 wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0);
202 wrapper.instrumentChromeApiFunction( 202 wrapper.instrumentChromeApiFunction(
203 'notifications.onPermissionLevelChanged.addListener', 0); 203 'notifications.onPermissionLevelChanged.addListener', 0);
204 wrapper.instrumentChromeApiFunction( 204 wrapper.instrumentChromeApiFunction(
205 'notifications.onShowSettings.addListener', 0); 205 'notifications.onShowSettings.addListener', 0);
206 wrapper.instrumentChromeApiFunction('permissions.contains', 1); 206 wrapper.instrumentChromeApiFunction('permissions.contains', 1);
207 wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0); 207 wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0);
208 wrapper.instrumentChromeApiFunction('storage.onChanged.addListener', 0);
208 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0); 209 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0);
209 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0); 210 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0);
210 wrapper.instrumentChromeApiFunction('tabs.create', 1); 211 wrapper.instrumentChromeApiFunction('tabs.create', 1);
211 212
212 var updateCardsAttempts = buildAttemptManager( 213 var updateCardsAttempts = buildAttemptManager(
213 'cards-update', 214 'cards-update',
214 requestCards, 215 requestCards,
215 INITIAL_POLLING_PERIOD_SECONDS, 216 INITIAL_POLLING_PERIOD_SECONDS,
216 MAXIMUM_POLLING_PERIOD_SECONDS); 217 MAXIMUM_POLLING_PERIOD_SECONDS);
217 var optInCheckAttempts = buildAttemptManager( 218 var optInPollAttempts = buildAttemptManager(
218 'optin', 219 'optin',
219 pollOptedIn, 220 pollOptedInNoImmediateRecheck,
220 INITIAL_OPTIN_POLLING_PERIOD_SECONDS, 221 INITIAL_POLLING_PERIOD_SECONDS,
221 MAXIMUM_OPTIN_POLLING_PERIOD_SECONDS); 222 MAXIMUM_POLLING_PERIOD_SECONDS);
223 var optInRecheckAttempts = buildAttemptManager(
224 'optin-recheck',
225 pollOptedInWithRecheck,
226 INITIAL_OPTIN_RECHECK_PERIOD_SECONDS,
227 MAXIMUM_OPTIN_RECHECK_PERIOD_SECONDS);
222 var dismissalAttempts = buildAttemptManager( 228 var dismissalAttempts = buildAttemptManager(
223 'dismiss', 229 'dismiss',
224 retryPendingDismissals, 230 retryPendingDismissals,
225 INITIAL_RETRY_DISMISS_PERIOD_SECONDS, 231 INITIAL_RETRY_DISMISS_PERIOD_SECONDS,
226 MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS); 232 MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS);
227 var cardSet = buildCardSet(); 233 var cardSet = buildCardSet();
228 234
229 var authenticationManager = buildAuthenticationManager(); 235 var authenticationManager = buildAuthenticationManager();
230 236
231 /** 237 /**
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 }; 424 };
419 425
420 var combinedCard = 426 var combinedCard =
421 combinedCards[receivedNotification.chromeNotificationId] || []; 427 combinedCards[receivedNotification.chromeNotificationId] || [];
422 combinedCard.push(uncombinedNotification); 428 combinedCard.push(uncombinedNotification);
423 combinedCards[receivedNotification.chromeNotificationId] = combinedCard; 429 combinedCards[receivedNotification.chromeNotificationId] = combinedCard;
424 } 430 }
425 } 431 }
426 432
427 /** 433 /**
434 * Calculates the soonest poll time from a map of groups as an absolute time.
435 * @param {Object.<string, StoredNotificationGroup>} groups Map from group name
436 * to group information.
437 * @return {number} The next poll time based off of the groups.
438 */
439 function calculateNextPollTimeMilliseconds(groups) {
440 var nextPollTime = null;
441
442 for (var groupName in groups) {
443 var group = groups[groupName];
444 if (group.nextPollTime !== undefined) {
445 nextPollTime = nextPollTime == null ?
446 group.nextPollTime : Math.min(group.nextPollTime, nextPollTime);
447 }
448 }
449
450 // At least one of the groups must have nextPollTime.
451 verify(nextPollTime != null, 'calculateNextPollTime: nextPollTime is null');
452 return nextPollTime;
453 }
454
455 /**
428 * Schedules next cards poll. 456 * Schedules next cards poll.
429 * @param {Object.<string, StoredNotificationGroup>} groups Map from group name 457 * @param {Object.<string, StoredNotificationGroup>} groups Map from group name
430 * to group information. 458 * to group information.
431 * @param {boolean} isOptedIn True if the user is opted in to Google Now.
432 */ 459 */
433 function scheduleNextPoll(groups, isOptedIn) { 460 function scheduleNextCardsPoll(groups) {
434 if (isOptedIn) { 461 var nextPollTimeMs = calculateNextPollTimeMilliseconds(groups);
435 var nextPollTime = null;
436 462
437 for (var groupName in groups) { 463 var nextPollDelaySeconds = Math.max(
438 var group = groups[groupName]; 464 (nextPollTimeMs - Date.now()) / MS_IN_SECOND,
439 if (group.nextPollTime !== undefined) { 465 MINIMUM_POLLING_PERIOD_SECONDS);
440 nextPollTime = nextPollTime == null ? 466 updateCardsAttempts.start(nextPollDelaySeconds);
441 group.nextPollTime : Math.min(group.nextPollTime, nextPollTime);
442 }
443 }
444
445 // At least one of the groups must have nextPollTime.
446 verify(nextPollTime != null, 'scheduleNextPoll: nextPollTime is null');
447
448 var nextPollDelaySeconds = Math.max(
449 (nextPollTime - Date.now()) / MS_IN_SECOND,
450 MINIMUM_POLLING_PERIOD_SECONDS);
451 updateCardsAttempts.start(nextPollDelaySeconds);
452 } else {
453 instrumented.metricsPrivate.getVariationParams(
454 'GoogleNow', function(params) {
455 var optinPollPeriodSeconds =
456 parseInt(params && params.optinPollPeriodSeconds, 10) ||
457 DEFAULT_OPTIN_CHECK_PERIOD_SECONDS;
458 updateCardsAttempts.start(optinPollPeriodSeconds);
459 });
460 }
461 } 467 }
462 468
463 /** 469 /**
470 * Schedules the next opt-in check poll.
471 */
472 function scheduleOptInCheckPoll() {
473 instrumented.metricsPrivate.getVariationParams(
474 'GoogleNow', function(params) {
475 var optinPollPeriodSeconds =
476 parseInt(params && params.optinPollPeriodSeconds, 10) ||
477 DEFAULT_OPTIN_CHECK_PERIOD_SECONDS;
478 optInPollAttempts.start(optinPollPeriodSeconds);
479 });
480 }
481
482 /**
464 * Combines notification groups into a set of Chrome notifications. 483 * Combines notification groups into a set of Chrome notifications.
465 * @param {Object.<string, StoredNotificationGroup>} notificationGroups Map from 484 * @param {Object.<string, StoredNotificationGroup>} notificationGroups Map from
466 * group name to group information. 485 * group name to group information.
467 * @return {Object.<ChromeNotificationId, CombinedCard>} Cards to show. 486 * @return {Object.<ChromeNotificationId, CombinedCard>} Cards to show.
468 */ 487 */
469 function combineCardsFromGroups(notificationGroups) { 488 function combineCardsFromGroups(notificationGroups) {
470 console.log('combineCardsFromGroups ' + JSON.stringify(notificationGroups)); 489 console.log('combineCardsFromGroups ' + JSON.stringify(notificationGroups));
471 /** @type {Object.<ChromeNotificationId, CombinedCard>} */ 490 /** @type {Object.<ChromeNotificationId, CombinedCard>} */
472 var combinedCards = {}; 491 var combinedCards = {};
473 492
474 for (var groupName in notificationGroups) 493 for (var groupName in notificationGroups)
475 combineGroup(combinedCards, notificationGroups[groupName]); 494 combineGroup(combinedCards, notificationGroups[groupName]);
476 495
477 return combinedCards; 496 return combinedCards;
478 } 497 }
479 498
480 /** 499 /**
481 * Processes a server response for consumption by showNotificationGroups. 500 * Processes a server response for consumption by showNotificationGroups.
482 * @param {ServerResponse} response Server response. 501 * @param {ServerResponse} response Server response.
483 * @return {Promise} A promise to process the server response and provide 502 * @return {Promise} A promise to process the server response and provide
484 * updated groups. Rejects if the server response shouldn't be processed. 503 * updated groups. Rejects if the server response shouldn't be processed.
485 */ 504 */
486 function processServerResponse(response) { 505 function processServerResponse(response) {
487 console.log('processServerResponse ' + JSON.stringify(response)); 506 console.log('processServerResponse ' + JSON.stringify(response));
488 507
489 if (response.googleNowDisabled) { 508 if (response.googleNowDisabled) {
490 chrome.storage.local.set({googleNowEnabled: false}); 509 chrome.storage.local.set({googleNowEnabled: false});
491 // TODO(robliao): Remove the line below once the server stops sending groups
492 // with 'googleNowDisabled' responses.
493 response.groups = {};
494 // Google Now was enabled; now it's disabled. This is a state change.
495 onStateChange();
496 // Start the Google Now Disabled polling period.
497 scheduleNextPoll({}, false);
498 // Stop processing now. The state change will clear the cards. 510 // Stop processing now. The state change will clear the cards.
499 return Promise.reject(); 511 return Promise.reject();
500 } 512 }
501 513
502 var receivedGroups = response.groups; 514 var receivedGroups = response.groups;
503 515
504 return fillFromChromeLocalStorage({ 516 return fillFromChromeLocalStorage({
505 /** @type {Object.<string, StoredNotificationGroup>} */ 517 /** @type {Object.<string, StoredNotificationGroup>} */
506 notificationGroups: {}, 518 notificationGroups: {},
507 /** @type {Object.<ServerNotificationId, number>} */ 519 /** @type {Object.<ServerNotificationId, number>} */
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 // 'nextPollSeconds' may be sent even for groups that don't contain 578 // 'nextPollSeconds' may be sent even for groups that don't contain
567 // cards updates. 579 // cards updates.
568 if (receivedGroup.nextPollSeconds !== undefined) { 580 if (receivedGroup.nextPollSeconds !== undefined) {
569 storedGroup.nextPollTime = 581 storedGroup.nextPollTime =
570 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; 582 now + receivedGroup.nextPollSeconds * MS_IN_SECOND;
571 } 583 }
572 584
573 updatedGroups[groupName] = storedGroup; 585 updatedGroups[groupName] = storedGroup;
574 } 586 }
575 587
576 scheduleNextPoll(updatedGroups, !response.googleNowDisabled); 588 scheduleNextCardsPoll(updatedGroups);
577 return { 589 return {
578 updatedGroups: updatedGroups, 590 updatedGroups: updatedGroups,
579 recentDismissals: updatedRecentDismissals 591 recentDismissals: updatedRecentDismissals
580 }; 592 };
581 }); 593 });
582 } 594 }
583 595
584 /** 596 /**
585 * Update the Explanatory Total Cards Shown Count. 597 * Update the Explanatory Total Cards Shown Count.
586 */ 598 */
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 console.log( 643 console.log(
632 'requestNotificationGroupsFromServer-received ' + request.status); 644 'requestNotificationGroupsFromServer-received ' + request.status);
633 if (request.status == HTTP_OK) { 645 if (request.status == HTTP_OK) {
634 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); 646 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
635 return JSON.parse(request.responseText); 647 return JSON.parse(request.responseText);
636 } 648 }
637 }); 649 });
638 } 650 }
639 651
640 /** 652 /**
653 * Performs an opt-in poll without an immediate recheck.
654 * If the response is not opted-in, schedule an opt-in check poll.
655 */
656 function pollOptedInNoImmediateRecheck() {
657 requestAndUpdateOptedIn()
658 .then(function(optedIn) {
659 if (!optedIn) {
660 // Request a repoll if we're not opted in.
661 return Promise.reject();
662 }
663 })
664 .catch(function() {
665 scheduleOptInCheckPoll();
666 });
667 }
668
669 /**
641 * Requests the account opted-in state from the server and updates any 670 * Requests the account opted-in state from the server and updates any
642 * state as necessary. 671 * state as necessary.
643 * @return {Promise} A promise to request and update the opted-in state. 672 * @return {Promise} A promise to request and update the opted-in state.
644 * The promise resolves if the opt-in state is true. 673 * The promise resolves with the opt-in state.
645 */ 674 */
646 function requestAndUpdateOptedIn() { 675 function requestAndUpdateOptedIn() {
647 console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL); 676 console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL);
648 677
649 return requestFromServer('GET', 'settings/optin').then(function(request) { 678 return requestFromServer('GET', 'settings/optin').then(function(request) {
650 console.log( 679 console.log(
651 'requestOptedIn-received ' + request.status + ' ' + request.response); 680 'requestOptedIn-received ' + request.status + ' ' + request.response);
652 if (request.status == HTTP_OK) { 681 if (request.status == HTTP_OK) {
653 var parsedResponse = JSON.parse(request.responseText); 682 var parsedResponse = JSON.parse(request.responseText);
654 return parsedResponse.value; 683 return parsedResponse.value;
655 } 684 }
656 }).then(function(optedIn) { 685 }).then(function(optedIn) {
657 if (optedIn) { 686 chrome.storage.local.set({googleNowEnabled: optedIn});
658 chrome.storage.local.set({googleNowEnabled: true}); 687 return optedIn;
659 // Google Now was disabled, now it's enabled. This is a state change.
660 onStateChange();
661 return Promise.resolve();
662 } else {
663 scheduleNextPoll({}, false);
664 return Promise.reject();
665 }
666 }); 688 });
667 } 689 }
668 690
669 /** 691 /**
670 * Determines the groups that need to be requested right now. 692 * Determines the groups that need to be requested right now.
671 * @return {Promise} A promise to determine the groups to request. 693 * @return {Promise} A promise to determine the groups to request.
672 */ 694 */
673 function getGroupsToRequest() { 695 function getGroupsToRequest() {
674 return fillFromChromeLocalStorage({ 696 return fillFromChromeLocalStorage({
675 /** @type {Object.<string, StoredNotificationGroup>} */ 697 /** @type {Object.<string, StoredNotificationGroup>} */
(...skipping 12 matching lines...) Expand all
688 }); 710 });
689 } 711 }
690 712
691 /** 713 /**
692 * Requests notification cards from the server. 714 * Requests notification cards from the server.
693 * @return {Promise} A promise to request the notification cards. 715 * @return {Promise} A promise to request the notification cards.
694 * Rejects if the cards won't be requested. 716 * Rejects if the cards won't be requested.
695 */ 717 */
696 function requestNotificationCards() { 718 function requestNotificationCards() {
697 console.log('requestNotificationCards'); 719 console.log('requestNotificationCards');
698 720 return getGroupsToRequest()
699 return isGoogleNowEnabled()
700 .then(function(googleNowEnabled) {
701 return googleNowEnabled ? Promise.resolve() : requestAndUpdateOptedIn();
702 })
703 .then(getGroupsToRequest)
704 .then(requestNotificationGroupsFromServer) 721 .then(requestNotificationGroupsFromServer)
705 .then(processServerResponse) 722 .then(processServerResponse)
706 .then(function(processedResponse) { 723 .then(function(processedResponse) {
707 var onCardShown = 724 var onCardShown =
708 shouldShowExplanatoryCard() ? countExplanatoryCard : undefined; 725 shouldShowExplanatoryCard() ? countExplanatoryCard : undefined;
709 return showNotificationGroups( 726 return showNotificationGroups(
710 processedResponse.updatedGroups, onCardShown).then(function() { 727 processedResponse.updatedGroups, onCardShown).then(function() {
711 chrome.storage.local.set({ 728 chrome.storage.local.set({
712 notificationGroups: processedResponse.updatedGroups, 729 notificationGroups: processedResponse.updatedGroups,
713 recentDismissals: processedResponse.updatedRecentDismissals 730 recentDismissals: processedResponse.updatedRecentDismissals
(...skipping 10 matching lines...) Expand all
724 function requestCards() { 741 function requestCards() {
725 console.log('requestCards @' + new Date()); 742 console.log('requestCards @' + new Date());
726 // LOCATION_REQUEST is a legacy histogram value when we requested location. 743 // LOCATION_REQUEST is a legacy histogram value when we requested location.
727 // This corresponds to the extension attempting to request for cards. 744 // This corresponds to the extension attempting to request for cards.
728 // We're keeping the name the same to keep our histograms in order. 745 // We're keeping the name the same to keep our histograms in order.
729 recordEvent(GoogleNowEvent.LOCATION_REQUEST); 746 recordEvent(GoogleNowEvent.LOCATION_REQUEST);
730 tasks.add(UPDATE_CARDS_TASK_NAME, function() { 747 tasks.add(UPDATE_CARDS_TASK_NAME, function() {
731 console.log('requestCards-task-begin'); 748 console.log('requestCards-task-begin');
732 updateCardsAttempts.isRunning(function(running) { 749 updateCardsAttempts.isRunning(function(running) {
733 if (running) { 750 if (running) {
734 updateCardsAttempts.planForNext(function() { 751 // The cards are requested only if there are no unsent dismissals.
735 // The cards are requested only if there are no unsent dismissals. 752 processPendingDismissals()
736 processPendingDismissals().then(requestNotificationCards); 753 .then(requestNotificationCards)
737 }); 754 .catch(updateCardsAttempts.scheduleRetry);
738 } 755 }
739 }); 756 });
740 }); 757 });
741 } 758 }
742 759
743 /** 760 /**
744 * Sends a server request to dismiss a card. 761 * Sends a server request to dismiss a card.
745 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of 762 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of
746 * the card. 763 * the card.
747 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in 764 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
844 861
845 return doProcessDismissals(); 862 return doProcessDismissals();
846 }); 863 });
847 } 864 }
848 865
849 /** 866 /**
850 * Submits a task to send pending dismissals. 867 * Submits a task to send pending dismissals.
851 */ 868 */
852 function retryPendingDismissals() { 869 function retryPendingDismissals() {
853 tasks.add(RETRY_DISMISS_TASK_NAME, function() { 870 tasks.add(RETRY_DISMISS_TASK_NAME, function() {
854 dismissalAttempts.planForNext(function() { 871 processPendingDismissals().catch(dismissalAttempts.scheduleRetry);
855 processPendingDismissals();
856 });
857 }); 872 });
858 } 873 }
859 874
860 /** 875 /**
861 * Opens a URL in a new tab. 876 * Opens a URL in a new tab.
862 * @param {string} url URL to open. 877 * @param {string} url URL to open.
863 */ 878 */
864 function openUrl(url) { 879 function openUrl(url) {
865 instrumented.tabs.create({url: url}, function(tab) { 880 instrumented.tabs.create({url: url}, function(tab) {
866 if (tab) 881 if (tab)
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
999 else 1014 else
1000 stopPollingCards(); 1015 stopPollingCards();
1001 } else { 1016 } else {
1002 console.log( 1017 console.log(
1003 'Action Ignored setShouldPollCards=' + shouldPollCardsRequest); 1018 'Action Ignored setShouldPollCards=' + shouldPollCardsRequest);
1004 } 1019 }
1005 }); 1020 });
1006 } 1021 }
1007 1022
1008 /** 1023 /**
1024 * Starts or stops the optin check.
1025 * @param {boolean} shouldPollOptInStatus true to start and false to stop
1026 * polling the optin status.
1027 */
1028 function setShouldPollOptInStatus(shouldPollOptInStatus) {
1029 optInPollAttempts.isRunning(function(currentValue) {
1030 if (shouldPollOptInStatus != currentValue) {
1031 console.log(
1032 'Action Taken setShouldPollOptInStatus=' + shouldPollOptInStatus);
1033 if (shouldPollOptInStatus) {
1034 pollOptedInNoImmediateRecheck();
1035 } else {
1036 optInPollAttempts.stop();
1037 }
1038 } else {
1039 console.log(
1040 'Action Ignored setShouldPollOptInStatus=' + shouldPollOptInStatus);
1041 }
1042 });
1043 }
1044
1045 /**
1009 * Enables or disables the Google Now background permission. 1046 * Enables or disables the Google Now background permission.
1010 * @param {boolean} backgroundEnable true to run in the background. 1047 * @param {boolean} backgroundEnable true to run in the background.
1011 * false to not run in the background. 1048 * false to not run in the background.
1012 */ 1049 */
1013 function setBackgroundEnable(backgroundEnable) { 1050 function setBackgroundEnable(backgroundEnable) {
1014 instrumented.permissions.contains({permissions: ['background']}, 1051 instrumented.permissions.contains({permissions: ['background']},
1015 function(hasPermission) { 1052 function(hasPermission) {
1016 if (backgroundEnable != hasPermission) { 1053 if (backgroundEnable != hasPermission) {
1017 console.log('Action Taken setBackgroundEnable=' + backgroundEnable); 1054 console.log('Action Taken setBackgroundEnable=' + backgroundEnable);
1018 if (backgroundEnable) 1055 if (backgroundEnable)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1059 canEnableBackground, 1096 canEnableBackground,
1060 notificationEnabled, 1097 notificationEnabled,
1061 googleNowEnabled) { 1098 googleNowEnabled) {
1062 console.log( 1099 console.log(
1063 'State Update signedIn=' + signedIn + ' ' + 1100 'State Update signedIn=' + signedIn + ' ' +
1064 'canEnableBackground=' + canEnableBackground + ' ' + 1101 'canEnableBackground=' + canEnableBackground + ' ' +
1065 'notificationEnabled=' + notificationEnabled + ' ' + 1102 'notificationEnabled=' + notificationEnabled + ' ' +
1066 'googleNowEnabled=' + googleNowEnabled); 1103 'googleNowEnabled=' + googleNowEnabled);
1067 1104
1068 var shouldPollCards = false; 1105 var shouldPollCards = false;
1106 var shouldPollOptInStatus = false;
1069 var shouldSetBackground = false; 1107 var shouldSetBackground = false;
1070 var shouldClearCards = true;
1071 1108
1072 if (signedIn && notificationEnabled) { 1109 if (signedIn && notificationEnabled) {
1073 shouldClearCards = !googleNowEnabled; 1110 shouldPollCards = googleNowEnabled;
1111 shouldPollOptInStatus = !googleNowEnabled;
1074 shouldSetBackground = canEnableBackground && googleNowEnabled; 1112 shouldSetBackground = canEnableBackground && googleNowEnabled;
1075 shouldPollCards = true;
1076 } else { 1113 } else {
1077 recordEvent(GoogleNowEvent.STOPPED); 1114 recordEvent(GoogleNowEvent.STOPPED);
1078 } 1115 }
1079 1116
1080 recordEventIfNoCards(signedIn, notificationEnabled, googleNowEnabled); 1117 recordEventIfNoCards(signedIn, notificationEnabled, googleNowEnabled);
1081 1118
1082 console.log( 1119 console.log(
1083 'Requested Actions shouldSetBackground=' + shouldSetBackground + ' ' + 1120 'Requested Actions shouldSetBackground=' + shouldSetBackground + ' ' +
1084 'setShouldPollCards=' + shouldPollCards + ' ' + 1121 'setShouldPollCards=' + shouldPollCards + ' ' +
1085 'shouldClearCards=' + shouldClearCards); 1122 'shouldPollOptInStatus=' + shouldPollOptInStatus);
1086 1123
1087 setBackgroundEnable(shouldSetBackground); 1124 setBackgroundEnable(shouldSetBackground);
1088 setShouldPollCards(shouldPollCards); 1125 setShouldPollCards(shouldPollCards);
1089 if (shouldClearCards) { 1126 setShouldPollOptInStatus(shouldPollOptInStatus);
1127 if (!shouldPollCards) {
1090 removeAllCards(); 1128 removeAllCards();
1091 } 1129 }
1092 } 1130 }
1093 1131
1094 /** 1132 /**
1095 * Coordinates the behavior of Google Now for Chrome depending on 1133 * Coordinates the behavior of Google Now for Chrome depending on
1096 * Chrome and extension state. 1134 * Chrome and extension state.
1097 */ 1135 */
1098 function onStateChange() { 1136 function onStateChange() {
1099 tasks.add(STATE_CHANGED_TASK_NAME, function() { 1137 tasks.add(STATE_CHANGED_TASK_NAME, function() {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1145 .then(function(items) { 1183 .then(function(items) {
1146 return items.googleNowEnabled; 1184 return items.googleNowEnabled;
1147 }); 1185 });
1148 } 1186 }
1149 1187
1150 /** 1188 /**
1151 * Polls the optin state. 1189 * Polls the optin state.
1152 * Sometimes we get the response to the opted in result too soon during 1190 * Sometimes we get the response to the opted in result too soon during
1153 * push messaging. We'll recheck the optin state a few times before giving up. 1191 * push messaging. We'll recheck the optin state a few times before giving up.
1154 */ 1192 */
1155 function pollOptedIn() { 1193 function pollOptedInWithRecheck() {
1156 /** 1194 /**
1157 * Cleans up any state used to recheck the opt-in poll. 1195 * Cleans up any state used to recheck the opt-in poll.
1158 */ 1196 */
1159 function clearPollingState() { 1197 function clearPollingState() {
1160 localStorage.removeItem('optedInCheckCount'); 1198 localStorage.removeItem('optedInCheckCount');
1161 optInCheckAttempts.stop(); 1199 optInRecheckAttempts.stop();
1162 } 1200 }
1163 1201
1164 if (localStorage.optedInCheckCount === undefined) { 1202 if (localStorage.optedInCheckCount === undefined) {
1165 localStorage.optedInCheckCount = 0; 1203 localStorage.optedInCheckCount = 0;
1166 optInCheckAttempts.start(); 1204 optInRecheckAttempts.start();
1167 } 1205 }
1168 1206
1169 console.log(new Date() + 1207 console.log(new Date() +
1170 ' checkOptedIn Attempt ' + localStorage.optedInCheckCount); 1208 ' checkOptedIn Attempt ' + localStorage.optedInCheckCount);
1171 1209
1172 requestAndUpdateOptedIn().then(function() { 1210 requestAndUpdateOptedIn().then(function(optedIn) {
1173 clearPollingState(); 1211 if (optedIn) {
1174 requestCards(); 1212 clearPollingState();
1213 return Promise.resolve();
1214 } else {
1215 // If we're not opted in, reject to retry.
1216 return Promise.reject();
1217 }
1175 }).catch(function() { 1218 }).catch(function() {
1176 if (localStorage.optedInCheckCount < 5) { 1219 if (localStorage.optedInCheckCount < 5) {
1177 localStorage.optedInCheckCount++; 1220 localStorage.optedInCheckCount++;
1178 optInCheckAttempts.planForNext(function() {}); 1221 optInRecheckAttempts.scheduleRetry();
1179 } else { 1222 } else {
1180 clearPollingState(); 1223 clearPollingState();
1181 } 1224 }
1182 }); 1225 });
1183 } 1226 }
1184 1227
1185 instrumented.runtime.onInstalled.addListener(function(details) { 1228 instrumented.runtime.onInstalled.addListener(function(details) {
1186 console.log('onInstalled ' + JSON.stringify(details)); 1229 console.log('onInstalled ' + JSON.stringify(details));
1187 if (details.reason != 'chrome_update') { 1230 if (details.reason != 'chrome_update') {
1188 initialize(); 1231 initialize();
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1252 instrumented.notifications.onPermissionLevelChanged.addListener( 1295 instrumented.notifications.onPermissionLevelChanged.addListener(
1253 function(permissionLevel) { 1296 function(permissionLevel) {
1254 console.log('Notifications permissionLevel Change'); 1297 console.log('Notifications permissionLevel Change');
1255 onStateChange(); 1298 onStateChange();
1256 }); 1299 });
1257 1300
1258 instrumented.notifications.onShowSettings.addListener(function() { 1301 instrumented.notifications.onShowSettings.addListener(function() {
1259 openUrl(SETTINGS_URL); 1302 openUrl(SETTINGS_URL);
1260 }); 1303 });
1261 1304
1305 // Handles state change notifications for the Google Now enabled bit.
1306 instrumented.storage.onChanged.addListener(function(changes, areaName) {
1307 if (areaName === 'local') {
1308 if ('googleNowEnabled' in changes) {
1309 onStateChange();
1310 }
1311 }
1312 });
1313
1262 instrumented.pushMessaging.onMessage.addListener(function(message) { 1314 instrumented.pushMessaging.onMessage.addListener(function(message) {
1263 // message.payload will be '' when the extension first starts. 1315 // message.payload will be '' when the extension first starts.
1264 // Each time after signing in, we'll get latest payload for all channels. 1316 // Each time after signing in, we'll get latest payload for all channels.
1265 // So, we need to poll the server only when the payload is non-empty and has 1317 // So, we need to poll the server only when the payload is non-empty and has
1266 // changed. 1318 // changed.
1267 console.log('pushMessaging.onMessage ' + JSON.stringify(message)); 1319 console.log('pushMessaging.onMessage ' + JSON.stringify(message));
1268 if (message.payload.indexOf('REQUEST_CARDS') == 0) { 1320 if (message.payload.indexOf('REQUEST_CARDS') == 0) {
1269 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() { 1321 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() {
1270 // Accept promise rejection on failure since it's safer to do nothing, 1322 // Accept promise rejection on failure since it's safer to do nothing,
1271 // preventing polling the server when the payload really didn't change. 1323 // preventing polling the server when the payload really didn't change.
1272 fillFromChromeLocalStorage({ 1324 fillFromChromeLocalStorage({
1273 lastPollNowPayloads: {}, 1325 lastPollNowPayloads: {},
1274 /** @type {Object.<string, StoredNotificationGroup>} */ 1326 /** @type {Object.<string, StoredNotificationGroup>} */
1275 notificationGroups: {} 1327 notificationGroups: {}
1276 }, PromiseRejection.ALLOW).then(function(items) { 1328 }, PromiseRejection.ALLOW).then(function(items) {
1277 if (items.lastPollNowPayloads[message.subchannelId] != 1329 if (items.lastPollNowPayloads[message.subchannelId] !=
1278 message.payload) { 1330 message.payload) {
1279 items.lastPollNowPayloads[message.subchannelId] = message.payload; 1331 items.lastPollNowPayloads[message.subchannelId] = message.payload;
1280 1332
1281 items.notificationGroups['PUSH' + message.subchannelId] = { 1333 items.notificationGroups['PUSH' + message.subchannelId] = {
1282 cards: [], 1334 cards: [],
1283 nextPollTime: Date.now() 1335 nextPollTime: Date.now()
1284 }; 1336 };
1285 1337
1286 chrome.storage.local.set({ 1338 chrome.storage.local.set({
1287 lastPollNowPayloads: items.lastPollNowPayloads, 1339 lastPollNowPayloads: items.lastPollNowPayloads,
1288 notificationGroups: items.notificationGroups 1340 notificationGroups: items.notificationGroups
1289 }); 1341 });
1290 1342
1291 pollOptedIn(); 1343 pollOptedInWithRecheck();
1292 } 1344 }
1293 }); 1345 });
1294 }); 1346 });
1295 } 1347 }
1296 }); 1348 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698