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. |
11 * The service performs periodic updating of Google Now cards. | 11 * The service performs periodic updating of Google Now cards. |
12 * Each updating of the cards includes 4 steps: | 12 * Each updating of the cards includes 4 steps: |
13 * 1. Obtaining the location of the machine; | 13 * 1. Obtaining the location of the machine; |
14 * 2. Processing requests for cards dismissals that are not yet sent to the | 14 * 2. Processing requests for cards dismissals that are not yet sent to the |
15 * server; | 15 * server; |
16 * 3. Making a server request based on that location; | 16 * 3. Making a server request based on that location; |
17 * 4. Showing the received cards as notifications. | 17 * 4. Showing the received cards as notifications. |
18 */ | 18 */ |
19 | 19 |
20 // TODO(vadimt): Use background permission to show notifications even when all | 20 // TODO(vadimt): Use background permission to show notifications even when all |
21 // browser windows are closed. | 21 // browser windows are closed. |
22 // TODO(vadimt): Decide what to do in incognito mode. | 22 // TODO(vadimt): Decide what to do in incognito mode. |
23 // TODO(vadimt): Honor the flag the enables Google Now integration. | 23 // TODO(vadimt): Honor the flag the enables Google Now integration. |
24 // TODO(vadimt): Figure out the final values of the constants. | 24 // TODO(vadimt): Figure out the final values of the constants. |
25 // TODO(vadimt): Remove 'console' calls. | 25 // TODO(vadimt): Remove 'console' calls. |
26 // TODO(vadimt): Consider sending JS stacks for chrome.* API errors and | 26 // TODO(vadimt): Consider sending JS stacks for malformed server responses. |
27 // malformed server responses. | |
28 | 27 |
29 /** | 28 /** |
30 * Standard response code for successful HTTP requests. This is the only success | 29 * Standard response code for successful HTTP requests. This is the only success |
31 * code the server will send. | 30 * code the server will send. |
32 */ | 31 */ |
33 var HTTP_OK = 200; | 32 var HTTP_OK = 200; |
34 | 33 |
35 var HTTP_BAD_REQUEST = 400; | 34 var HTTP_BAD_REQUEST = 400; |
36 var HTTP_UNAUTHORIZED = 401; | 35 var HTTP_UNAUTHORIZED = 401; |
37 var HTTP_FORBIDDEN = 403; | 36 var HTTP_FORBIDDEN = 403; |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 * For example, this occurs when the geolocation preference is unchecked in the | 338 * For example, this occurs when the geolocation preference is unchecked in the |
340 * content settings. | 339 * content settings. |
341 */ | 340 */ |
342 function removeAllCards() { | 341 function removeAllCards() { |
343 console.log('removeAllCards'); | 342 console.log('removeAllCards'); |
344 | 343 |
345 // TODO(robliao): Once Google Now clears its own checkbox in the | 344 // TODO(robliao): Once Google Now clears its own checkbox in the |
346 // notifications center and bug 260376 is fixed, the below clearing | 345 // notifications center and bug 260376 is fixed, the below clearing |
347 // code is no longer necessary. | 346 // code is no longer necessary. |
348 instrumented.notifications.getAll(function(notifications) { | 347 instrumented.notifications.getAll(function(notifications) { |
| 348 notifications = notifications || {}; |
349 for (var notificationId in notifications) { | 349 for (var notificationId in notifications) { |
350 chrome.notifications.clear(notificationId, function() {}); | 350 chrome.notifications.clear(notificationId, function() {}); |
351 } | 351 } |
352 chrome.storage.local.set({notificationsData: {}}); | 352 chrome.storage.local.set({notificationsData: {}}); |
353 }); | 353 }); |
354 } | 354 } |
355 | 355 |
356 /** | 356 /** |
357 * Requests notification cards from the server. | 357 * Requests notification cards from the server. |
358 * @param {Location} position Location of this computer. | 358 * @param {Location} position Location of this computer. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 }); | 398 }); |
399 } | 399 } |
400 | 400 |
401 /** | 401 /** |
402 * Starts getting location for a cards update. | 402 * Starts getting location for a cards update. |
403 */ | 403 */ |
404 function requestLocation() { | 404 function requestLocation() { |
405 console.log('requestLocation'); | 405 console.log('requestLocation'); |
406 recordEvent(GoogleNowEvent.LOCATION_REQUEST); | 406 recordEvent(GoogleNowEvent.LOCATION_REQUEST); |
407 // TODO(vadimt): Figure out location request options. | 407 // TODO(vadimt): Figure out location request options. |
408 chrome.metricsPrivate.getVariationParams('GoogleNow', function(params) { | 408 instrumented.metricsPrivate.getVariationParams('GoogleNow', function(params) { |
409 var minDistanceInMeters = | 409 var minDistanceInMeters = |
410 parseInt(params && params.minDistanceInMeters, 10) || | 410 parseInt(params && params.minDistanceInMeters, 10) || |
411 100; | 411 100; |
412 var minTimeInMilliseconds = | 412 var minTimeInMilliseconds = |
413 parseInt(params && params.minTimeInMilliseconds, 10) || | 413 parseInt(params && params.minTimeInMilliseconds, 10) || |
414 180000; // 3 minutes. | 414 180000; // 3 minutes. |
415 | 415 |
416 chrome.location.watchLocation(LOCATION_WATCH_NAME, { | 416 chrome.location.watchLocation(LOCATION_WATCH_NAME, { |
417 minDistanceInMeters: minDistanceInMeters, | 417 minDistanceInMeters: minDistanceInMeters, |
418 minTimeInMilliseconds: minTimeInMilliseconds | 418 minTimeInMilliseconds: minTimeInMilliseconds |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 } | 575 } |
576 | 576 |
577 /** | 577 /** |
578 * Opens URL corresponding to the clicked part of the notification. | 578 * Opens URL corresponding to the clicked part of the notification. |
579 * @param {string} notificationId Unique identifier of the notification. | 579 * @param {string} notificationId Unique identifier of the notification. |
580 * @param {function(Object): string} selector Function that extracts the url for | 580 * @param {function(Object): string} selector Function that extracts the url for |
581 * the clicked area from the button action URLs info. | 581 * the clicked area from the button action URLs info. |
582 */ | 582 */ |
583 function onNotificationClicked(notificationId, selector) { | 583 function onNotificationClicked(notificationId, selector) { |
584 instrumented.storage.local.get('notificationsData', function(items) { | 584 instrumented.storage.local.get('notificationsData', function(items) { |
585 items.notificationsData = items.notificationsData || {}; | 585 var notificationData = items && |
| 586 items.notificationsData && |
| 587 items.notificationsData[notificationId]; |
586 | 588 |
587 var notificationData = items.notificationsData[notificationId]; | 589 if (!notificationData) |
588 | |
589 if (!notificationData) { | |
590 // 'notificationsData' in storage may not match the actual list of | |
591 // notifications. | |
592 return; | 590 return; |
593 } | |
594 | 591 |
595 var actionUrls = notificationData.actionUrls; | 592 var actionUrls = notificationData.actionUrls; |
596 if (typeof actionUrls != 'object') { | 593 if (typeof actionUrls != 'object') { |
597 return; | 594 return; |
598 } | 595 } |
599 | 596 |
600 var url = selector(actionUrls); | 597 var url = selector(actionUrls); |
601 | 598 if (!url) |
602 if (typeof url != 'string') | |
603 return; | 599 return; |
604 | 600 |
605 instrumented.tabs.create({url: url}, function(tab) { | 601 instrumented.tabs.create({url: url}, function(tab) { |
606 if (tab) | 602 if (tab) |
607 chrome.windows.update(tab.windowId, {focused: true}); | 603 chrome.windows.update(tab.windowId, {focused: true}); |
608 else | 604 else |
609 chrome.windows.create({url: url, focused: true}); | 605 chrome.windows.create({url: url, focused: true}); |
610 }); | 606 }); |
611 }); | 607 }); |
612 } | 608 } |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
879 instrumented. | 875 instrumented. |
880 preferencesPrivate. | 876 preferencesPrivate. |
881 googleGeolocationAccessEnabled. | 877 googleGeolocationAccessEnabled. |
882 get({}, function(prefValue) { | 878 get({}, function(prefValue) { |
883 var geolocationEnabled = !!prefValue.value; | 879 var geolocationEnabled = !!prefValue.value; |
884 tasks.debugSetStepName( | 880 tasks.debugSetStepName( |
885 'onStateChange-get-userRespondedToToast'); | 881 'onStateChange-get-userRespondedToToast'); |
886 instrumented.storage.local.get( | 882 instrumented.storage.local.get( |
887 'userRespondedToToast', | 883 'userRespondedToToast', |
888 function(items) { | 884 function(items) { |
889 var userRespondedToToast = !!items.userRespondedToToast; | 885 var userRespondedToToast = |
| 886 !items || !!items.userRespondedToToast; |
890 updateRunningState( | 887 updateRunningState( |
891 signedIn, | 888 signedIn, |
892 geolocationEnabled, | 889 geolocationEnabled, |
893 userRespondedToToast, | 890 userRespondedToToast, |
894 enableBackground, | 891 enableBackground, |
895 callback); | 892 callback); |
896 }); | 893 }); |
897 }); | 894 }); |
898 }); | 895 }); |
899 }); | 896 }); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
967 }); | 964 }); |
968 | 965 |
969 instrumented.notifications.onButtonClicked.addListener( | 966 instrumented.notifications.onButtonClicked.addListener( |
970 function(notificationId, buttonIndex) { | 967 function(notificationId, buttonIndex) { |
971 if (notificationId == WELCOME_TOAST_NOTIFICATION_ID) { | 968 if (notificationId == WELCOME_TOAST_NOTIFICATION_ID) { |
972 onToastNotificationClicked(buttonIndex); | 969 onToastNotificationClicked(buttonIndex); |
973 } else { | 970 } else { |
974 chrome.metricsPrivate.recordUserAction( | 971 chrome.metricsPrivate.recordUserAction( |
975 'GoogleNow.ButtonClicked' + buttonIndex); | 972 'GoogleNow.ButtonClicked' + buttonIndex); |
976 onNotificationClicked(notificationId, function(actionUrls) { | 973 onNotificationClicked(notificationId, function(actionUrls) { |
977 if (!Array.isArray(actionUrls.buttonUrls)) | 974 var url = actionUrls.buttonUrls[buttonIndex]; |
978 return undefined; | 975 verify(url, 'onButtonClicked: no url for a button'); |
979 | 976 return url; |
980 return actionUrls.buttonUrls[buttonIndex]; | |
981 }); | 977 }); |
982 } | 978 } |
983 }); | 979 }); |
984 | 980 |
985 instrumented.notifications.onClosed.addListener(onNotificationClosed); | 981 instrumented.notifications.onClosed.addListener(onNotificationClosed); |
986 | 982 |
987 instrumented.location.onLocationUpdate.addListener(function(position) { | 983 instrumented.location.onLocationUpdate.addListener(function(position) { |
988 recordEvent(GoogleNowEvent.LOCATION_UPDATE); | 984 recordEvent(GoogleNowEvent.LOCATION_UPDATE); |
989 updateNotificationsCards(position); | 985 updateNotificationsCards(position); |
990 }); | 986 }); |
991 | 987 |
992 instrumented.omnibox.onInputEntered.addListener(function(text) { | 988 instrumented.omnibox.onInputEntered.addListener(function(text) { |
993 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; | 989 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; |
994 initialize(); | 990 initialize(); |
995 }); | 991 }); |
OLD | NEW |