| 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 14 matching lines...) Expand all Loading... |
| 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 chrome.* API errors and |
| 27 // malformed server responses. | 27 // malformed server responses. |
| 28 | 28 |
| 29 /** | 29 /** |
| 30 * Standard response code for successful HTTP requests. This is the only success | 30 * Standard response code for successful HTTP requests. This is the only success |
| 31 * code the server will send. | 31 * code the server will send. |
| 32 */ | 32 */ |
| 33 var HTTP_OK = 200; | 33 var HTTP_OK = 200; |
| 34 | 34 |
| 35 var HTTP_UNAUTHORIZED = 401; |
| 36 var HTTP_FORBIDDEN = 403; |
| 37 |
| 35 /** | 38 /** |
| 36 * Initial period for polling for Google Now Notifications cards to use when the | 39 * Initial period for polling for Google Now Notifications cards to use when the |
| 37 * period from the server is not available. | 40 * period from the server is not available. |
| 38 */ | 41 */ |
| 39 var INITIAL_POLLING_PERIOD_SECONDS = 5 * 60; // 5 minutes | 42 var INITIAL_POLLING_PERIOD_SECONDS = 5 * 60; // 5 minutes |
| 40 | 43 |
| 41 /** | 44 /** |
| 42 * Maximal period for polling for Google Now Notifications cards to use when the | 45 * Maximal period for polling for Google Now Notifications cards to use when the |
| 43 * period from the server is not available. | 46 * period from the server is not available. |
| 44 */ | 47 */ |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 // send dismissals is scheduled. | 108 // send dismissals is scheduled. |
| 106 return true; | 109 return true; |
| 107 } | 110 } |
| 108 | 111 |
| 109 return false; | 112 return false; |
| 110 } | 113 } |
| 111 | 114 |
| 112 var tasks = buildTaskManager(areTasksConflicting); | 115 var tasks = buildTaskManager(areTasksConflicting); |
| 113 | 116 |
| 114 // Add error processing to API calls. | 117 // Add error processing to API calls. |
| 118 tasks.instrumentApiFunction(chrome.identity, 'getAuthToken', 1); |
| 119 tasks.instrumentApiFunction(chrome.identity, 'removeCachedAuthToken', 1); |
| 115 tasks.instrumentApiFunction(chrome.location.onLocationUpdate, 'addListener', 0); | 120 tasks.instrumentApiFunction(chrome.location.onLocationUpdate, 'addListener', 0); |
| 116 tasks.instrumentApiFunction(chrome.notifications, 'create', 2); | 121 tasks.instrumentApiFunction(chrome.notifications, 'create', 2); |
| 117 tasks.instrumentApiFunction(chrome.notifications, 'update', 2); | 122 tasks.instrumentApiFunction(chrome.notifications, 'update', 2); |
| 118 tasks.instrumentApiFunction(chrome.notifications, 'getAll', 0); | 123 tasks.instrumentApiFunction(chrome.notifications, 'getAll', 0); |
| 119 tasks.instrumentApiFunction( | 124 tasks.instrumentApiFunction( |
| 120 chrome.notifications.onButtonClicked, 'addListener', 0); | 125 chrome.notifications.onButtonClicked, 'addListener', 0); |
| 121 tasks.instrumentApiFunction(chrome.notifications.onClicked, 'addListener', 0); | 126 tasks.instrumentApiFunction(chrome.notifications.onClicked, 'addListener', 0); |
| 122 tasks.instrumentApiFunction(chrome.notifications.onClosed, 'addListener', 0); | 127 tasks.instrumentApiFunction(chrome.notifications.onClosed, 'addListener', 0); |
| 123 tasks.instrumentApiFunction(chrome.runtime.onInstalled, 'addListener', 0); | 128 tasks.instrumentApiFunction(chrome.runtime.onInstalled, 'addListener', 0); |
| 124 tasks.instrumentApiFunction(chrome.runtime.onStartup, 'addListener', 0); | 129 tasks.instrumentApiFunction(chrome.runtime.onStartup, 'addListener', 0); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 type: 'histogram-linear', | 167 type: 'histogram-linear', |
| 163 min: 1, | 168 min: 1, |
| 164 max: DiagnosticEvent.EVENTS_TOTAL, | 169 max: DiagnosticEvent.EVENTS_TOTAL, |
| 165 buckets: DiagnosticEvent.EVENTS_TOTAL + 1 | 170 buckets: DiagnosticEvent.EVENTS_TOTAL + 1 |
| 166 }; | 171 }; |
| 167 | 172 |
| 168 chrome.metricsPrivate.recordValue(metricDescription, event); | 173 chrome.metricsPrivate.recordValue(metricDescription, event); |
| 169 } | 174 } |
| 170 | 175 |
| 171 /** | 176 /** |
| 177 * Adds authorization behavior to the request. |
| 178 * @param {XMLHttpRequest} request Server request. |
| 179 * @param {function(boolean)} callbackBoolean Completion callback with 'success' |
| 180 * parameter. |
| 181 */ |
| 182 function setAuthorization(request, callbackBoolean) { |
| 183 tasks.debugSetStepName('setAuthorization-getAuthToken'); |
| 184 chrome.identity.getAuthToken({interactive: false}, function(token) { |
| 185 var errorMessage = |
| 186 chrome.runtime.lastError && chrome.runtime.lastError.message; |
| 187 console.log('setAuthorization: error=' + errorMessage + |
| 188 ', token=' + (token && 'non-empty')); |
| 189 if (chrome.runtime.lastError || !token) { |
| 190 callbackBoolean(false); |
| 191 return; |
| 192 } |
| 193 |
| 194 request.setRequestHeader('Authorization', 'Bearer ' + token); |
| 195 |
| 196 // Instrument onloadend to remove stale auth tokens. |
| 197 var originalOnLoadEnd = request.onloadend; |
| 198 request.onloadend = tasks.wrapCallback(function(event) { |
| 199 if (request.status == HTTP_FORBIDDEN || |
| 200 request.status == HTTP_UNAUTHORIZED) { |
| 201 tasks.debugSetStepName('setAuthorization-removeCachedAuthToken'); |
| 202 chrome.identity.removeCachedAuthToken({token: token}, function() { |
| 203 // After purging the token cache, call getAuthToken() again to let |
| 204 // Chrome know about the problem with the token. |
| 205 chrome.identity.getAuthToken({interactive: false}, function() {}); |
| 206 originalOnLoadEnd(event); |
| 207 }); |
| 208 } else { |
| 209 originalOnLoadEnd(event); |
| 210 } |
| 211 }); |
| 212 |
| 213 callbackBoolean(true); |
| 214 }); |
| 215 } |
| 216 |
| 217 /** |
| 172 * Shows a notification and remembers information associated with it. | 218 * Shows a notification and remembers information associated with it. |
| 173 * @param {Object} card Google Now card represented as a set of parameters for | 219 * @param {Object} card Google Now card represented as a set of parameters for |
| 174 * showing a Chrome notification. | 220 * showing a Chrome notification. |
| 175 * @param {Object} notificationsData Map from notification id to the data | 221 * @param {Object} notificationsData Map from notification id to the data |
| 176 * associated with a notification. | 222 * associated with a notification. |
| 177 * @param {number=} opt_previousVersion The version of the shown card with this | 223 * @param {number=} opt_previousVersion The version of the shown card with this |
| 178 * id, if it exists, undefined otherwise. | 224 * id, if it exists, undefined otherwise. |
| 179 */ | 225 */ |
| 180 function showNotification(card, notificationsData, opt_previousVersion) { | 226 function showNotification(card, notificationsData, opt_previousVersion) { |
| 181 console.log('showNotification ' + JSON.stringify(card) + ' ' + | 227 console.log('showNotification ' + JSON.stringify(card) + ' ' + |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 } | 396 } |
| 351 | 397 |
| 352 recordEvent(DiagnosticEvent.REQUEST_FOR_CARDS_TOTAL); | 398 recordEvent(DiagnosticEvent.REQUEST_FOR_CARDS_TOTAL); |
| 353 | 399 |
| 354 // TODO(vadimt): Should we use 'q' as the parameter name? | 400 // TODO(vadimt): Should we use 'q' as the parameter name? |
| 355 var requestParameters = | 401 var requestParameters = |
| 356 'q=' + position.coords.latitude + | 402 'q=' + position.coords.latitude + |
| 357 ',' + position.coords.longitude + | 403 ',' + position.coords.longitude + |
| 358 ',' + position.coords.accuracy; | 404 ',' + position.coords.accuracy; |
| 359 | 405 |
| 360 // TODO(vadimt): Figure out how to send user's identity to the server. | |
| 361 var request = buildServerRequest('notifications'); | 406 var request = buildServerRequest('notifications'); |
| 362 | 407 |
| 363 request.onloadend = tasks.wrapCallback(function(event) { | 408 request.onloadend = function(event) { |
| 364 console.log('requestNotificationCards-onloadend ' + request.status); | 409 console.log('requestNotificationCards-onloadend ' + request.status); |
| 365 if (request.status == HTTP_OK) { | 410 if (request.status == HTTP_OK) { |
| 366 recordEvent(DiagnosticEvent.REQUEST_FOR_CARDS_SUCCESS); | 411 recordEvent(DiagnosticEvent.REQUEST_FOR_CARDS_SUCCESS); |
| 367 parseAndShowNotificationCards(request.response, callback); | 412 parseAndShowNotificationCards(request.response, callback); |
| 368 } else { | 413 } else { |
| 369 callback(); | 414 callback(); |
| 370 } | 415 } |
| 416 }; |
| 417 |
| 418 setAuthorization(request, function(success) { |
| 419 if (success) { |
| 420 tasks.debugSetStepName('requestNotificationCards-send-request'); |
| 421 request.send(requestParameters); |
| 422 } else { |
| 423 callback(); |
| 424 } |
| 371 }); | 425 }); |
| 372 | |
| 373 tasks.debugSetStepName('requestNotificationCards-send-request'); | |
| 374 request.send(requestParameters); | |
| 375 } | 426 } |
| 376 | 427 |
| 377 /** | 428 /** |
| 378 * Starts getting location for a cards update. | 429 * Starts getting location for a cards update. |
| 379 */ | 430 */ |
| 380 function requestLocation() { | 431 function requestLocation() { |
| 381 console.log('requestLocation'); | 432 console.log('requestLocation'); |
| 382 recordEvent(DiagnosticEvent.LOCATION_REQUEST); | 433 recordEvent(DiagnosticEvent.LOCATION_REQUEST); |
| 383 // TODO(vadimt): Figure out location request options. | 434 // TODO(vadimt): Figure out location request options. |
| 384 chrome.location.watchLocation(LOCATION_WATCH_NAME, {}); | 435 chrome.location.watchLocation(LOCATION_WATCH_NAME, {}); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 */ | 469 */ |
| 419 function requestCardDismissal( | 470 function requestCardDismissal( |
| 420 notificationId, dismissalTimeMs, callbackBoolean) { | 471 notificationId, dismissalTimeMs, callbackBoolean) { |
| 421 console.log('requestDismissingCard ' + notificationId + ' from ' + | 472 console.log('requestDismissingCard ' + notificationId + ' from ' + |
| 422 NOTIFICATION_CARDS_URL); | 473 NOTIFICATION_CARDS_URL); |
| 423 recordEvent(DiagnosticEvent.DISMISS_REQUEST_TOTAL); | 474 recordEvent(DiagnosticEvent.DISMISS_REQUEST_TOTAL); |
| 424 // Send a dismiss request to the server. | 475 // Send a dismiss request to the server. |
| 425 var requestParameters = 'id=' + notificationId + | 476 var requestParameters = 'id=' + notificationId + |
| 426 '&dismissalAge=' + (Date.now() - dismissalTimeMs); | 477 '&dismissalAge=' + (Date.now() - dismissalTimeMs); |
| 427 var request = buildServerRequest('dismiss'); | 478 var request = buildServerRequest('dismiss'); |
| 428 request.onloadend = tasks.wrapCallback(function(event) { | 479 request.onloadend = function(event) { |
| 429 console.log('requestDismissingCard-onloadend ' + request.status); | 480 console.log('requestDismissingCard-onloadend ' + request.status); |
| 430 if (request.status == HTTP_OK) | 481 if (request.status == HTTP_OK) |
| 431 recordEvent(DiagnosticEvent.DISMISS_REQUEST_SUCCESS); | 482 recordEvent(DiagnosticEvent.DISMISS_REQUEST_SUCCESS); |
| 432 | 483 |
| 433 callbackBoolean(request.status == HTTP_OK); | 484 callbackBoolean(request.status == HTTP_OK); |
| 485 }; |
| 486 |
| 487 setAuthorization(request, function(success) { |
| 488 if (success) { |
| 489 tasks.debugSetStepName('requestCardDismissal-send-request'); |
| 490 request.send(requestParameters); |
| 491 } else { |
| 492 callbackBoolean(false); |
| 493 } |
| 434 }); | 494 }); |
| 435 | |
| 436 tasks.debugSetStepName('requestCardDismissal-send-request'); | |
| 437 request.send(requestParameters); | |
| 438 } | 495 } |
| 439 | 496 |
| 440 /** | 497 /** |
| 441 * Tries to send dismiss requests for all pending dismissals. | 498 * Tries to send dismiss requests for all pending dismissals. |
| 442 * @param {function(boolean)} callbackBoolean Completion callback with 'success' | 499 * @param {function(boolean)} callbackBoolean Completion callback with 'success' |
| 443 * parameter. Success means that no pending dismissals are left. | 500 * parameter. Success means that no pending dismissals are left. |
| 444 */ | 501 */ |
| 445 function processPendingDismissals(callbackBoolean) { | 502 function processPendingDismissals(callbackBoolean) { |
| 446 tasks.debugSetStepName('processPendingDismissals-storage-get'); | 503 tasks.debugSetStepName('processPendingDismissals-storage-get'); |
| 447 storage.get(['pendingDismissals', 'recentDismissals'], function(items) { | 504 storage.get(['pendingDismissals', 'recentDismissals'], function(items) { |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 | 749 |
| 693 chrome.location.onLocationUpdate.addListener(function(position) { | 750 chrome.location.onLocationUpdate.addListener(function(position) { |
| 694 recordEvent(DiagnosticEvent.LOCATION_UPDATE); | 751 recordEvent(DiagnosticEvent.LOCATION_UPDATE); |
| 695 updateNotificationsCards(position); | 752 updateNotificationsCards(position); |
| 696 }); | 753 }); |
| 697 | 754 |
| 698 chrome.omnibox.onInputEntered.addListener(function(text) { | 755 chrome.omnibox.onInputEntered.addListener(function(text) { |
| 699 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; | 756 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; |
| 700 initialize(); | 757 initialize(); |
| 701 }); | 758 }); |
| OLD | NEW |