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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 * Time we keep dismissals after successful server dismiss requests. | 68 * Time we keep dismissals after successful server dismiss requests. |
| 69 */ | 69 */ |
| 70 var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000; // 20 minutes | 70 var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000; // 20 minutes |
| 71 | 71 |
| 72 /** | 72 /** |
| 73 * Names for tasks that can be created by the extension. | 73 * Names for tasks that can be created by the extension. |
| 74 */ | 74 */ |
| 75 var UPDATE_CARDS_TASK_NAME = 'update-cards'; | 75 var UPDATE_CARDS_TASK_NAME = 'update-cards'; |
| 76 var DISMISS_CARD_TASK_NAME = 'dismiss-card'; | 76 var DISMISS_CARD_TASK_NAME = 'dismiss-card'; |
| 77 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; | 77 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; |
| 78 var STATE_CHANGED_TASK_NAME = 'state-changed'; | |
| 78 | 79 |
| 79 var LOCATION_WATCH_NAME = 'location-watch'; | 80 var LOCATION_WATCH_NAME = 'location-watch'; |
| 80 | 81 |
| 81 var WELCOME_TOAST_NOTIFICATION_ID = 'enable-now-toast'; | 82 var WELCOME_TOAST_NOTIFICATION_ID = 'enable-now-toast'; |
| 82 | 83 |
| 83 /** | 84 /** |
| 84 * The indices of the buttons that are displayed on the welcome toast. | 85 * The indices of the buttons that are displayed on the welcome toast. |
| 85 * @enum {number} | 86 * @enum {number} |
| 86 */ | 87 */ |
| 87 var ToastButtonIndex = {YES: 0, NO: 1}; | 88 var ToastButtonIndex = {YES: 0, NO: 1}; |
| 88 | 89 |
| 89 /** | 90 /** |
| 90 * The action that the user performed on the welcome toast. | |
| 91 * @enum {number} | |
| 92 */ | |
| 93 var ToastOptionResponse = {CHOSE_YES: 1, CHOSE_NO: 2}; | |
| 94 | |
| 95 /** | |
| 96 * Checks if a new task can't be scheduled when another task is already | 91 * Checks if a new task can't be scheduled when another task is already |
| 97 * scheduled. | 92 * scheduled. |
| 98 * @param {string} newTaskName Name of the new task. | 93 * @param {string} newTaskName Name of the new task. |
| 99 * @param {string} scheduledTaskName Name of the scheduled task. | 94 * @param {string} scheduledTaskName Name of the scheduled task. |
| 100 * @return {boolean} Whether the new task conflicts with the existing task. | 95 * @return {boolean} Whether the new task conflicts with the existing task. |
| 101 */ | 96 */ |
| 102 function areTasksConflicting(newTaskName, scheduledTaskName) { | 97 function areTasksConflicting(newTaskName, scheduledTaskName) { |
| 103 if (newTaskName == UPDATE_CARDS_TASK_NAME && | 98 if (newTaskName == UPDATE_CARDS_TASK_NAME && |
| 104 scheduledTaskName == UPDATE_CARDS_TASK_NAME) { | 99 scheduledTaskName == UPDATE_CARDS_TASK_NAME) { |
| 105 // If a card update is requested while an old update is still scheduled, we | 100 // If a card update is requested while an old update is still scheduled, we |
| 106 // don't need the new update. | 101 // don't need the new update. |
| 107 return true; | 102 return true; |
| 108 } | 103 } |
| 109 | 104 |
| 110 if (newTaskName == RETRY_DISMISS_TASK_NAME && | 105 if (newTaskName == RETRY_DISMISS_TASK_NAME && |
| 111 (scheduledTaskName == UPDATE_CARDS_TASK_NAME || | 106 (scheduledTaskName == UPDATE_CARDS_TASK_NAME || |
| 112 scheduledTaskName == DISMISS_CARD_TASK_NAME || | 107 scheduledTaskName == DISMISS_CARD_TASK_NAME || |
| 113 scheduledTaskName == RETRY_DISMISS_TASK_NAME)) { | 108 scheduledTaskName == RETRY_DISMISS_TASK_NAME)) { |
| 114 // No need to schedule retry-dismiss action if another action that tries to | 109 // No need to schedule retry-dismiss action if another action that tries to |
| 115 // send dismissals is scheduled. | 110 // send dismissals is scheduled. |
| 116 return true; | 111 return true; |
| 117 } | 112 } |
| 118 | 113 |
| 119 return false; | 114 return false; |
| 120 } | 115 } |
| 121 | 116 |
| 117 var googleGeolocationAccessEnabledPref = | |
| 118 chrome.preferencesPrivate.googleGeolocationAccessEnabled; | |
| 119 | |
| 122 var tasks = buildTaskManager(areTasksConflicting); | 120 var tasks = buildTaskManager(areTasksConflicting); |
| 123 | 121 |
| 124 // Add error processing to API calls. | 122 // Add error processing to API calls. |
| 125 tasks.instrumentApiFunction(chrome.identity, 'getAuthToken', 1); | 123 tasks.instrumentApiFunction(chrome.identity, 'getAuthToken', 1); |
| 126 tasks.instrumentApiFunction(chrome.identity, 'removeCachedAuthToken', 1); | 124 tasks.instrumentApiFunction(chrome.identity, 'removeCachedAuthToken', 1); |
| 127 tasks.instrumentApiFunction(chrome.location.onLocationUpdate, 'addListener', 0); | 125 tasks.instrumentApiFunction(chrome.location.onLocationUpdate, 'addListener', 0); |
| 128 tasks.instrumentApiFunction(chrome.notifications, 'create', 2); | 126 tasks.instrumentApiFunction(chrome.notifications, 'create', 2); |
| 129 tasks.instrumentApiFunction(chrome.notifications, 'update', 2); | 127 tasks.instrumentApiFunction(chrome.notifications, 'update', 2); |
| 130 tasks.instrumentApiFunction(chrome.notifications, 'getAll', 0); | 128 tasks.instrumentApiFunction(chrome.notifications, 'getAll', 0); |
| 131 tasks.instrumentApiFunction( | 129 tasks.instrumentApiFunction( |
| 132 chrome.notifications.onButtonClicked, 'addListener', 0); | 130 chrome.notifications.onButtonClicked, 'addListener', 0); |
| 133 tasks.instrumentApiFunction(chrome.notifications.onClicked, 'addListener', 0); | 131 tasks.instrumentApiFunction(chrome.notifications.onClicked, 'addListener', 0); |
| 134 tasks.instrumentApiFunction(chrome.notifications.onClosed, 'addListener', 0); | 132 tasks.instrumentApiFunction(chrome.notifications.onClosed, 'addListener', 0); |
| 133 tasks.instrumentApiFunction( | |
| 134 googleGeolocationAccessEnabledPref.onChange, | |
| 135 'addListener', | |
| 136 0); | |
| 135 tasks.instrumentApiFunction(chrome.runtime.onInstalled, 'addListener', 0); | 137 tasks.instrumentApiFunction(chrome.runtime.onInstalled, 'addListener', 0); |
| 136 tasks.instrumentApiFunction(chrome.runtime.onStartup, 'addListener', 0); | 138 tasks.instrumentApiFunction(chrome.runtime.onStartup, 'addListener', 0); |
| 137 tasks.instrumentApiFunction(chrome.tabs, 'create', 1); | 139 tasks.instrumentApiFunction(chrome.tabs, 'create', 1); |
| 138 tasks.instrumentApiFunction(storage, 'get', 1); | 140 tasks.instrumentApiFunction(storage, 'get', 1); |
| 139 | 141 |
| 140 var updateCardsAttempts = buildAttemptManager( | 142 var updateCardsAttempts = buildAttemptManager( |
| 141 'cards-update', | 143 'cards-update', |
| 142 requestLocation, | 144 requestLocation, |
| 143 INITIAL_POLLING_PERIOD_SECONDS, | 145 INITIAL_POLLING_PERIOD_SECONDS, |
| 144 MAXIMUM_POLLING_PERIOD_SECONDS); | 146 MAXIMUM_POLLING_PERIOD_SECONDS); |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 storage.set({ | 387 storage.set({ |
| 386 notificationsData: newNotificationsData, | 388 notificationsData: newNotificationsData, |
| 387 recentDismissals: updatedRecentDismissals | 389 recentDismissals: updatedRecentDismissals |
| 388 }); | 390 }); |
| 389 callback(); | 391 callback(); |
| 390 }); | 392 }); |
| 391 }); | 393 }); |
| 392 } | 394 } |
| 393 | 395 |
| 394 /** | 396 /** |
| 397 * Removes all cards and card state on Google Now close down. | |
| 398 * For example, this occurs when the geolocation preference is unchecked in the | |
| 399 * content settings. | |
| 400 */ | |
| 401 function removeAllCards() { | |
| 402 console.log('removeAllCards'); | |
| 403 | |
| 404 // TODO(robliao): Once Google Now clears its own checkbox in the | |
| 405 // notifications center and bug 260376 is fixed, the below clearing | |
| 406 // code is no longer necessary. | |
| 407 chrome.notifications.getAll(function(notifications) { | |
| 408 for (var notificationId in notifications) { | |
| 409 chrome.notifications.clear(notificationId, function() {}); | |
| 410 } | |
| 411 storage.set({notificationsData: {}}); | |
| 412 }); | |
| 413 } | |
| 414 | |
| 415 /** | |
| 395 * Requests notification cards from the server. | 416 * Requests notification cards from the server. |
| 396 * @param {Location} position Location of this computer. | 417 * @param {Location} position Location of this computer. |
| 397 * @param {function()} callback Completion callback. | 418 * @param {function()} callback Completion callback. |
| 398 */ | 419 */ |
| 399 function requestNotificationCards(position, callback) { | 420 function requestNotificationCards(position, callback) { |
| 400 console.log('requestNotificationCards ' + JSON.stringify(position) + | 421 console.log('requestNotificationCards ' + JSON.stringify(position) + |
| 401 ' from ' + NOTIFICATION_CARDS_URL); | 422 ' from ' + NOTIFICATION_CARDS_URL); |
| 402 | 423 |
| 403 if (!NOTIFICATION_CARDS_URL) { | 424 if (!NOTIFICATION_CARDS_URL) { |
| 404 callback(); | 425 callback(); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 439 /** | 460 /** |
| 440 * Starts getting location for a cards update. | 461 * Starts getting location for a cards update. |
| 441 */ | 462 */ |
| 442 function requestLocation() { | 463 function requestLocation() { |
| 443 console.log('requestLocation'); | 464 console.log('requestLocation'); |
| 444 recordEvent(DiagnosticEvent.LOCATION_REQUEST); | 465 recordEvent(DiagnosticEvent.LOCATION_REQUEST); |
| 445 // TODO(vadimt): Figure out location request options. | 466 // TODO(vadimt): Figure out location request options. |
| 446 chrome.location.watchLocation(LOCATION_WATCH_NAME, {}); | 467 chrome.location.watchLocation(LOCATION_WATCH_NAME, {}); |
| 447 } | 468 } |
| 448 | 469 |
| 470 /** | |
| 471 * Stops getting the location. | |
| 472 */ | |
| 473 function stopRequestLocation() { | |
| 474 console.log('stopRequestLocation'); | |
| 475 chrome.location.clearWatch(LOCATION_WATCH_NAME); | |
| 476 } | |
| 449 | 477 |
| 450 /** | 478 /** |
| 451 * Obtains new location; requests and shows notification cards based on this | 479 * Obtains new location; requests and shows notification cards based on this |
| 452 * location. | 480 * location. |
| 453 * @param {Location} position Location of this computer. | 481 * @param {Location} position Location of this computer. |
| 454 */ | 482 */ |
| 455 function updateNotificationsCards(position) { | 483 function updateNotificationsCards(position) { |
| 456 console.log('updateNotificationsCards ' + JSON.stringify(position) + | 484 console.log('updateNotificationsCards ' + JSON.stringify(position) + |
| 457 ' @' + new Date()); | 485 ' @' + new Date()); |
| 458 tasks.add(UPDATE_CARDS_TASK_NAME, function(callback) { | 486 tasks.add(UPDATE_CARDS_TASK_NAME, function(callback) { |
| 459 console.log('updateNotificationsCards-task-begin'); | 487 console.log('updateNotificationsCards-task-begin'); |
| 460 updateCardsAttempts.planForNext(function() { | 488 updateCardsAttempts.isRunning(function(running) { |
| 461 processPendingDismissals(function(success) { | 489 if (running) { |
| 462 if (success) { | 490 updateCardsAttempts.planForNext(function() { |
| 463 // The cards are requested only if there are no unsent dismissals. | 491 processPendingDismissals(function(success) { |
| 464 requestNotificationCards(position, callback); | 492 if (success) { |
| 465 } else { | 493 // The cards are requested only if there are no unsent dismissals. |
| 466 callback(); | 494 requestNotificationCards(position, callback); |
| 467 } | 495 } else { |
| 468 }); | 496 callback(); |
| 497 } | |
| 498 }); | |
| 499 }); | |
| 500 } | |
| 469 }); | 501 }); |
| 470 }); | 502 }); |
| 471 } | 503 } |
| 472 | 504 |
| 473 /** | 505 /** |
| 474 * Sends a server request to dismiss a card. | 506 * Sends a server request to dismiss a card. |
| 475 * @param {string} notificationId Unique identifier of the card. | 507 * @param {string} notificationId Unique identifier of the card. |
| 476 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in | 508 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in |
| 477 * milliseconds since epoch. | 509 * milliseconds since epoch. |
| 478 * @param {Object} dismissalParameters Dismissal parameters. | 510 * @param {Object} dismissalParameters Dismissal parameters. |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 621 chrome.windows.create({url: url}); | 653 chrome.windows.create({url: url}); |
| 622 }); | 654 }); |
| 623 }); | 655 }); |
| 624 } | 656 } |
| 625 | 657 |
| 626 /** | 658 /** |
| 627 * Responds to a click of one of the buttons on the welcome toast. | 659 * Responds to a click of one of the buttons on the welcome toast. |
| 628 * @param {number} buttonIndex The index of the button which was clicked. | 660 * @param {number} buttonIndex The index of the button which was clicked. |
| 629 */ | 661 */ |
| 630 function onToastNotificationClicked(buttonIndex) { | 662 function onToastNotificationClicked(buttonIndex) { |
| 663 storage.set({userRespondedToToast: true}); | |
| 664 | |
| 631 if (buttonIndex == ToastButtonIndex.YES) { | 665 if (buttonIndex == ToastButtonIndex.YES) { |
| 632 chrome.metricsPrivate.recordUserAction('GoogleNow.WelcomeToastClickedYes'); | 666 chrome.metricsPrivate.recordUserAction('GoogleNow.WelcomeToastClickedYes'); |
| 633 storage.set({toastState: ToastOptionResponse.CHOSE_YES}); | 667 googleGeolocationAccessEnabledPref.set({value: true}); |
| 634 | 668 // The googlegeolocationaccessenabled preference change callback |
| 635 // TODO(zturner): Update chrome geolocation setting once the settings | 669 // will take care of starting the poll for cards. |
| 636 // API is in place. | |
| 637 startPollingCards(); | |
| 638 } else { | 670 } else { |
| 639 chrome.metricsPrivate.recordUserAction('GoogleNow.WelcomeToastClickedNo'); | 671 chrome.metricsPrivate.recordUserAction('GoogleNow.WelcomeToastClickedNo'); |
| 640 storage.set({toastState: ToastOptionResponse.CHOSE_NO}); | 672 onStateChange(); |
| 641 } | 673 } |
| 642 | |
| 643 chrome.notifications.clear( | |
| 644 WELCOME_TOAST_NOTIFICATION_ID, | |
| 645 function(wasCleared) {}); | |
| 646 } | 674 } |
| 647 | 675 |
| 648 /** | 676 /** |
| 649 * Callback for chrome.notifications.onClosed event. | 677 * Callback for chrome.notifications.onClosed event. |
| 650 * @param {string} notificationId Unique identifier of the notification. | 678 * @param {string} notificationId Unique identifier of the notification. |
| 651 * @param {boolean} byUser Whether the notification was closed by the user. | 679 * @param {boolean} byUser Whether the notification was closed by the user. |
| 652 */ | 680 */ |
| 653 function onNotificationClosed(notificationId, byUser) { | 681 function onNotificationClosed(notificationId, byUser) { |
| 654 if (!byUser) | 682 if (!byUser) |
| 655 return; | 683 return; |
| 656 | 684 |
| 657 if (notificationId == WELCOME_TOAST_NOTIFICATION_ID) { | 685 if (notificationId == WELCOME_TOAST_NOTIFICATION_ID) { |
| 658 // Even though they only closed the notification without clicking no, treat | 686 // Even though they only closed the notification without clicking no, treat |
| 659 // it as though they clicked No anwyay, and don't show the toast again. | 687 // it as though they clicked No anwyay, and don't show the toast again. |
| 660 chrome.metricsPrivate.recordUserAction('GoogleNow.WelcomeToastDismissed'); | 688 chrome.metricsPrivate.recordUserAction('GoogleNow.WelcomeToastDismissed'); |
| 661 storage.set({toastState: ToastOptionResponse.CHOSE_NO}); | 689 storage.set({userRespondedToToast: true}); |
| 662 return; | 690 return; |
| 663 } | 691 } |
| 664 | 692 |
| 665 // At this point we are guaranteed that the notification is a now card. | 693 // At this point we are guaranteed that the notification is a now card. |
| 666 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); | 694 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); |
| 667 | 695 |
| 668 tasks.add(DISMISS_CARD_TASK_NAME, function(callback) { | 696 tasks.add(DISMISS_CARD_TASK_NAME, function(callback) { |
| 669 dismissalAttempts.start(); | 697 dismissalAttempts.start(); |
| 670 | 698 |
| 671 // Deleting the notification in case it was re-added while this task was | 699 // Deleting the notification in case it was re-added while this task was |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 699 */ | 727 */ |
| 700 function startPollingCards() { | 728 function startPollingCards() { |
| 701 // Create an update timer for a case when for some reason location request | 729 // Create an update timer for a case when for some reason location request |
| 702 // gets stuck. | 730 // gets stuck. |
| 703 updateCardsAttempts.start(MAXIMUM_POLLING_PERIOD_SECONDS); | 731 updateCardsAttempts.start(MAXIMUM_POLLING_PERIOD_SECONDS); |
| 704 | 732 |
| 705 requestLocation(); | 733 requestLocation(); |
| 706 } | 734 } |
| 707 | 735 |
| 708 /** | 736 /** |
| 737 * Stops all machinery in the polling system. | |
| 738 */ | |
| 739 function stopPollingCards() { | |
| 740 stopRequestLocation(); | |
| 741 | |
| 742 updateCardsAttempts.stop(); | |
| 743 | |
| 744 removeAllCards(); | |
| 745 } | |
| 746 | |
| 747 /** | |
| 748 * Stops everything in Google Now from polling. | |
| 749 */ | |
| 750 function stopAndCloseDown() { | |
|
vadimt
2013/07/24 20:49:43
You don't need this method. You already have stopP
robliao
2013/07/24 21:07:06
Done.
| |
| 751 stopPollingCards(); | |
| 752 } | |
| 753 | |
| 754 /** | |
| 709 * Initializes the event page on install or on browser startup. | 755 * Initializes the event page on install or on browser startup. |
| 710 */ | 756 */ |
| 711 function initialize() { | 757 function initialize() { |
| 712 recordEvent(DiagnosticEvent.EXTENSION_START); | 758 recordEvent(DiagnosticEvent.EXTENSION_START); |
| 713 storage.get('toastState', function(items) { | |
| 714 // The toast state might be undefined (e.g. not in storage yet) if this is | |
| 715 // the first time ever being prompted. | |
| 716 | 759 |
| 717 // TODO(zturner): Get the value of isGeolocationEnabled from the settings | 760 // Alarms persist across chrome restarts. This is undesirable since it |
| 718 // api and additionally make sure it is true. | 761 // prevents us from starting up everything (alarms are a heuristic to |
| 719 if (!items.toastState) { | 762 // determine if we are already running). To mitigate this, we will |
| 720 if (NOTIFICATION_CARDS_URL) { | 763 // shut everything down on initialize before starting everything up. |
| 721 chrome.identity.getAuthToken({interactive: false}, function(token) { | 764 stopAndCloseDown(); |
| 722 if (!chrome.runtime.lastError && token) | 765 onStateChange(); |
| 723 showWelcomeToast(); | 766 } |
| 724 }); | 767 |
| 725 } | 768 /** |
| 726 } else if (items.toastState == ToastOptionResponse.CHOSE_YES) { | 769 * Starts or stops the extension machinery. |
| 727 startPollingCards(); | 770 * @param {boolean} shouldRunRequest true to start and |
| 771 * false to stop this extension. | |
| 772 * @param {function} onSuccess Called on completion. | |
| 773 */ | |
| 774 function setShouldRun(shouldRunRequest, onSuccess) { | |
| 775 tasks.debugSetStepName( | |
| 776 'setShouldRun-shouldRun-updateCardsAttemptsIsRunning'); | |
| 777 updateCardsAttempts.isRunning(function(currentValue) { | |
| 778 if (shouldRunRequest != currentValue) { | |
| 779 if (shouldRunRequest) | |
| 780 startPollingCards(); | |
| 781 else | |
| 782 stopAndCloseDown(); | |
| 728 } | 783 } |
| 784 onSuccess(); | |
| 729 }); | 785 }); |
| 730 } | 786 } |
| 731 | 787 |
| 788 /** | |
| 789 * Shows or hides the toast. | |
| 790 * @param {boolean} visibleRequest true to show the toast and | |
| 791 * false to hide the toast. | |
| 792 * @param {function} onSuccess Called on completion. | |
| 793 */ | |
| 794 function setToastVisible(visibleRequest, onSuccess) { | |
| 795 tasks.debugSetStepName( | |
| 796 'setToastVisible-shouldSetToastVisible-getAllNotifications'); | |
| 797 chrome.notifications.getAll(function(notifications) { | |
| 798 // TODO(vadimt): Figure out what to do when notifications are disabled for | |
| 799 // our extension. | |
| 800 notifications = notifications || {}; | |
| 801 | |
| 802 if (visibleRequest != !!notifications[WELCOME_TOAST_NOTIFICATION_ID]) { | |
| 803 if (visibleRequest) | |
| 804 showWelcomeToast(); | |
| 805 else | |
| 806 hideWelcomeToast(); | |
| 807 } | |
| 808 | |
| 809 onSuccess(); | |
| 810 }); | |
| 811 } | |
| 812 | |
| 813 /** | |
| 814 * Does the actual work of deciding what Google Now should do | |
| 815 * based off of the current state of Chrome. | |
| 816 * @param {boolean} signedIn true if the user is signed in. | |
| 817 * @param {boolean} geolocationEnabled true if | |
| 818 * the geolocation option is enabled. | |
| 819 * @param {boolean} userRespondedToToast true if | |
| 820 * the user has responded to the toast. | |
| 821 * @param {function()} callback Call this function on completion. | |
| 822 */ | |
| 823 function updateRunningState( | |
| 824 signedIn, | |
| 825 geolocationEnabled, | |
| 826 userRespondedToToast, | |
| 827 callback) { | |
| 828 | |
| 829 var shouldSetToastVisible = false; | |
| 830 var shouldRun = false; | |
| 831 | |
| 832 if (signedIn) { | |
| 833 if (geolocationEnabled) { | |
| 834 if (!userRespondedToToast) { | |
| 835 // If the user enabled geolocation independently of Google Now, | |
| 836 // the user has implicitly responded to the toast. | |
| 837 // We do not want to show it again. | |
| 838 storage.set({userRespondedToToast: true}); | |
| 839 } | |
| 840 | |
| 841 shouldRun = true; | |
| 842 } else { | |
| 843 if (userRespondedToToast) { | |
| 844 shouldRun = false; | |
| 845 } else { | |
| 846 shouldSetToastVisible = true; | |
| 847 } | |
| 848 } | |
| 849 } else { | |
| 850 shouldRun = false; | |
| 851 } | |
| 852 | |
| 853 setToastVisible(shouldSetToastVisible, function() { | |
| 854 setShouldRun(shouldRun, callback); | |
| 855 }); | |
| 856 } | |
| 857 | |
| 858 /** | |
| 859 * Coordinates the behavior of Google Now for Chrome depending on | |
| 860 * Chrome and extension state. | |
| 861 */ | |
| 862 function onStateChange() { | |
| 863 tasks.add(STATE_CHANGED_TASK_NAME, function(callback) { | |
| 864 tasks.debugSetStepName('onStateChange-getAuthToken'); | |
| 865 chrome.identity.getAuthToken({interactive: false}, function(token) { | |
| 866 var signedIn = | |
| 867 !chrome.runtime.lastError && | |
| 868 token && | |
| 869 !!NOTIFICATION_CARDS_URL; | |
| 870 tasks.debugSetStepName( | |
| 871 'onStateChange-get-googleGeolocationAccessEnabledPref'); | |
| 872 googleGeolocationAccessEnabledPref.get({}, function(prefValue) { | |
| 873 var geolocationEnabled = !!prefValue.value; | |
| 874 tasks.debugSetStepName( | |
| 875 'onStateChange-get-userRespondedToToast'); | |
| 876 storage.get('userRespondedToToast', function(items) { | |
| 877 var userRespondedToToast = !!items.userRespondedToToast; | |
| 878 updateRunningState( | |
| 879 signedIn, | |
| 880 geolocationEnabled, | |
| 881 userRespondedToToast, | |
| 882 callback); | |
| 883 }); | |
| 884 }); | |
| 885 }); | |
| 886 }); | |
| 887 } | |
| 888 | |
| 732 /** | 889 /** |
| 733 * Displays a toast to the user asking if they want to opt in to receiving | 890 * Displays a toast to the user asking if they want to opt in to receiving |
| 734 * Google Now cards. | 891 * Google Now cards. |
| 735 */ | 892 */ |
| 736 function showWelcomeToast() { | 893 function showWelcomeToast() { |
| 737 recordEvent(DiagnosticEvent.SHOW_WELCOME_TOAST); | 894 recordEvent(DiagnosticEvent.SHOW_WELCOME_TOAST); |
| 738 // TODO(zturner): Localize this once the component extension localization | 895 // TODO(zturner): Localize this once the component extension localization |
| 739 // api is complete. | 896 // api is complete. |
| 740 // TODO(zturner): Add icons. | 897 // TODO(zturner): Add icons. |
| 741 var buttons = [{title: 'Yes'}, {title: 'No'}]; | 898 var buttons = [{title: 'Yes'}, {title: 'No'}]; |
| 742 var options = { | 899 var options = { |
| 743 type: 'basic', | 900 type: 'basic', |
| 744 title: 'Enable Google Now Cards', | 901 title: 'Enable Google Now Cards', |
| 745 message: 'Would you like to be shown Google Now cards?', | 902 message: 'Would you like to be shown Google Now cards?', |
| 746 iconUrl: 'http://www.gstatic.com/googlenow/chrome/default.png', | 903 iconUrl: 'http://www.gstatic.com/googlenow/chrome/default.png', |
| 747 priority: 2, | 904 priority: 2, |
| 748 buttons: buttons | 905 buttons: buttons |
| 749 }; | 906 }; |
| 750 chrome.notifications.create(WELCOME_TOAST_NOTIFICATION_ID, options, | 907 chrome.notifications.create(WELCOME_TOAST_NOTIFICATION_ID, options, |
| 751 function(notificationId) {}); | 908 function(notificationId) {}); |
| 752 } | 909 } |
| 753 | 910 |
| 911 /** | |
| 912 * Hides the welcome toast. | |
| 913 */ | |
| 914 function hideWelcomeToast() { | |
| 915 chrome.notifications.clear( | |
| 916 WELCOME_TOAST_NOTIFICATION_ID, | |
| 917 function() {}); | |
| 918 } | |
| 919 | |
| 754 chrome.runtime.onInstalled.addListener(function(details) { | 920 chrome.runtime.onInstalled.addListener(function(details) { |
| 755 console.log('onInstalled ' + JSON.stringify(details)); | 921 console.log('onInstalled ' + JSON.stringify(details)); |
| 756 if (details.reason != 'chrome_update') { | 922 if (details.reason != 'chrome_update') { |
| 757 initialize(); | 923 initialize(); |
| 758 } | 924 } |
| 759 }); | 925 }); |
| 760 | 926 |
| 761 chrome.runtime.onStartup.addListener(function() { | 927 chrome.runtime.onStartup.addListener(function() { |
| 762 console.log('onStartup'); | 928 console.log('onStartup'); |
| 763 initialize(); | 929 initialize(); |
| 764 }); | 930 }); |
| 765 | 931 |
| 932 googleGeolocationAccessEnabledPref.onChange.addListener(function(prefValue) { | |
| 933 console.log('googleGeolocationAccessEnabledPref onChange ' + prefValue.value); | |
| 934 onStateChange(); | |
| 935 }); | |
| 936 | |
| 766 chrome.notifications.onClicked.addListener( | 937 chrome.notifications.onClicked.addListener( |
| 767 function(notificationId) { | 938 function(notificationId) { |
| 768 chrome.metricsPrivate.recordUserAction('GoogleNow.MessageClicked'); | 939 chrome.metricsPrivate.recordUserAction('GoogleNow.MessageClicked'); |
| 769 onNotificationClicked(notificationId, function(actionUrls) { | 940 onNotificationClicked(notificationId, function(actionUrls) { |
| 770 return actionUrls.messageUrl; | 941 return actionUrls.messageUrl; |
| 771 }); | 942 }); |
| 772 }); | 943 }); |
| 773 | 944 |
| 774 chrome.notifications.onButtonClicked.addListener( | 945 chrome.notifications.onButtonClicked.addListener( |
| 775 function(notificationId, buttonIndex) { | 946 function(notificationId, buttonIndex) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 791 | 962 |
| 792 chrome.location.onLocationUpdate.addListener(function(position) { | 963 chrome.location.onLocationUpdate.addListener(function(position) { |
| 793 recordEvent(DiagnosticEvent.LOCATION_UPDATE); | 964 recordEvent(DiagnosticEvent.LOCATION_UPDATE); |
| 794 updateNotificationsCards(position); | 965 updateNotificationsCards(position); |
| 795 }); | 966 }); |
| 796 | 967 |
| 797 chrome.omnibox.onInputEntered.addListener(function(text) { | 968 chrome.omnibox.onInputEntered.addListener(function(text) { |
| 798 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; | 969 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; |
| 799 initialize(); | 970 initialize(); |
| 800 }); | 971 }); |
| OLD | NEW |