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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 // send dismissals is scheduled. | 108 // send dismissals is scheduled. |
| 109 return true; | 109 return true; |
| 110 } | 110 } |
| 111 | 111 |
| 112 return false; | 112 return false; |
| 113 } | 113 } |
| 114 | 114 |
| 115 var tasks = buildTaskManager(areTasksConflicting); | 115 var tasks = buildTaskManager(areTasksConflicting); |
| 116 | 116 |
| 117 // Add error processing to API calls. | 117 // Add error processing to API calls. |
| 118 tasks.instrumentApiFunction(chrome.alarms, 'getAll', 0); | |
|
rgustafson
2013/07/19 23:37:12
Where is alarms.getAll used?
vadimt
2013/07/22 19:22:52
Done.
| |
| 118 tasks.instrumentApiFunction(chrome.identity, 'getAuthToken', 1); | 119 tasks.instrumentApiFunction(chrome.identity, 'getAuthToken', 1); |
| 119 tasks.instrumentApiFunction(chrome.identity, 'removeCachedAuthToken', 1); | 120 tasks.instrumentApiFunction(chrome.identity, 'removeCachedAuthToken', 1); |
| 120 tasks.instrumentApiFunction(chrome.location.onLocationUpdate, 'addListener', 0); | 121 tasks.instrumentApiFunction(chrome.location.onLocationUpdate, 'addListener', 0); |
| 121 tasks.instrumentApiFunction(chrome.notifications, 'create', 2); | 122 tasks.instrumentApiFunction(chrome.notifications, 'create', 2); |
| 122 tasks.instrumentApiFunction(chrome.notifications, 'update', 2); | 123 tasks.instrumentApiFunction(chrome.notifications, 'update', 2); |
| 123 tasks.instrumentApiFunction(chrome.notifications, 'getAll', 0); | 124 tasks.instrumentApiFunction(chrome.notifications, 'getAll', 0); |
| 124 tasks.instrumentApiFunction( | 125 tasks.instrumentApiFunction( |
| 125 chrome.notifications.onButtonClicked, 'addListener', 0); | 126 chrome.notifications.onButtonClicked, 'addListener', 0); |
| 126 tasks.instrumentApiFunction(chrome.notifications.onClicked, 'addListener', 0); | 127 tasks.instrumentApiFunction(chrome.notifications.onClicked, 'addListener', 0); |
| 127 tasks.instrumentApiFunction(chrome.notifications.onClosed, 'addListener', 0); | 128 tasks.instrumentApiFunction(chrome.notifications.onClosed, 'addListener', 0); |
| 128 tasks.instrumentApiFunction(chrome.runtime.onInstalled, 'addListener', 0); | 129 tasks.instrumentApiFunction(chrome.runtime.onInstalled, 'addListener', 0); |
| 129 tasks.instrumentApiFunction(chrome.runtime.onStartup, 'addListener', 0); | 130 tasks.instrumentApiFunction(chrome.runtime.onStartup, 'addListener', 0); |
| 130 tasks.instrumentApiFunction(chrome.tabs, 'create', 1); | 131 tasks.instrumentApiFunction(chrome.tabs, 'create', 1); |
| 131 tasks.instrumentApiFunction(storage, 'get', 1); | 132 tasks.instrumentApiFunction(storage, 'get', 1); |
| 132 | 133 |
| 133 var updateCardsAttempts = buildAttemptManager( | 134 var updateCardsAttempts = buildAttemptManager( |
| 134 'cards-update', | 135 'cards-update', |
| 135 requestLocation, | 136 requestLocation, |
| 136 INITIAL_POLLING_PERIOD_SECONDS, | 137 INITIAL_POLLING_PERIOD_SECONDS, |
| 137 MAXIMUM_POLLING_PERIOD_SECONDS); | 138 MAXIMUM_POLLING_PERIOD_SECONDS); |
| 138 var dismissalAttempts = buildAttemptManager( | 139 var dismissalAttempts = buildAttemptManager( |
| 139 'dismiss', | 140 'dismiss', |
| 140 retryPendingDismissals, | 141 retryPendingDismissals, |
| 141 INITIAL_RETRY_DISMISS_PERIOD_SECONDS, | 142 INITIAL_RETRY_DISMISS_PERIOD_SECONDS, |
| 142 MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS); | 143 MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS); |
| 144 var cardSet = buildCardManager(); | |
| 143 | 145 |
| 144 /** | 146 /** |
| 145 * Diagnostic event identifier. | 147 * Diagnostic event identifier. |
| 146 * @enum {number} | 148 * @enum {number} |
| 147 */ | 149 */ |
| 148 var DiagnosticEvent = { | 150 var DiagnosticEvent = { |
| 149 REQUEST_FOR_CARDS_TOTAL: 0, | 151 REQUEST_FOR_CARDS_TOTAL: 0, |
| 150 REQUEST_FOR_CARDS_SUCCESS: 1, | 152 REQUEST_FOR_CARDS_SUCCESS: 1, |
| 151 CARDS_PARSE_SUCCESS: 2, | 153 CARDS_PARSE_SUCCESS: 2, |
| 152 DISMISS_REQUEST_TOTAL: 3, | 154 DISMISS_REQUEST_TOTAL: 3, |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 210 } else { | 212 } else { |
| 211 originalOnLoadEnd(event); | 213 originalOnLoadEnd(event); |
| 212 } | 214 } |
| 213 }); | 215 }); |
| 214 | 216 |
| 215 callbackBoolean(true); | 217 callbackBoolean(true); |
| 216 }); | 218 }); |
| 217 } | 219 } |
| 218 | 220 |
| 219 /** | 221 /** |
| 220 * Shows a notification and remembers information associated with it. | |
| 221 * @param {Object} card Google Now card represented as a set of parameters for | |
| 222 * showing a Chrome notification. | |
| 223 * @param {Object} notificationsData Map from notification id to the data | |
| 224 * associated with a notification. | |
| 225 * @param {number=} opt_previousVersion The version of the shown card with this | |
| 226 * id, if it exists, undefined otherwise. | |
| 227 */ | |
| 228 function showNotification(card, notificationsData, opt_previousVersion) { | |
| 229 console.log('showNotification ' + JSON.stringify(card) + ' ' + | |
| 230 opt_previousVersion); | |
| 231 | |
| 232 if (typeof card.version != 'number') { | |
| 233 console.error('card.version is not a number'); | |
| 234 // Fix card version. | |
| 235 card.version = opt_previousVersion !== undefined ? opt_previousVersion : 0; | |
| 236 } | |
| 237 | |
| 238 if (opt_previousVersion !== card.version) { | |
| 239 try { | |
| 240 // Delete a notification with the specified id if it already exists, and | |
| 241 // then create a notification. | |
| 242 chrome.notifications.create( | |
| 243 card.notificationId, | |
| 244 card.notification, | |
| 245 function(notificationId) { | |
| 246 if (!notificationId || chrome.runtime.lastError) { | |
| 247 var errorMessage = | |
| 248 chrome.runtime.lastError && chrome.runtime.lastError.message; | |
| 249 console.error('notifications.create: ID=' + notificationId + | |
| 250 ', ERROR=' + errorMessage); | |
| 251 } | |
| 252 }); | |
| 253 } catch (error) { | |
| 254 console.error('Error in notifications.create: ' + error); | |
| 255 } | |
| 256 } else { | |
| 257 try { | |
| 258 // Update existing notification. | |
| 259 chrome.notifications.update( | |
| 260 card.notificationId, | |
| 261 card.notification, | |
| 262 function(wasUpdated) { | |
| 263 if (!wasUpdated || chrome.runtime.lastError) { | |
| 264 var errorMessage = | |
| 265 chrome.runtime.lastError && chrome.runtime.lastError.message; | |
| 266 console.error('notifications.update: UPDATED=' + wasUpdated + | |
| 267 ', ERROR=' + errorMessage); | |
| 268 } | |
| 269 }); | |
| 270 } catch (error) { | |
| 271 console.error('Error in notifications.update: ' + error); | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 notificationsData[card.notificationId] = { | |
| 276 actionUrls: card.actionUrls, | |
| 277 version: card.version | |
| 278 }; | |
| 279 } | |
| 280 | |
| 281 /** | |
| 282 * Parses JSON response from the notification server, show notifications and | 222 * Parses JSON response from the notification server, show notifications and |
| 283 * schedule next update. | 223 * schedule next update. |
| 284 * @param {string} response Server response. | 224 * @param {string} response Server response. |
| 285 * @param {function()} callback Completion callback. | 225 * @param {function()} callback Completion callback. |
| 286 */ | 226 */ |
| 287 function parseAndShowNotificationCards(response, callback) { | 227 function parseAndShowNotificationCards(response, callback) { |
| 288 console.log('parseAndShowNotificationCards ' + response); | 228 console.log('parseAndShowNotificationCards ' + response); |
| 289 try { | 229 try { |
| 290 var parsedResponse = JSON.parse(response); | 230 var parsedResponse = JSON.parse(response); |
| 291 } catch (error) { | 231 } catch (error) { |
| 292 console.error('parseAndShowNotificationCards parse error: ' + error); | 232 console.error('parseAndShowNotificationCards parse error: ' + error); |
| 293 callback(); | 233 callback(); |
| 294 return; | 234 return; |
| 295 } | 235 } |
| 296 | 236 |
| 297 var cards = parsedResponse.cards; | 237 var cards = parsedResponse.cards; |
| 298 | 238 |
| 299 if (!(cards instanceof Array)) { | 239 if (!(cards instanceof Array)) { |
| 300 callback(); | 240 callback(); |
| 301 return; | 241 return; |
| 302 } | 242 } |
| 303 | 243 |
| 304 if (typeof parsedResponse.expiration_timestamp_seconds != 'number') { | 244 if (typeof parsedResponse.expiration_timestamp_seconds != 'number') { |
|
rgustafson
2013/07/22 17:48:07
Can we change expiration_timestamp_seconds to next
vadimt
2013/07/22 19:22:52
Done.
| |
| 305 callback(); | 245 callback(); |
| 306 return; | 246 return; |
| 307 } | 247 } |
| 308 | 248 |
| 309 tasks.debugSetStepName('parseAndShowNotificationCards-storage-get'); | 249 tasks.debugSetStepName('parseAndShowNotificationCards-storage-get'); |
| 310 storage.get(['notificationsData', 'recentDismissals'], function(items) { | 250 storage.get(['notificationsData', 'recentDismissals'], function(items) { |
| 311 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items)); | 251 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items)); |
| 312 items.notificationsData = items.notificationsData || {}; | 252 items.notificationsData = items.notificationsData || {}; |
| 313 items.recentDismissals = items.recentDismissals || {}; | 253 items.recentDismissals = items.recentDismissals || {}; |
| 314 | 254 |
| 315 tasks.debugSetStepName( | 255 tasks.debugSetStepName( |
| 316 'parseAndShowNotificationCards-notifications-getAll'); | 256 'parseAndShowNotificationCards-notifications-getAll'); |
| 317 chrome.notifications.getAll(function(notifications) { | 257 chrome.notifications.getAll(function(notifications) { |
| 318 console.log('parseAndShowNotificationCards-getAll ' + | 258 console.log('parseAndShowNotificationCards-getAll ' + |
| 319 JSON.stringify(notifications)); | 259 JSON.stringify(notifications)); |
| 320 // TODO(vadimt): Figure out what to do when notifications are disabled for | 260 // TODO(vadimt): Figure out what to do when notifications are disabled for |
|
rgustafson
2013/07/19 23:37:12
Why was this un-tabbed? It should be on the level
vadimt
2013/07/22 19:22:52
Done. I probably need to see my doctor.
| |
| 321 // our extension. | 261 // our extension. |
| 322 notifications = notifications || {}; | 262 notifications = notifications || {}; |
| 323 | 263 |
| 324 // Build a set of non-expired recent dismissals. It will be used for | 264 // Build a set of non-expired recent dismissals. It will be used for |
| 325 // client-side filtering of cards. | 265 // client-side filtering of cards. |
| 326 var updatedRecentDismissals = {}; | 266 var updatedRecentDismissals = {}; |
| 327 var currentTimeMs = Date.now(); | 267 var currentTimeMs = Date.now(); |
| 328 for (var notificationId in items.recentDismissals) { | 268 for (var notificationId in items.recentDismissals) { |
| 329 if (currentTimeMs - items.recentDismissals[notificationId] < | 269 if (currentTimeMs - items.recentDismissals[notificationId] < |
| 330 DISMISS_RETENTION_TIME_MS) { | 270 DISMISS_RETENTION_TIME_MS) { |
| 331 updatedRecentDismissals[notificationId] = | 271 updatedRecentDismissals[notificationId] = |
| 332 items.recentDismissals[notificationId]; | 272 items.recentDismissals[notificationId]; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 344 updatedNotifications[notificationId] = true; | 284 updatedNotifications[notificationId] = true; |
| 345 } | 285 } |
| 346 } | 286 } |
| 347 | 287 |
| 348 // Delete notifications that didn't receive an update. | 288 // Delete notifications that didn't receive an update. |
| 349 for (var notificationId in notifications) { | 289 for (var notificationId in notifications) { |
| 350 console.log('parseAndShowNotificationCards-delete-check ' + | 290 console.log('parseAndShowNotificationCards-delete-check ' + |
| 351 notificationId); | 291 notificationId); |
| 352 if (!(notificationId in updatedNotifications)) { | 292 if (!(notificationId in updatedNotifications)) { |
| 353 console.log('parseAndShowNotificationCards-delete ' + notificationId); | 293 console.log('parseAndShowNotificationCards-delete ' + notificationId); |
| 354 chrome.notifications.clear( | 294 cardSet.clear(notificationId); |
| 355 notificationId, | |
| 356 function() {}); | |
| 357 } | 295 } |
| 358 } | 296 } |
| 359 | 297 |
| 360 recordEvent(DiagnosticEvent.CARDS_PARSE_SUCCESS); | 298 recordEvent(DiagnosticEvent.CARDS_PARSE_SUCCESS); |
| 361 | 299 |
| 362 // Create/update notifications and store their new properties. | 300 // Create/update notifications and store their new properties. |
| 363 var newNotificationsData = {}; | 301 var newNotificationsData = {}; |
| 364 for (var i = 0; i < cards.length; ++i) { | 302 for (var i = 0; i < cards.length; ++i) { |
| 365 var card = cards[i]; | 303 var card = cards[i]; |
| 366 if (!(card.notificationId in updatedRecentDismissals)) { | 304 if (!(card.notificationId in updatedRecentDismissals)) { |
| 367 var notificationData = items.notificationsData[card.notificationId]; | 305 var notificationData = items.notificationsData[card.notificationId]; |
| 368 var previousVersion = notifications[card.notificationId] && | 306 var previousVersion = notifications[card.notificationId] && |
| 369 notificationData && | 307 notificationData && |
| 370 notificationData.previousVersion; | 308 notificationData.cardCreateInfo && |
| 371 showNotification(card, newNotificationsData, previousVersion); | 309 notificationData.cardCreateInfo.version; |
| 310 newNotificationsData[card.notificationId] = | |
| 311 cardSet.update(card, previousVersion); | |
| 372 } | 312 } |
| 373 } | 313 } |
| 374 | 314 |
| 375 updateCardsAttempts.start(parsedResponse.expiration_timestamp_seconds); | 315 updateCardsAttempts.start(parsedResponse.expiration_timestamp_seconds); |
|
rgustafson
2013/07/22 17:48:07
expiration_timestamp_seconds to next_poll_seconds
vadimt
2013/07/22 19:22:52
Done.
| |
| 376 | 316 |
| 377 storage.set({ | 317 storage.set({ |
| 378 notificationsData: newNotificationsData, | 318 notificationsData: newNotificationsData, |
| 379 recentDismissals: updatedRecentDismissals | 319 recentDismissals: updatedRecentDismissals |
| 380 }); | 320 }); |
| 381 callback(); | 321 callback(); |
| 382 }); | 322 }); |
| 383 }); | 323 }); |
| 384 } | 324 } |
| 385 | 325 |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 634 } | 574 } |
| 635 | 575 |
| 636 // At this point we are guaranteed that the notification is a now card. | 576 // At this point we are guaranteed that the notification is a now card. |
| 637 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); | 577 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); |
| 638 | 578 |
| 639 tasks.add(DISMISS_CARD_TASK_NAME, function(callback) { | 579 tasks.add(DISMISS_CARD_TASK_NAME, function(callback) { |
| 640 dismissalAttempts.start(); | 580 dismissalAttempts.start(); |
| 641 | 581 |
| 642 // Deleting the notification in case it was re-added while this task was | 582 // Deleting the notification in case it was re-added while this task was |
| 643 // scheduled, waiting for execution. | 583 // scheduled, waiting for execution. |
| 644 chrome.notifications.clear( | 584 cardSet.clear(notificationId); |
| 645 notificationId, | |
| 646 function() {}); | |
| 647 | 585 |
| 648 tasks.debugSetStepName('onNotificationClosed-get-pendingDismissals'); | 586 tasks.debugSetStepName('onNotificationClosed-get-pendingDismissals'); |
| 649 storage.get('pendingDismissals', function(items) { | 587 storage.get('pendingDismissals', function(items) { |
| 650 items.pendingDismissals = items.pendingDismissals || []; | 588 items.pendingDismissals = items.pendingDismissals || []; |
| 651 | 589 |
| 652 var dismissal = { | 590 var dismissal = { |
| 653 notificationId: notificationId, | 591 notificationId: notificationId, |
| 654 time: Date.now() | 592 time: Date.now() |
| 655 }; | 593 }; |
| 656 items.pendingDismissals.push(dismissal); | 594 items.pendingDismissals.push(dismissal); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 758 | 696 |
| 759 chrome.location.onLocationUpdate.addListener(function(position) { | 697 chrome.location.onLocationUpdate.addListener(function(position) { |
| 760 recordEvent(DiagnosticEvent.LOCATION_UPDATE); | 698 recordEvent(DiagnosticEvent.LOCATION_UPDATE); |
| 761 updateNotificationsCards(position); | 699 updateNotificationsCards(position); |
| 762 }); | 700 }); |
| 763 | 701 |
| 764 chrome.omnibox.onInputEntered.addListener(function(text) { | 702 chrome.omnibox.onInputEntered.addListener(function(text) { |
| 765 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; | 703 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; |
| 766 initialize(); | 704 initialize(); |
| 767 }); | 705 }); |
| OLD | NEW |