Chromium Code Reviews| 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 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 'preferencesPrivate.googleGeolocationAccessEnabled.get', | 199 'preferencesPrivate.googleGeolocationAccessEnabled.get', |
| 200 1); | 200 1); |
| 201 wrapper.instrumentChromeApiFunction( | 201 wrapper.instrumentChromeApiFunction( |
| 202 'preferencesPrivate.googleGeolocationAccessEnabled.onChange.addListener', | 202 'preferencesPrivate.googleGeolocationAccessEnabled.onChange.addListener', |
| 203 0); | 203 0); |
| 204 wrapper.instrumentChromeApiFunction('permissions.contains', 1); | 204 wrapper.instrumentChromeApiFunction('permissions.contains', 1); |
| 205 wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0); | 205 wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0); |
| 206 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0); | 206 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0); |
| 207 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0); | 207 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0); |
| 208 wrapper.instrumentChromeApiFunction('tabs.create', 1); | 208 wrapper.instrumentChromeApiFunction('tabs.create', 1); |
| 209 wrapper.instrumentChromeApiFunction('storage.local.get', 1); | |
| 210 | 209 |
| 211 var updateCardsAttempts = buildAttemptManager( | 210 var updateCardsAttempts = buildAttemptManager( |
| 212 'cards-update', | 211 'cards-update', |
| 213 requestLocation, | 212 requestLocation, |
| 214 INITIAL_POLLING_PERIOD_SECONDS, | 213 INITIAL_POLLING_PERIOD_SECONDS, |
| 215 MAXIMUM_POLLING_PERIOD_SECONDS); | 214 MAXIMUM_POLLING_PERIOD_SECONDS); |
| 216 var dismissalAttempts = buildAttemptManager( | 215 var dismissalAttempts = buildAttemptManager( |
| 217 'dismiss', | 216 'dismiss', |
| 218 retryPendingDismissals, | 217 retryPendingDismissals, |
| 219 INITIAL_RETRY_DISMISS_PERIOD_SECONDS, | 218 INITIAL_RETRY_DISMISS_PERIOD_SECONDS, |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 451 chrome.storage.local.set({googleNowEnabled: false}); | 450 chrome.storage.local.set({googleNowEnabled: false}); |
| 452 // TODO(vadimt): Remove the line below once the server stops sending groups | 451 // TODO(vadimt): Remove the line below once the server stops sending groups |
| 453 // with 'googleNowDisabled' responses. | 452 // with 'googleNowDisabled' responses. |
| 454 response.groups = {}; | 453 response.groups = {}; |
| 455 // Google Now was enabled; now it's disabled. This is a state change. | 454 // Google Now was enabled; now it's disabled. This is a state change. |
| 456 onStateChange(); | 455 onStateChange(); |
| 457 } | 456 } |
| 458 | 457 |
| 459 var receivedGroups = response.groups; | 458 var receivedGroups = response.groups; |
| 460 | 459 |
| 461 instrumented.storage.local.get( | 460 fillFromChromeLocalStorage({ |
| 462 ['notificationGroups', 'recentDismissals'], | 461 /** @type {Object.<string, StoredNotificationGroup>} */ |
| 463 function(items) { | 462 notificationGroups: {}, |
| 464 console.log( | 463 /** @type {Object.<NotificationId, number>} */ |
| 465 'processServerResponse-get ' + JSON.stringify(items)); | 464 recentDismissals: {} |
| 466 items = items || {}; | 465 }).then(function(items) { |
| 467 /** @type {Object.<string, StoredNotificationGroup>} */ | 466 console.log('processServerResponse-get ' + JSON.stringify(items)); |
| 468 items.notificationGroups = items.notificationGroups || {}; | |
| 469 /** @type {Object.<NotificationId, number>} */ | |
| 470 items.recentDismissals = items.recentDismissals || {}; | |
| 471 | 467 |
| 472 // Build a set of non-expired recent dismissals. It will be used for | 468 // Build a set of non-expired recent dismissals. It will be used for |
| 473 // client-side filtering of cards. | 469 // client-side filtering of cards. |
| 474 /** @type {Object.<NotificationId, number>} */ | 470 /** @type {Object.<NotificationId, number>} */ |
| 475 var updatedRecentDismissals = {}; | 471 var updatedRecentDismissals = {}; |
| 476 var now = Date.now(); | 472 var now = Date.now(); |
| 477 for (var notificationId in items.recentDismissals) { | 473 for (var notificationId in items.recentDismissals) { |
| 478 var dismissalAge = now - items.recentDismissals[notificationId]; | 474 var dismissalAge = now - items.recentDismissals[notificationId]; |
| 479 if (dismissalAge < DISMISS_RETENTION_TIME_MS) { | 475 if (dismissalAge < DISMISS_RETENTION_TIME_MS) { |
| 480 updatedRecentDismissals[notificationId] = | 476 updatedRecentDismissals[notificationId] = |
| 481 items.recentDismissals[notificationId]; | 477 items.recentDismissals[notificationId]; |
| 482 } | 478 } |
| 479 } | |
| 480 | |
| 481 // Populate groups with corresponding cards. | |
| 482 if (response.notifications) { | |
| 483 for (var i = 0; i < response.notifications.length; ++i) { | |
| 484 /** @type {ReceivedNotification} */ | |
| 485 var card = response.notifications[i]; | |
| 486 if (!(card.notificationId in updatedRecentDismissals)) { | |
| 487 var group = receivedGroups[card.groupName]; | |
| 488 group.cards = group.cards || []; | |
| 489 group.cards.push(card); | |
| 483 } | 490 } |
| 491 } | |
| 492 } | |
| 484 | 493 |
| 485 // Populate groups with corresponding cards. | 494 // Build updated set of groups. |
| 486 if (response.notifications) { | 495 var updatedGroups = {}; |
| 487 for (var i = 0; i < response.notifications.length; ++i) { | |
| 488 /** @type {ReceivedNotification} */ | |
| 489 var card = response.notifications[i]; | |
| 490 if (!(card.notificationId in updatedRecentDismissals)) { | |
| 491 var group = receivedGroups[card.groupName]; | |
| 492 group.cards = group.cards || []; | |
| 493 group.cards.push(card); | |
| 494 } | |
| 495 } | |
| 496 } | |
| 497 | 496 |
| 498 // Build updated set of groups. | 497 for (var groupName in receivedGroups) { |
| 499 var updatedGroups = {}; | 498 var receivedGroup = receivedGroups[groupName]; |
| 499 var storedGroup = items.notificationGroups[groupName] || { | |
| 500 cards: [], | |
| 501 cardsTimestamp: undefined, | |
| 502 nextPollTime: undefined, | |
| 503 rank: undefined | |
| 504 }; | |
| 500 | 505 |
| 501 for (var groupName in receivedGroups) { | 506 if (receivedGroup.requested) |
| 502 var receivedGroup = receivedGroups[groupName]; | 507 receivedGroup.cards = receivedGroup.cards || []; |
| 503 var storedGroup = items.notificationGroups[groupName] || { | |
| 504 cards: [], | |
| 505 cardsTimestamp: undefined, | |
| 506 nextPollTime: undefined, | |
| 507 rank: undefined | |
| 508 }; | |
| 509 | 508 |
| 510 if (receivedGroup.requested) | 509 if (receivedGroup.cards) { |
| 511 receivedGroup.cards = receivedGroup.cards || []; | 510 // If the group contains a cards update, all its fields will get new |
| 511 // values. | |
| 512 storedGroup.cards = receivedGroup.cards; | |
| 513 storedGroup.cardsTimestamp = now; | |
| 514 storedGroup.rank = receivedGroup.rank; | |
| 515 storedGroup.nextPollTime = undefined; | |
| 516 // The code below assigns nextPollTime a defined value if | |
| 517 // nextPollSeconds is specified in the received group. | |
| 518 // If the group's cards are not updated, and nextPollSeconds is | |
| 519 // unspecified, this method doesn't change group's nextPollTime. | |
| 520 } | |
| 512 | 521 |
| 513 if (receivedGroup.cards) { | 522 // 'nextPollSeconds' may be sent even for groups that don't contain |
| 514 // If the group contains a cards update, all its fields will get new | 523 // cards updates. |
| 515 // values. | 524 if (receivedGroup.nextPollSeconds !== undefined) { |
| 516 storedGroup.cards = receivedGroup.cards; | 525 storedGroup.nextPollTime = |
| 517 storedGroup.cardsTimestamp = now; | 526 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; |
| 518 storedGroup.rank = receivedGroup.rank; | 527 } |
| 519 storedGroup.nextPollTime = undefined; | |
| 520 // The code below assigns nextPollTime a defined value if | |
| 521 // nextPollSeconds is specified in the received group. | |
| 522 // If the group's cards are not updated, and nextPollSeconds is | |
| 523 // unspecified, this method doesn't change group's nextPollTime. | |
| 524 } | |
| 525 | 528 |
| 526 // 'nextPollSeconds' may be sent even for groups that don't contain | 529 updatedGroups[groupName] = storedGroup; |
| 527 // cards updates. | 530 } |
| 528 if (receivedGroup.nextPollSeconds !== undefined) { | |
| 529 storedGroup.nextPollTime = | |
| 530 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; | |
| 531 } | |
| 532 | 531 |
| 533 updatedGroups[groupName] = storedGroup; | 532 scheduleNextPoll(updatedGroups, !response.googleNowDisabled); |
| 534 } | 533 combineAndShowNotificationCards( |
| 535 | 534 updatedGroups, |
| 536 scheduleNextPoll(updatedGroups, !response.googleNowDisabled); | 535 function() { |
| 537 combineAndShowNotificationCards( | 536 chrome.storage.local.set({ |
| 538 updatedGroups, | 537 notificationGroups: updatedGroups, |
| 539 function() { | 538 recentDismissals: updatedRecentDismissals |
| 540 chrome.storage.local.set({ | 539 }); |
| 541 notificationGroups: updatedGroups, | 540 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); |
| 542 recentDismissals: updatedRecentDismissals | 541 }, |
| 543 }); | 542 onCardShown); |
| 544 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); | 543 }); |
| 545 }, | |
| 546 onCardShown); | |
| 547 }); | |
| 548 } | 544 } |
| 549 | 545 |
| 550 /** | 546 /** |
| 551 * Update the Explanatory Total Cards Shown Count. | 547 * Update the Explanatory Total Cards Shown Count. |
| 552 */ | 548 */ |
| 553 function countExplanatoryCard() { | 549 function countExplanatoryCard() { |
| 554 localStorage['explanatoryCardsShown']++; | 550 localStorage['explanatoryCardsShown']++; |
| 555 } | 551 } |
| 556 | 552 |
| 557 /** | 553 /** |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 632 }); | 628 }); |
| 633 } | 629 } |
| 634 | 630 |
| 635 /** | 631 /** |
| 636 * Requests notification cards from the server. | 632 * Requests notification cards from the server. |
| 637 * @param {Location=} position Location of this computer. | 633 * @param {Location=} position Location of this computer. |
| 638 */ | 634 */ |
| 639 function requestNotificationCards(position) { | 635 function requestNotificationCards(position) { |
| 640 console.log('requestNotificationCards ' + JSON.stringify(position)); | 636 console.log('requestNotificationCards ' + JSON.stringify(position)); |
| 641 | 637 |
| 642 instrumented.storage.local.get( | 638 fillFromChromeLocalStorage({ |
| 643 ['notificationGroups', 'googleNowEnabled'], function(items) { | |
| 644 console.log('requestNotificationCards-storage-get ' + | |
| 645 JSON.stringify(items)); | |
| 646 items = items || {}; | |
| 647 /** @type {Object.<string, StoredNotificationGroup>} */ | 639 /** @type {Object.<string, StoredNotificationGroup>} */ |
| 648 items.notificationGroups = items.notificationGroups || {}; | 640 notificationGroups: {}, |
| 641 googleNowEnabled: false | |
| 642 }).then(function(items) { | |
| 643 console.log( | |
| 644 'requestNotificationCards-storage-get ' + JSON.stringify(items)); | |
| 649 | 645 |
| 650 var groupsToRequest = []; | 646 var groupsToRequest = []; |
| 651 | 647 |
| 652 var now = Date.now(); | 648 var now = Date.now(); |
| 653 | 649 |
| 654 for (var groupName in items.notificationGroups) { | 650 for (var groupName in items.notificationGroups) { |
| 655 var group = items.notificationGroups[groupName]; | 651 var group = items.notificationGroups[groupName]; |
| 656 if (group.nextPollTime !== undefined && group.nextPollTime <= now) | 652 if (group.nextPollTime !== undefined && group.nextPollTime <= now) |
| 657 groupsToRequest.push(groupName); | 653 groupsToRequest.push(groupName); |
| 658 } | 654 } |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 784 callbackBoolean(false); | 780 callbackBoolean(false); |
| 785 }); | 781 }); |
| 786 } | 782 } |
| 787 | 783 |
| 788 /** | 784 /** |
| 789 * Tries to send dismiss requests for all pending dismissals. | 785 * Tries to send dismiss requests for all pending dismissals. |
| 790 * @param {function(boolean)} callbackBoolean Completion callback with 'success' | 786 * @param {function(boolean)} callbackBoolean Completion callback with 'success' |
| 791 * parameter. Success means that no pending dismissals are left. | 787 * parameter. Success means that no pending dismissals are left. |
| 792 */ | 788 */ |
| 793 function processPendingDismissals(callbackBoolean) { | 789 function processPendingDismissals(callbackBoolean) { |
| 794 instrumented.storage.local.get(['pendingDismissals', 'recentDismissals'], | 790 fillFromChromeLocalStorage({ |
| 795 function(items) { | 791 /** @type {Array.<PendingDismissal>} */ |
| 796 console.log('processPendingDismissals-storage-get ' + | 792 pendingDismissals: [], |
| 797 JSON.stringify(items)); | 793 /** @type {Object.<NotificationId, number>} */ |
| 798 items = items || {}; | 794 recentDismissals: {} |
| 799 /** @type {Array.<PendingDismissal>} */ | 795 }).then(function(items) { |
| 800 items.pendingDismissals = items.pendingDismissals || []; | 796 console.log( |
| 801 /** @type {Object.<NotificationId, number>} */ | 797 'processPendingDismissals-storage-get ' + JSON.stringify(items)); |
| 802 items.recentDismissals = items.recentDismissals || {}; | |
| 803 | 798 |
| 804 var dismissalsChanged = false; | 799 var dismissalsChanged = false; |
| 805 | 800 |
| 806 function onFinish(success) { | 801 function onFinish(success) { |
| 807 if (dismissalsChanged) { | 802 if (dismissalsChanged) { |
| 808 chrome.storage.local.set({ | 803 chrome.storage.local.set({ |
| 809 pendingDismissals: items.pendingDismissals, | 804 pendingDismissals: items.pendingDismissals, |
| 810 recentDismissals: items.recentDismissals | 805 recentDismissals: items.recentDismissals |
| 811 }); | 806 }); |
| 812 } | 807 } |
| 813 callbackBoolean(success); | 808 callbackBoolean(success); |
| 814 } | 809 } |
| 815 | 810 |
| 816 function doProcessDismissals() { | 811 function doProcessDismissals() { |
| 817 if (items.pendingDismissals.length == 0) { | 812 if (items.pendingDismissals.length == 0) { |
| 818 dismissalAttempts.stop(); | 813 dismissalAttempts.stop(); |
| 819 onFinish(true); | 814 onFinish(true); |
| 820 return; | 815 return; |
| 821 } | 816 } |
| 822 | 817 |
| 823 // Send dismissal for the first card, and if successful, repeat | 818 // Send dismissal for the first card, and if successful, repeat |
| 824 // recursively with the rest. | 819 // recursively with the rest. |
| 825 /** @type {PendingDismissal} */ | 820 /** @type {PendingDismissal} */ |
| 826 var dismissal = items.pendingDismissals[0]; | 821 var dismissal = items.pendingDismissals[0]; |
| 827 requestCardDismissal( | 822 requestCardDismissal( |
| 828 dismissal.chromeNotificationId, | 823 dismissal.chromeNotificationId, |
| 829 dismissal.time, | 824 dismissal.time, |
| 830 dismissal.dismissalData, | 825 dismissal.dismissalData, |
| 831 function(done) { | 826 function(done) { |
| 832 if (done) { | 827 if (done) { |
| 833 dismissalsChanged = true; | 828 dismissalsChanged = true; |
| 834 items.pendingDismissals.splice(0, 1); | 829 items.pendingDismissals.splice(0, 1); |
| 835 items.recentDismissals[ | 830 items.recentDismissals[ |
| 836 dismissal.dismissalData.notificationId] = | 831 dismissal.dismissalData.notificationId] = |
| 837 Date.now(); | 832 Date.now(); |
| 838 doProcessDismissals(); | 833 doProcessDismissals(); |
| 839 } else { | 834 } else { |
| 840 onFinish(false); | 835 onFinish(false); |
| 841 } | 836 } |
| 842 }); | 837 }); |
| 843 } | 838 } |
| 844 | 839 |
| 845 doProcessDismissals(); | 840 doProcessDismissals(); |
| 846 }); | 841 }); |
| 847 } | 842 } |
| 848 | 843 |
| 849 /** | 844 /** |
| 850 * Submits a task to send pending dismissals. | 845 * Submits a task to send pending dismissals. |
| 851 */ | 846 */ |
| 852 function retryPendingDismissals() { | 847 function retryPendingDismissals() { |
| 853 tasks.add(RETRY_DISMISS_TASK_NAME, function() { | 848 tasks.add(RETRY_DISMISS_TASK_NAME, function() { |
| 854 dismissalAttempts.planForNext(function() { | 849 dismissalAttempts.planForNext(function() { |
| 855 processPendingDismissals(function(success) {}); | 850 processPendingDismissals(function(success) {}); |
| 856 }); | 851 }); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 872 | 867 |
| 873 /** | 868 /** |
| 874 * Opens URL corresponding to the clicked part of the notification. | 869 * Opens URL corresponding to the clicked part of the notification. |
| 875 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of | 870 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of |
| 876 * the card. | 871 * the card. |
| 877 * @param {function((ActionUrls|undefined)): (string|undefined)} selector | 872 * @param {function((ActionUrls|undefined)): (string|undefined)} selector |
| 878 * Function that extracts the url for the clicked area from the button | 873 * Function that extracts the url for the clicked area from the button |
| 879 * action URLs info. | 874 * action URLs info. |
| 880 */ | 875 */ |
| 881 function onNotificationClicked(chromeNotificationId, selector) { | 876 function onNotificationClicked(chromeNotificationId, selector) { |
| 882 instrumented.storage.local.get('notificationsData', function(items) { | 877 fillFromChromeLocalStorage({ |
| 883 /** @type {(NotificationDataEntry|undefined)} */ | 878 /** @type {NotificationDataEntry} */ |
|
rgustafson
2014/02/27 21:32:09
Object.<ChromeNotificationId or string,Notificatio
robliao
2014/02/27 23:52:36
Noted, and that clarification should really be don
| |
| 884 var notificationData = items && | 879 notificationsData: {} |
| 885 items.notificationsData && | 880 }).then(function(items) { |
| 886 items.notificationsData[chromeNotificationId]; | 881 var notificationData = items.notificationsData[chromeNotificationId]; |
| 887 | |
| 888 if (!notificationData) | 882 if (!notificationData) |
| 889 return; | 883 return; |
| 890 | 884 |
| 891 var url = selector(notificationData.actionUrls); | 885 var url = selector(notificationData.actionUrls); |
| 892 if (!url) | 886 if (!url) |
| 893 return; | 887 return; |
| 894 | 888 |
| 895 openUrl(url); | 889 openUrl(url); |
| 896 }); | 890 }); |
| 897 } | 891 } |
| 898 | 892 |
| 899 /** | 893 /** |
| 900 * Callback for chrome.notifications.onClosed event. | 894 * Callback for chrome.notifications.onClosed event. |
| 901 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of | 895 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of |
| 902 * the card. | 896 * the card. |
| 903 * @param {boolean} byUser Whether the notification was closed by the user. | 897 * @param {boolean} byUser Whether the notification was closed by the user. |
| 904 */ | 898 */ |
| 905 function onNotificationClosed(chromeNotificationId, byUser) { | 899 function onNotificationClosed(chromeNotificationId, byUser) { |
| 906 if (!byUser) | 900 if (!byUser) |
| 907 return; | 901 return; |
| 908 | 902 |
| 909 // At this point we are guaranteed that the notification is a now card. | 903 // At this point we are guaranteed that the notification is a now card. |
| 910 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); | 904 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); |
| 911 | 905 |
| 912 tasks.add(DISMISS_CARD_TASK_NAME, function() { | 906 tasks.add(DISMISS_CARD_TASK_NAME, function() { |
| 913 dismissalAttempts.start(); | 907 dismissalAttempts.start(); |
| 914 | 908 |
| 915 instrumented.storage.local.get( | 909 fillFromChromeLocalStorage({ |
| 916 ['pendingDismissals', 'notificationsData', 'notificationGroups'], | 910 /** @type {Array.<PendingDismissal>} */ |
| 917 function(items) { | 911 pendingDismissals: [], |
| 918 items = items || {}; | 912 /** @type {Object.<string, NotificationDataEntry>} */ |
| 919 /** @type {Array.<PendingDismissal>} */ | 913 notificationsData: {}, |
| 920 items.pendingDismissals = items.pendingDismissals || []; | 914 /** @type {Object.<string, StoredNotificationGroup>} */ |
| 921 /** @type {Object.<string, NotificationDataEntry>} */ | 915 notificationGroups: {} |
| 922 items.notificationsData = items.notificationsData || {}; | 916 }).then(function(items) { |
| 923 /** @type {Object.<string, StoredNotificationGroup>} */ | 917 /** @type {NotificationDataEntry} */ |
| 924 items.notificationGroups = items.notificationGroups || {}; | 918 var notificationData = |
| 919 items.notificationsData[chromeNotificationId] || | |
| 920 { | |
| 921 timestamp: Date.now(), | |
| 922 combinedCard: [] | |
| 923 }; | |
| 925 | 924 |
| 926 /** @type {NotificationDataEntry} */ | 925 var dismissalResult = |
| 927 var notificationData = | 926 cardSet.onDismissal( |
| 928 items.notificationsData[chromeNotificationId] || | 927 chromeNotificationId, |
| 929 { | 928 notificationData, |
| 930 timestamp: Date.now(), | 929 items.notificationGroups); |
| 931 combinedCard: [] | |
| 932 }; | |
| 933 | 930 |
| 934 var dismissalResult = | 931 for (var i = 0; i < dismissalResult.dismissals.length; i++) { |
| 935 cardSet.onDismissal( | 932 /** @type {PendingDismissal} */ |
| 936 chromeNotificationId, | 933 var dismissal = { |
| 937 notificationData, | 934 chromeNotificationId: chromeNotificationId, |
| 938 items.notificationGroups); | 935 time: Date.now(), |
| 936 dismissalData: dismissalResult.dismissals[i] | |
| 937 }; | |
| 938 items.pendingDismissals.push(dismissal); | |
| 939 } | |
| 939 | 940 |
| 940 for (var i = 0; i < dismissalResult.dismissals.length; i++) { | 941 items.notificationsData[chromeNotificationId] = |
| 941 /** @type {PendingDismissal} */ | 942 dismissalResult.notificationData; |
| 942 var dismissal = { | |
| 943 chromeNotificationId: chromeNotificationId, | |
| 944 time: Date.now(), | |
| 945 dismissalData: dismissalResult.dismissals[i] | |
| 946 }; | |
| 947 items.pendingDismissals.push(dismissal); | |
| 948 } | |
| 949 | 943 |
| 950 items.notificationsData[chromeNotificationId] = | 944 chrome.storage.local.set(items); |
| 951 dismissalResult.notificationData; | |
| 952 | 945 |
| 953 chrome.storage.local.set(items); | 946 processPendingDismissals(function(success) {}); |
| 954 | 947 }); |
| 955 processPendingDismissals(function(success) {}); | |
| 956 }); | |
| 957 }); | 948 }); |
| 958 } | 949 } |
| 959 | 950 |
| 960 /** | 951 /** |
| 961 * Initializes the polling system to start monitoring location and fetching | 952 * Initializes the polling system to start monitoring location and fetching |
| 962 * cards. | 953 * cards. |
| 963 */ | 954 */ |
| 964 function startPollingCards() { | 955 function startPollingCards() { |
| 965 // Create an update timer for a case when for some reason location request | 956 // Create an update timer for a case when for some reason location request |
| 966 // gets stuck. | 957 // gets stuck. |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1138 }); | 1129 }); |
| 1139 }); | 1130 }); |
| 1140 } | 1131 } |
| 1141 | 1132 |
| 1142 /** | 1133 /** |
| 1143 * Gets the previous Google Now opt-in state. | 1134 * Gets the previous Google Now opt-in state. |
| 1144 * @return {Promise} A promise to determine the previous Google Now | 1135 * @return {Promise} A promise to determine the previous Google Now |
| 1145 * opt-in state. | 1136 * opt-in state. |
| 1146 */ | 1137 */ |
| 1147 function isGoogleNowEnabled() { | 1138 function isGoogleNowEnabled() { |
| 1148 return new Promise(function(resolve) { | 1139 return fillFromChromeLocalStorage({googleNowEnabled: false}) |
| 1149 instrumented.storage.local.get('googleNowEnabled', function(items) { | 1140 .then(function(items) { |
| 1150 resolve(items && !!items.googleNowEnabled); | 1141 return items.googleNowEnabled; |
| 1151 }); | 1142 }); |
| 1152 }); | |
| 1153 } | 1143 } |
| 1154 | 1144 |
| 1155 instrumented.runtime.onInstalled.addListener(function(details) { | 1145 instrumented.runtime.onInstalled.addListener(function(details) { |
| 1156 console.log('onInstalled ' + JSON.stringify(details)); | 1146 console.log('onInstalled ' + JSON.stringify(details)); |
| 1157 if (details.reason != 'chrome_update') { | 1147 if (details.reason != 'chrome_update') { |
| 1158 initialize(); | 1148 initialize(); |
| 1159 } | 1149 } |
| 1160 }); | 1150 }); |
| 1161 | 1151 |
| 1162 instrumented.runtime.onStartup.addListener(function() { | 1152 instrumented.runtime.onStartup.addListener(function() { |
| 1163 console.log('onStartup'); | 1153 console.log('onStartup'); |
| 1164 | 1154 |
| 1165 // Show notifications received by earlier polls. Doing this as early as | 1155 // Show notifications received by earlier polls. Doing this as early as |
| 1166 // possible to reduce latency of showing first notifications. This mimics how | 1156 // possible to reduce latency of showing first notifications. This mimics how |
| 1167 // persistent notifications will work. | 1157 // persistent notifications will work. |
| 1168 tasks.add(SHOW_ON_START_TASK_NAME, function() { | 1158 tasks.add(SHOW_ON_START_TASK_NAME, function() { |
| 1169 instrumented.storage.local.get('notificationGroups', function(items) { | 1159 fillFromChromeLocalStorage({ |
| 1160 /** @type {Object.<string, StoredNotificationGroup>} */ | |
| 1161 notificationGroups: {} | |
| 1162 }).then(function(items) { | |
| 1170 console.log('onStartup-get ' + JSON.stringify(items)); | 1163 console.log('onStartup-get ' + JSON.stringify(items)); |
| 1171 items = items || {}; | |
| 1172 /** @type {Object.<string, StoredNotificationGroup>} */ | |
| 1173 items.notificationGroups = items.notificationGroups || {}; | |
| 1174 | 1164 |
| 1175 combineAndShowNotificationCards(items.notificationGroups, function() { | 1165 combineAndShowNotificationCards(items.notificationGroups, function() { |
| 1176 chrome.storage.local.set(items); | 1166 chrome.storage.local.set(items); |
| 1177 }); | 1167 }); |
| 1178 }); | 1168 }); |
| 1179 }); | 1169 }); |
| 1180 | 1170 |
| 1181 initialize(); | 1171 initialize(); |
| 1182 }); | 1172 }); |
| 1183 | 1173 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1233 }); | 1223 }); |
| 1234 | 1224 |
| 1235 instrumented.pushMessaging.onMessage.addListener(function(message) { | 1225 instrumented.pushMessaging.onMessage.addListener(function(message) { |
| 1236 // message.payload will be '' when the extension first starts. | 1226 // message.payload will be '' when the extension first starts. |
| 1237 // Each time after signing in, we'll get latest payload for all channels. | 1227 // Each time after signing in, we'll get latest payload for all channels. |
| 1238 // So, we need to poll the server only when the payload is non-empty and has | 1228 // So, we need to poll the server only when the payload is non-empty and has |
| 1239 // changed. | 1229 // changed. |
| 1240 console.log('pushMessaging.onMessage ' + JSON.stringify(message)); | 1230 console.log('pushMessaging.onMessage ' + JSON.stringify(message)); |
| 1241 if (message.payload.indexOf('REQUEST_CARDS') == 0) { | 1231 if (message.payload.indexOf('REQUEST_CARDS') == 0) { |
| 1242 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() { | 1232 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() { |
| 1243 instrumented.storage.local.get( | 1233 // Accept promise rejection on failure since it's safer to do nothing, |
| 1244 ['lastPollNowPayloads', 'notificationGroups'], function(items) { | 1234 // preventing polling the server when the payload really didn't change. |
| 1245 // If storage.get fails, it's safer to do nothing, preventing polling | 1235 fillFromChromeLocalStorage({ |
| 1246 // the server when the payload really didn't change. | 1236 lastPollNowPayloads: {}, |
| 1247 if (!items) | 1237 /** @type {Object.<string, StoredNotificationGroup>} */ |
| 1248 return; | 1238 notificationGroups: {} |
| 1249 | 1239 }, PromiseRejection.ALLOW).then(function(items) { |
| 1250 // If this is the first time we get lastPollNowPayloads, initialize it. | |
| 1251 items.lastPollNowPayloads = items.lastPollNowPayloads || {}; | |
| 1252 | |
| 1253 if (items.lastPollNowPayloads[message.subchannelId] != | 1240 if (items.lastPollNowPayloads[message.subchannelId] != |
| 1254 message.payload) { | 1241 message.payload) { |
| 1255 items.lastPollNowPayloads[message.subchannelId] = message.payload; | 1242 items.lastPollNowPayloads[message.subchannelId] = message.payload; |
| 1256 | 1243 |
| 1257 /** @type {Object.<string, StoredNotificationGroup>} */ | |
| 1258 items.notificationGroups = items.notificationGroups || {}; | |
| 1259 items.notificationGroups['PUSH' + message.subchannelId] = { | 1244 items.notificationGroups['PUSH' + message.subchannelId] = { |
| 1260 cards: [], | 1245 cards: [], |
| 1261 nextPollTime: Date.now() | 1246 nextPollTime: Date.now() |
| 1262 }; | 1247 }; |
| 1263 | 1248 |
| 1264 chrome.storage.local.set({ | 1249 chrome.storage.local.set({ |
| 1265 lastPollNowPayloads: items.lastPollNowPayloads, | 1250 lastPollNowPayloads: items.lastPollNowPayloads, |
| 1266 notificationGroups: items.notificationGroups | 1251 notificationGroups: items.notificationGroups |
| 1267 }); | 1252 }); |
| 1268 | 1253 |
| 1269 updateNotificationsCards(); | 1254 updateNotificationsCards(); |
| 1270 } | 1255 } |
| 1271 }); | 1256 }); |
| 1272 }); | 1257 }); |
| 1273 } | 1258 } |
| 1274 }); | 1259 }); |
| OLD | NEW |