OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 'use strict'; | 5 'use strict'; |
6 | 6 |
7 /** | 7 /** |
8 * @fileoverview The event page for Google Now for Chrome implementation. | 8 * @fileoverview The event page for Google Now for Chrome implementation. |
9 * The Google Now event page gets Google Now cards from the server and shows | 9 * The Google Now event page gets Google Now cards from the server and shows |
10 * them as Chrome notifications. | 10 * them as Chrome notifications. |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0); | 189 wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0); |
190 wrapper.instrumentChromeApiFunction( | 190 wrapper.instrumentChromeApiFunction( |
191 'notifications.onPermissionLevelChanged.addListener', 0); | 191 'notifications.onPermissionLevelChanged.addListener', 0); |
192 wrapper.instrumentChromeApiFunction( | 192 wrapper.instrumentChromeApiFunction( |
193 'notifications.onShowSettings.addListener', 0); | 193 'notifications.onShowSettings.addListener', 0); |
194 wrapper.instrumentChromeApiFunction('permissions.contains', 1); | 194 wrapper.instrumentChromeApiFunction('permissions.contains', 1); |
195 wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0); | 195 wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0); |
196 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0); | 196 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0); |
197 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0); | 197 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0); |
198 wrapper.instrumentChromeApiFunction('tabs.create', 1); | 198 wrapper.instrumentChromeApiFunction('tabs.create', 1); |
199 wrapper.instrumentChromeApiFunction('storage.local.get', 1); | |
200 | 199 |
201 var updateCardsAttempts = buildAttemptManager( | 200 var updateCardsAttempts = buildAttemptManager( |
202 'cards-update', | 201 'cards-update', |
203 requestCards, | 202 requestCards, |
204 INITIAL_POLLING_PERIOD_SECONDS, | 203 INITIAL_POLLING_PERIOD_SECONDS, |
205 MAXIMUM_POLLING_PERIOD_SECONDS); | 204 MAXIMUM_POLLING_PERIOD_SECONDS); |
206 var dismissalAttempts = buildAttemptManager( | 205 var dismissalAttempts = buildAttemptManager( |
207 'dismiss', | 206 'dismiss', |
208 retryPendingDismissals, | 207 retryPendingDismissals, |
209 INITIAL_RETRY_DISMISS_PERIOD_SECONDS, | 208 INITIAL_RETRY_DISMISS_PERIOD_SECONDS, |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 chrome.storage.local.set({googleNowEnabled: false}); | 438 chrome.storage.local.set({googleNowEnabled: false}); |
440 // TODO(vadimt): Remove the line below once the server stops sending groups | 439 // TODO(vadimt): Remove the line below once the server stops sending groups |
441 // with 'googleNowDisabled' responses. | 440 // with 'googleNowDisabled' responses. |
442 response.groups = {}; | 441 response.groups = {}; |
443 // Google Now was enabled; now it's disabled. This is a state change. | 442 // Google Now was enabled; now it's disabled. This is a state change. |
444 onStateChange(); | 443 onStateChange(); |
445 } | 444 } |
446 | 445 |
447 var receivedGroups = response.groups; | 446 var receivedGroups = response.groups; |
448 | 447 |
449 instrumented.storage.local.get( | 448 fillFromChromeLocalStorage({ |
450 ['notificationGroups', 'recentDismissals'], | 449 /** @type {Object.<string, StoredNotificationGroup>} */ |
451 function(items) { | 450 notificationGroups: {}, |
452 console.log( | 451 /** @type {Object.<NotificationId, number>} */ |
453 'processServerResponse-get ' + JSON.stringify(items)); | 452 recentDismissals: {} |
454 items = items || {}; | 453 }).then(function(items) { |
455 /** @type {Object.<string, StoredNotificationGroup>} */ | 454 console.log('processServerResponse-get ' + JSON.stringify(items)); |
456 items.notificationGroups = items.notificationGroups || {}; | |
457 /** @type {Object.<NotificationId, number>} */ | |
458 items.recentDismissals = items.recentDismissals || {}; | |
459 | 455 |
460 // Build a set of non-expired recent dismissals. It will be used for | 456 // Build a set of non-expired recent dismissals. It will be used for |
461 // client-side filtering of cards. | 457 // client-side filtering of cards. |
462 /** @type {Object.<NotificationId, number>} */ | 458 /** @type {Object.<NotificationId, number>} */ |
463 var updatedRecentDismissals = {}; | 459 var updatedRecentDismissals = {}; |
464 var now = Date.now(); | 460 var now = Date.now(); |
465 for (var notificationId in items.recentDismissals) { | 461 for (var notificationId in items.recentDismissals) { |
466 var dismissalAge = now - items.recentDismissals[notificationId]; | 462 var dismissalAge = now - items.recentDismissals[notificationId]; |
467 if (dismissalAge < DISMISS_RETENTION_TIME_MS) { | 463 if (dismissalAge < DISMISS_RETENTION_TIME_MS) { |
468 updatedRecentDismissals[notificationId] = | 464 updatedRecentDismissals[notificationId] = |
469 items.recentDismissals[notificationId]; | 465 items.recentDismissals[notificationId]; |
470 } | 466 } |
| 467 } |
| 468 |
| 469 // Populate groups with corresponding cards. |
| 470 if (response.notifications) { |
| 471 for (var i = 0; i < response.notifications.length; ++i) { |
| 472 /** @type {ReceivedNotification} */ |
| 473 var card = response.notifications[i]; |
| 474 if (!(card.notificationId in updatedRecentDismissals)) { |
| 475 var group = receivedGroups[card.groupName]; |
| 476 group.cards = group.cards || []; |
| 477 group.cards.push(card); |
471 } | 478 } |
| 479 } |
| 480 } |
472 | 481 |
473 // Populate groups with corresponding cards. | 482 // Build updated set of groups. |
474 if (response.notifications) { | 483 var updatedGroups = {}; |
475 for (var i = 0; i < response.notifications.length; ++i) { | |
476 /** @type {ReceivedNotification} */ | |
477 var card = response.notifications[i]; | |
478 if (!(card.notificationId in updatedRecentDismissals)) { | |
479 var group = receivedGroups[card.groupName]; | |
480 group.cards = group.cards || []; | |
481 group.cards.push(card); | |
482 } | |
483 } | |
484 } | |
485 | 484 |
486 // Build updated set of groups. | 485 for (var groupName in receivedGroups) { |
487 var updatedGroups = {}; | 486 var receivedGroup = receivedGroups[groupName]; |
| 487 var storedGroup = items.notificationGroups[groupName] || { |
| 488 cards: [], |
| 489 cardsTimestamp: undefined, |
| 490 nextPollTime: undefined, |
| 491 rank: undefined |
| 492 }; |
488 | 493 |
489 for (var groupName in receivedGroups) { | 494 if (receivedGroup.requested) |
490 var receivedGroup = receivedGroups[groupName]; | 495 receivedGroup.cards = receivedGroup.cards || []; |
491 var storedGroup = items.notificationGroups[groupName] || { | |
492 cards: [], | |
493 cardsTimestamp: undefined, | |
494 nextPollTime: undefined, | |
495 rank: undefined | |
496 }; | |
497 | 496 |
498 if (receivedGroup.requested) | 497 if (receivedGroup.cards) { |
499 receivedGroup.cards = receivedGroup.cards || []; | 498 // If the group contains a cards update, all its fields will get new |
| 499 // values. |
| 500 storedGroup.cards = receivedGroup.cards; |
| 501 storedGroup.cardsTimestamp = now; |
| 502 storedGroup.rank = receivedGroup.rank; |
| 503 storedGroup.nextPollTime = undefined; |
| 504 // The code below assigns nextPollTime a defined value if |
| 505 // nextPollSeconds is specified in the received group. |
| 506 // If the group's cards are not updated, and nextPollSeconds is |
| 507 // unspecified, this method doesn't change group's nextPollTime. |
| 508 } |
500 | 509 |
501 if (receivedGroup.cards) { | 510 // 'nextPollSeconds' may be sent even for groups that don't contain |
502 // If the group contains a cards update, all its fields will get new | 511 // cards updates. |
503 // values. | 512 if (receivedGroup.nextPollSeconds !== undefined) { |
504 storedGroup.cards = receivedGroup.cards; | 513 storedGroup.nextPollTime = |
505 storedGroup.cardsTimestamp = now; | 514 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; |
506 storedGroup.rank = receivedGroup.rank; | 515 } |
507 storedGroup.nextPollTime = undefined; | |
508 // The code below assigns nextPollTime a defined value if | |
509 // nextPollSeconds is specified in the received group. | |
510 // If the group's cards are not updated, and nextPollSeconds is | |
511 // unspecified, this method doesn't change group's nextPollTime. | |
512 } | |
513 | 516 |
514 // 'nextPollSeconds' may be sent even for groups that don't contain | 517 updatedGroups[groupName] = storedGroup; |
515 // cards updates. | 518 } |
516 if (receivedGroup.nextPollSeconds !== undefined) { | |
517 storedGroup.nextPollTime = | |
518 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; | |
519 } | |
520 | 519 |
521 updatedGroups[groupName] = storedGroup; | 520 scheduleNextPoll(updatedGroups, !response.googleNowDisabled); |
522 } | 521 combineAndShowNotificationCards( |
523 | 522 updatedGroups, |
524 scheduleNextPoll(updatedGroups, !response.googleNowDisabled); | 523 function() { |
525 combineAndShowNotificationCards( | 524 chrome.storage.local.set({ |
526 updatedGroups, | 525 notificationGroups: updatedGroups, |
527 function() { | 526 recentDismissals: updatedRecentDismissals |
528 chrome.storage.local.set({ | 527 }); |
529 notificationGroups: updatedGroups, | 528 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); |
530 recentDismissals: updatedRecentDismissals | 529 }, |
531 }); | 530 onCardShown); |
532 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); | 531 }); |
533 }, | |
534 onCardShown); | |
535 }); | |
536 } | 532 } |
537 | 533 |
538 /** | 534 /** |
539 * Update the Explanatory Total Cards Shown Count. | 535 * Update the Explanatory Total Cards Shown Count. |
540 */ | 536 */ |
541 function countExplanatoryCard() { | 537 function countExplanatoryCard() { |
542 localStorage['explanatoryCardsShown']++; | 538 localStorage['explanatoryCardsShown']++; |
543 } | 539 } |
544 | 540 |
545 /** | 541 /** |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 request.send(); | 615 request.send(); |
620 }); | 616 }); |
621 } | 617 } |
622 | 618 |
623 /** | 619 /** |
624 * Requests notification cards from the server. | 620 * Requests notification cards from the server. |
625 */ | 621 */ |
626 function requestNotificationCards() { | 622 function requestNotificationCards() { |
627 console.log('requestNotificationCards'); | 623 console.log('requestNotificationCards'); |
628 | 624 |
629 instrumented.storage.local.get( | 625 fillFromChromeLocalStorage({ |
630 ['notificationGroups', 'googleNowEnabled'], function(items) { | |
631 console.log('requestNotificationCards-storage-get ' + | |
632 JSON.stringify(items)); | |
633 items = items || {}; | |
634 /** @type {Object.<string, StoredNotificationGroup>} */ | 626 /** @type {Object.<string, StoredNotificationGroup>} */ |
635 items.notificationGroups = items.notificationGroups || {}; | 627 notificationGroups: {}, |
| 628 googleNowEnabled: false |
| 629 }).then(function(items) { |
| 630 console.log( |
| 631 'requestNotificationCards-storage-get ' + JSON.stringify(items)); |
636 | 632 |
637 var groupsToRequest = []; | 633 var groupsToRequest = []; |
638 | 634 |
639 var now = Date.now(); | 635 var now = Date.now(); |
640 | 636 |
641 for (var groupName in items.notificationGroups) { | 637 for (var groupName in items.notificationGroups) { |
642 var group = items.notificationGroups[groupName]; | 638 var group = items.notificationGroups[groupName]; |
643 if (group.nextPollTime !== undefined && group.nextPollTime <= now) | 639 if (group.nextPollTime !== undefined && group.nextPollTime <= now) |
644 groupsToRequest.push(groupName); | 640 groupsToRequest.push(groupName); |
645 } | 641 } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 callbackBoolean(false); | 732 callbackBoolean(false); |
737 }); | 733 }); |
738 } | 734 } |
739 | 735 |
740 /** | 736 /** |
741 * Tries to send dismiss requests for all pending dismissals. | 737 * Tries to send dismiss requests for all pending dismissals. |
742 * @param {function(boolean)} callbackBoolean Completion callback with 'success' | 738 * @param {function(boolean)} callbackBoolean Completion callback with 'success' |
743 * parameter. Success means that no pending dismissals are left. | 739 * parameter. Success means that no pending dismissals are left. |
744 */ | 740 */ |
745 function processPendingDismissals(callbackBoolean) { | 741 function processPendingDismissals(callbackBoolean) { |
746 instrumented.storage.local.get(['pendingDismissals', 'recentDismissals'], | 742 fillFromChromeLocalStorage({ |
747 function(items) { | 743 /** @type {Array.<PendingDismissal>} */ |
748 console.log('processPendingDismissals-storage-get ' + | 744 pendingDismissals: [], |
749 JSON.stringify(items)); | 745 /** @type {Object.<NotificationId, number>} */ |
750 items = items || {}; | 746 recentDismissals: {} |
751 /** @type {Array.<PendingDismissal>} */ | 747 }).then(function(items) { |
752 items.pendingDismissals = items.pendingDismissals || []; | 748 console.log( |
753 /** @type {Object.<NotificationId, number>} */ | 749 'processPendingDismissals-storage-get ' + JSON.stringify(items)); |
754 items.recentDismissals = items.recentDismissals || {}; | |
755 | 750 |
756 var dismissalsChanged = false; | 751 var dismissalsChanged = false; |
757 | 752 |
758 function onFinish(success) { | 753 function onFinish(success) { |
759 if (dismissalsChanged) { | 754 if (dismissalsChanged) { |
760 chrome.storage.local.set({ | 755 chrome.storage.local.set({ |
761 pendingDismissals: items.pendingDismissals, | 756 pendingDismissals: items.pendingDismissals, |
762 recentDismissals: items.recentDismissals | 757 recentDismissals: items.recentDismissals |
763 }); | 758 }); |
764 } | 759 } |
765 callbackBoolean(success); | 760 callbackBoolean(success); |
766 } | 761 } |
767 | 762 |
768 function doProcessDismissals() { | 763 function doProcessDismissals() { |
769 if (items.pendingDismissals.length == 0) { | 764 if (items.pendingDismissals.length == 0) { |
770 dismissalAttempts.stop(); | 765 dismissalAttempts.stop(); |
771 onFinish(true); | 766 onFinish(true); |
772 return; | 767 return; |
773 } | 768 } |
774 | 769 |
775 // Send dismissal for the first card, and if successful, repeat | 770 // Send dismissal for the first card, and if successful, repeat |
776 // recursively with the rest. | 771 // recursively with the rest. |
777 /** @type {PendingDismissal} */ | 772 /** @type {PendingDismissal} */ |
778 var dismissal = items.pendingDismissals[0]; | 773 var dismissal = items.pendingDismissals[0]; |
779 requestCardDismissal( | 774 requestCardDismissal( |
780 dismissal.chromeNotificationId, | 775 dismissal.chromeNotificationId, |
781 dismissal.time, | 776 dismissal.time, |
782 dismissal.dismissalData, | 777 dismissal.dismissalData, |
783 function(done) { | 778 function(done) { |
784 if (done) { | 779 if (done) { |
785 dismissalsChanged = true; | 780 dismissalsChanged = true; |
786 items.pendingDismissals.splice(0, 1); | 781 items.pendingDismissals.splice(0, 1); |
787 items.recentDismissals[ | 782 items.recentDismissals[ |
788 dismissal.dismissalData.notificationId] = | 783 dismissal.dismissalData.notificationId] = |
789 Date.now(); | 784 Date.now(); |
790 doProcessDismissals(); | 785 doProcessDismissals(); |
791 } else { | 786 } else { |
792 onFinish(false); | 787 onFinish(false); |
793 } | 788 } |
794 }); | 789 }); |
795 } | 790 } |
796 | 791 |
797 doProcessDismissals(); | 792 doProcessDismissals(); |
798 }); | 793 }); |
799 } | 794 } |
800 | 795 |
801 /** | 796 /** |
802 * Submits a task to send pending dismissals. | 797 * Submits a task to send pending dismissals. |
803 */ | 798 */ |
804 function retryPendingDismissals() { | 799 function retryPendingDismissals() { |
805 tasks.add(RETRY_DISMISS_TASK_NAME, function() { | 800 tasks.add(RETRY_DISMISS_TASK_NAME, function() { |
806 dismissalAttempts.planForNext(function() { | 801 dismissalAttempts.planForNext(function() { |
807 processPendingDismissals(function(success) {}); | 802 processPendingDismissals(function(success) {}); |
808 }); | 803 }); |
(...skipping 15 matching lines...) Expand all Loading... |
824 | 819 |
825 /** | 820 /** |
826 * Opens URL corresponding to the clicked part of the notification. | 821 * Opens URL corresponding to the clicked part of the notification. |
827 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of | 822 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of |
828 * the card. | 823 * the card. |
829 * @param {function((ActionUrls|undefined)): (string|undefined)} selector | 824 * @param {function((ActionUrls|undefined)): (string|undefined)} selector |
830 * Function that extracts the url for the clicked area from the button | 825 * Function that extracts the url for the clicked area from the button |
831 * action URLs info. | 826 * action URLs info. |
832 */ | 827 */ |
833 function onNotificationClicked(chromeNotificationId, selector) { | 828 function onNotificationClicked(chromeNotificationId, selector) { |
834 instrumented.storage.local.get('notificationsData', function(items) { | 829 fillFromChromeLocalStorage({ |
| 830 /** @type {Object.<string, NotificationDataEntry>} */ |
| 831 notificationsData: {} |
| 832 }).then(function(items) { |
835 /** @type {(NotificationDataEntry|undefined)} */ | 833 /** @type {(NotificationDataEntry|undefined)} */ |
836 var notificationData = items && | 834 var notificationData = items.notificationsData[chromeNotificationId]; |
837 items.notificationsData && | |
838 items.notificationsData[chromeNotificationId]; | |
839 | |
840 if (!notificationData) | 835 if (!notificationData) |
841 return; | 836 return; |
842 | 837 |
843 var url = selector(notificationData.actionUrls); | 838 var url = selector(notificationData.actionUrls); |
844 if (!url) | 839 if (!url) |
845 return; | 840 return; |
846 | 841 |
847 openUrl(url); | 842 openUrl(url); |
848 }); | 843 }); |
849 } | 844 } |
850 | 845 |
851 /** | 846 /** |
852 * Callback for chrome.notifications.onClosed event. | 847 * Callback for chrome.notifications.onClosed event. |
853 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of | 848 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of |
854 * the card. | 849 * the card. |
855 * @param {boolean} byUser Whether the notification was closed by the user. | 850 * @param {boolean} byUser Whether the notification was closed by the user. |
856 */ | 851 */ |
857 function onNotificationClosed(chromeNotificationId, byUser) { | 852 function onNotificationClosed(chromeNotificationId, byUser) { |
858 if (!byUser) | 853 if (!byUser) |
859 return; | 854 return; |
860 | 855 |
861 // At this point we are guaranteed that the notification is a now card. | 856 // At this point we are guaranteed that the notification is a now card. |
862 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); | 857 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); |
863 | 858 |
864 tasks.add(DISMISS_CARD_TASK_NAME, function() { | 859 tasks.add(DISMISS_CARD_TASK_NAME, function() { |
865 dismissalAttempts.start(); | 860 dismissalAttempts.start(); |
866 | 861 |
867 instrumented.storage.local.get( | 862 fillFromChromeLocalStorage({ |
868 ['pendingDismissals', 'notificationsData', 'notificationGroups'], | 863 /** @type {Array.<PendingDismissal>} */ |
869 function(items) { | 864 pendingDismissals: [], |
870 items = items || {}; | 865 /** @type {Object.<string, NotificationDataEntry>} */ |
871 /** @type {Array.<PendingDismissal>} */ | 866 notificationsData: {}, |
872 items.pendingDismissals = items.pendingDismissals || []; | 867 /** @type {Object.<string, StoredNotificationGroup>} */ |
873 /** @type {Object.<string, NotificationDataEntry>} */ | 868 notificationGroups: {} |
874 items.notificationsData = items.notificationsData || {}; | 869 }).then(function(items) { |
875 /** @type {Object.<string, StoredNotificationGroup>} */ | 870 /** @type {NotificationDataEntry} */ |
876 items.notificationGroups = items.notificationGroups || {}; | 871 var notificationData = |
| 872 items.notificationsData[chromeNotificationId] || |
| 873 { |
| 874 timestamp: Date.now(), |
| 875 combinedCard: [] |
| 876 }; |
877 | 877 |
878 /** @type {NotificationDataEntry} */ | 878 var dismissalResult = |
879 var notificationData = | 879 cardSet.onDismissal( |
880 items.notificationsData[chromeNotificationId] || | 880 chromeNotificationId, |
881 { | 881 notificationData, |
882 timestamp: Date.now(), | 882 items.notificationGroups); |
883 combinedCard: [] | |
884 }; | |
885 | 883 |
886 var dismissalResult = | 884 for (var i = 0; i < dismissalResult.dismissals.length; i++) { |
887 cardSet.onDismissal( | 885 /** @type {PendingDismissal} */ |
888 chromeNotificationId, | 886 var dismissal = { |
889 notificationData, | 887 chromeNotificationId: chromeNotificationId, |
890 items.notificationGroups); | 888 time: Date.now(), |
| 889 dismissalData: dismissalResult.dismissals[i] |
| 890 }; |
| 891 items.pendingDismissals.push(dismissal); |
| 892 } |
891 | 893 |
892 for (var i = 0; i < dismissalResult.dismissals.length; i++) { | 894 items.notificationsData[chromeNotificationId] = |
893 /** @type {PendingDismissal} */ | 895 dismissalResult.notificationData; |
894 var dismissal = { | |
895 chromeNotificationId: chromeNotificationId, | |
896 time: Date.now(), | |
897 dismissalData: dismissalResult.dismissals[i] | |
898 }; | |
899 items.pendingDismissals.push(dismissal); | |
900 } | |
901 | 896 |
902 items.notificationsData[chromeNotificationId] = | 897 chrome.storage.local.set(items); |
903 dismissalResult.notificationData; | |
904 | 898 |
905 chrome.storage.local.set(items); | 899 processPendingDismissals(function(success) {}); |
906 | 900 }); |
907 processPendingDismissals(function(success) {}); | |
908 }); | |
909 }); | 901 }); |
910 } | 902 } |
911 | 903 |
912 /** | 904 /** |
913 * Initializes the polling system to start fetching cards. | 905 * Initializes the polling system to start fetching cards. |
914 */ | 906 */ |
915 function startPollingCards() { | 907 function startPollingCards() { |
916 console.log('startPollingCards'); | 908 console.log('startPollingCards'); |
917 // Create an update timer for a case when for some reason requesting | 909 // Create an update timer for a case when for some reason requesting |
918 // cards gets stuck. | 910 // cards gets stuck. |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1066 }); | 1058 }); |
1067 }); | 1059 }); |
1068 } | 1060 } |
1069 | 1061 |
1070 /** | 1062 /** |
1071 * Gets the previous Google Now opt-in state. | 1063 * Gets the previous Google Now opt-in state. |
1072 * @return {Promise} A promise to determine the previous Google Now | 1064 * @return {Promise} A promise to determine the previous Google Now |
1073 * opt-in state. | 1065 * opt-in state. |
1074 */ | 1066 */ |
1075 function isGoogleNowEnabled() { | 1067 function isGoogleNowEnabled() { |
1076 return new Promise(function(resolve) { | 1068 return fillFromChromeLocalStorage({googleNowEnabled: false}) |
1077 instrumented.storage.local.get('googleNowEnabled', function(items) { | 1069 .then(function(items) { |
1078 resolve(items && !!items.googleNowEnabled); | 1070 return items.googleNowEnabled; |
1079 }); | 1071 }); |
1080 }); | |
1081 } | 1072 } |
1082 | 1073 |
1083 instrumented.runtime.onInstalled.addListener(function(details) { | 1074 instrumented.runtime.onInstalled.addListener(function(details) { |
1084 console.log('onInstalled ' + JSON.stringify(details)); | 1075 console.log('onInstalled ' + JSON.stringify(details)); |
1085 if (details.reason != 'chrome_update') { | 1076 if (details.reason != 'chrome_update') { |
1086 initialize(); | 1077 initialize(); |
1087 } | 1078 } |
1088 }); | 1079 }); |
1089 | 1080 |
1090 instrumented.runtime.onStartup.addListener(function() { | 1081 instrumented.runtime.onStartup.addListener(function() { |
1091 console.log('onStartup'); | 1082 console.log('onStartup'); |
1092 | 1083 |
1093 // Show notifications received by earlier polls. Doing this as early as | 1084 // Show notifications received by earlier polls. Doing this as early as |
1094 // possible to reduce latency of showing first notifications. This mimics how | 1085 // possible to reduce latency of showing first notifications. This mimics how |
1095 // persistent notifications will work. | 1086 // persistent notifications will work. |
1096 tasks.add(SHOW_ON_START_TASK_NAME, function() { | 1087 tasks.add(SHOW_ON_START_TASK_NAME, function() { |
1097 instrumented.storage.local.get('notificationGroups', function(items) { | 1088 fillFromChromeLocalStorage({ |
| 1089 /** @type {Object.<string, StoredNotificationGroup>} */ |
| 1090 notificationGroups: {} |
| 1091 }).then(function(items) { |
1098 console.log('onStartup-get ' + JSON.stringify(items)); | 1092 console.log('onStartup-get ' + JSON.stringify(items)); |
1099 items = items || {}; | |
1100 /** @type {Object.<string, StoredNotificationGroup>} */ | |
1101 items.notificationGroups = items.notificationGroups || {}; | |
1102 | 1093 |
1103 combineAndShowNotificationCards(items.notificationGroups, function() { | 1094 combineAndShowNotificationCards(items.notificationGroups, function() { |
1104 chrome.storage.local.set(items); | 1095 chrome.storage.local.set(items); |
1105 }); | 1096 }); |
1106 }); | 1097 }); |
1107 }); | 1098 }); |
1108 | 1099 |
1109 initialize(); | 1100 initialize(); |
1110 }); | 1101 }); |
1111 | 1102 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1146 }); | 1137 }); |
1147 | 1138 |
1148 instrumented.pushMessaging.onMessage.addListener(function(message) { | 1139 instrumented.pushMessaging.onMessage.addListener(function(message) { |
1149 // message.payload will be '' when the extension first starts. | 1140 // message.payload will be '' when the extension first starts. |
1150 // Each time after signing in, we'll get latest payload for all channels. | 1141 // Each time after signing in, we'll get latest payload for all channels. |
1151 // So, we need to poll the server only when the payload is non-empty and has | 1142 // So, we need to poll the server only when the payload is non-empty and has |
1152 // changed. | 1143 // changed. |
1153 console.log('pushMessaging.onMessage ' + JSON.stringify(message)); | 1144 console.log('pushMessaging.onMessage ' + JSON.stringify(message)); |
1154 if (message.payload.indexOf('REQUEST_CARDS') == 0) { | 1145 if (message.payload.indexOf('REQUEST_CARDS') == 0) { |
1155 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() { | 1146 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() { |
1156 instrumented.storage.local.get( | 1147 // Accept promise rejection on failure since it's safer to do nothing, |
1157 ['lastPollNowPayloads', 'notificationGroups'], function(items) { | 1148 // preventing polling the server when the payload really didn't change. |
1158 // If storage.get fails, it's safer to do nothing, preventing polling | 1149 fillFromChromeLocalStorage({ |
1159 // the server when the payload really didn't change. | 1150 lastPollNowPayloads: {}, |
1160 if (!items) | 1151 /** @type {Object.<string, StoredNotificationGroup>} */ |
1161 return; | 1152 notificationGroups: {} |
1162 | 1153 }, PromiseRejection.ALLOW).then(function(items) { |
1163 // If this is the first time we get lastPollNowPayloads, initialize it. | |
1164 items.lastPollNowPayloads = items.lastPollNowPayloads || {}; | |
1165 | |
1166 if (items.lastPollNowPayloads[message.subchannelId] != | 1154 if (items.lastPollNowPayloads[message.subchannelId] != |
1167 message.payload) { | 1155 message.payload) { |
1168 items.lastPollNowPayloads[message.subchannelId] = message.payload; | 1156 items.lastPollNowPayloads[message.subchannelId] = message.payload; |
1169 | 1157 |
1170 /** @type {Object.<string, StoredNotificationGroup>} */ | |
1171 items.notificationGroups = items.notificationGroups || {}; | |
1172 items.notificationGroups['PUSH' + message.subchannelId] = { | 1158 items.notificationGroups['PUSH' + message.subchannelId] = { |
1173 cards: [], | 1159 cards: [], |
1174 nextPollTime: Date.now() | 1160 nextPollTime: Date.now() |
1175 }; | 1161 }; |
1176 | 1162 |
1177 chrome.storage.local.set({ | 1163 chrome.storage.local.set({ |
1178 lastPollNowPayloads: items.lastPollNowPayloads, | 1164 lastPollNowPayloads: items.lastPollNowPayloads, |
1179 notificationGroups: items.notificationGroups | 1165 notificationGroups: items.notificationGroups |
1180 }); | 1166 }); |
1181 | 1167 |
1182 requestCards(); | 1168 requestCards(); |
1183 } | 1169 } |
1184 }); | 1170 }); |
1185 }); | 1171 }); |
1186 } | 1172 } |
1187 }); | 1173 }); |
OLD | NEW |