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'; TODO(vadimt): Uncomment once crbug.com/237617 is fixed. | 5 // 'use strict'; TODO(vadimt): Uncomment once crbug.com/237617 is fixed. |
| 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 57 /** | 57 /** |
| 58 * Time we keep dismissals after successful server dismiss requests. | 58 * Time we keep dismissals after successful server dismiss requests. |
| 59 */ | 59 */ |
| 60 var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000; // 20 minutes | 60 var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000; // 20 minutes |
| 61 | 61 |
| 62 /** | 62 /** |
| 63 * Names for tasks that can be created by the extension. | 63 * Names for tasks that can be created by the extension. |
| 64 */ | 64 */ |
| 65 var UPDATE_CARDS_TASK_NAME = 'update-cards'; | 65 var UPDATE_CARDS_TASK_NAME = 'update-cards'; |
| 66 var DISMISS_CARD_TASK_NAME = 'dismiss-card'; | 66 var DISMISS_CARD_TASK_NAME = 'dismiss-card'; |
| 67 var CARD_CLICKED_TASK_NAME = 'card-clicked'; | |
| 68 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; | 67 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; |
| 69 | 68 |
| 70 var LOCATION_WATCH_NAME = 'location-watch'; | 69 var LOCATION_WATCH_NAME = 'location-watch'; |
| 71 | 70 |
| 72 /** | 71 /** |
| 73 * Checks if a new task can't be scheduled when another task is already | 72 * Checks if a new task can't be scheduled when another task is already |
| 74 * scheduled. | 73 * scheduled. |
| 75 * @param {string} newTaskName Name of the new task. | 74 * @param {string} newTaskName Name of the new task. |
| 76 * @param {string} scheduledTaskName Name of the scheduled task. | 75 * @param {string} scheduledTaskName Name of the scheduled task. |
| 77 * @return {boolean} Whether the new task conflicts with the existing task. | 76 * @return {boolean} Whether the new task conflicts with the existing task. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 95 | 94 |
| 96 return false; | 95 return false; |
| 97 } | 96 } |
| 98 | 97 |
| 99 var tasks = buildTaskManager(areTasksConflicting); | 98 var tasks = buildTaskManager(areTasksConflicting); |
| 100 | 99 |
| 101 // Add error processing to API calls. | 100 // Add error processing to API calls. |
| 102 tasks.instrumentApiFunction(chrome.location.onLocationUpdate, 'addListener', 0); | 101 tasks.instrumentApiFunction(chrome.location.onLocationUpdate, 'addListener', 0); |
| 103 tasks.instrumentApiFunction(chrome.notifications, 'create', 2); | 102 tasks.instrumentApiFunction(chrome.notifications, 'create', 2); |
| 104 tasks.instrumentApiFunction(chrome.notifications, 'update', 2); | 103 tasks.instrumentApiFunction(chrome.notifications, 'update', 2); |
| 104 tasks.instrumentApiFunction(chrome.notifications, 'getAll', 0); | |
| 105 tasks.instrumentApiFunction( | 105 tasks.instrumentApiFunction( |
| 106 chrome.notifications.onButtonClicked, 'addListener', 0); | 106 chrome.notifications.onButtonClicked, 'addListener', 0); |
| 107 tasks.instrumentApiFunction(chrome.notifications.onClicked, 'addListener', 0); | 107 tasks.instrumentApiFunction(chrome.notifications.onClicked, 'addListener', 0); |
| 108 tasks.instrumentApiFunction(chrome.notifications.onClosed, 'addListener', 0); | 108 tasks.instrumentApiFunction(chrome.notifications.onClosed, 'addListener', 0); |
| 109 tasks.instrumentApiFunction(chrome.runtime.onInstalled, 'addListener', 0); | 109 tasks.instrumentApiFunction(chrome.runtime.onInstalled, 'addListener', 0); |
| 110 tasks.instrumentApiFunction(chrome.runtime.onStartup, 'addListener', 0); | 110 tasks.instrumentApiFunction(chrome.runtime.onStartup, 'addListener', 0); |
| 111 tasks.instrumentApiFunction(chrome.tabs, 'create', 1); | 111 tasks.instrumentApiFunction(chrome.tabs, 'create', 1); |
| 112 tasks.instrumentApiFunction(storage, 'get', 1); | 112 tasks.instrumentApiFunction(storage, 'get', 1); |
| 113 | 113 |
| 114 var updateCardsAttempts = buildAttemptManager( | 114 var updateCardsAttempts = buildAttemptManager( |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 153 | 153 |
| 154 chrome.metricsPrivate.recordValue(metricDescription, event); | 154 chrome.metricsPrivate.recordValue(metricDescription, event); |
| 155 } | 155 } |
| 156 | 156 |
| 157 /** | 157 /** |
| 158 * Shows a notification and remembers information associated with it. | 158 * Shows a notification and remembers information associated with it. |
| 159 * @param {Object} card Google Now card represented as a set of parameters for | 159 * @param {Object} card Google Now card represented as a set of parameters for |
| 160 * showing a Chrome notification. | 160 * showing a Chrome notification. |
| 161 * @param {Object} notificationsData Map from notification id to the data | 161 * @param {Object} notificationsData Map from notification id to the data |
| 162 * associated with a notification. | 162 * associated with a notification. |
| 163 * @param {number} previousVersion The version of the shown card with this id, | 163 * @param {number=} opt_previousVersion The version of the shown card with this |
| 164 * if it exists, undefined otherwise. | 164 * id, if it exists, undefined otherwise. |
| 165 */ | 165 */ |
| 166 function showNotification(card, notificationsData, previousVersion) { | 166 function showNotification(card, notificationsData, opt_previousVersion) { |
| 167 console.log('showNotification ' + JSON.stringify(card) + ' ' + | 167 console.log('showNotification ' + JSON.stringify(card) + ' ' + |
| 168 previousVersion); | 168 opt_previousVersion); |
| 169 | 169 |
| 170 if (typeof card.version != 'number') { | 170 if (typeof card.version != 'number') { |
| 171 console.error('card.version is not a number'); | 171 console.error('card.version is not a number'); |
| 172 // Fix card version. | 172 // Fix card version. |
| 173 card.version = previousVersion !== undefined ? previousVersion : 0; | 173 card.version = opt_previousVersion !== undefined ? opt_previousVersion : 0; |
| 174 } | 174 } |
| 175 | 175 |
| 176 if (previousVersion !== card.version) { | 176 if (opt_previousVersion !== card.version) { |
| 177 try { | 177 try { |
| 178 // Delete a notification with the specified id if it already exists, and | 178 // Delete a notification with the specified id if it already exists, and |
| 179 // then create a notification. | 179 // then create a notification. |
| 180 chrome.notifications.create( | 180 chrome.notifications.create( |
| 181 card.notificationId, | 181 card.notificationId, |
| 182 card.notification, | 182 card.notification, |
| 183 function(notificationId) { | 183 function(notificationId) { |
| 184 if (!notificationId || chrome.runtime.lastError) { | 184 if (!notificationId || chrome.runtime.lastError) { |
| 185 var errorMessage = | 185 var errorMessage = |
| 186 chrome.runtime.lastError && chrome.runtime.lastError.message; | 186 chrome.runtime.lastError && chrome.runtime.lastError.message; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 callback(); | 238 callback(); |
| 239 return; | 239 return; |
| 240 } | 240 } |
| 241 | 241 |
| 242 if (typeof parsedResponse.expiration_timestamp_seconds != 'number') { | 242 if (typeof parsedResponse.expiration_timestamp_seconds != 'number') { |
| 243 callback(); | 243 callback(); |
| 244 return; | 244 return; |
| 245 } | 245 } |
| 246 | 246 |
| 247 tasks.debugSetStepName('parseAndShowNotificationCards-storage-get'); | 247 tasks.debugSetStepName('parseAndShowNotificationCards-storage-get'); |
| 248 storage.get(['activeNotifications', 'recentDismissals'], function(items) { | 248 storage.get(['notificationsData', 'recentDismissals'], function(items) { |
| 249 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items)); | 249 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items)); |
| 250 items.activeNotifications = items.activeNotifications || {}; | 250 items.notificationsData = items.notificationsData || {}; |
|
rgustafson
2013/05/31 19:07:25
btw, did you see the suggestion on an already subm
vadimt
2013/05/31 19:24:05
I didn't want to complicate this CR with unrelated
rgustafson
2013/05/31 20:48:12
Okay, making sure you didn't miss it cause it's a
| |
| 251 items.recentDismissals = items.recentDismissals || {}; | 251 items.recentDismissals = items.recentDismissals || {}; |
| 252 | 252 |
| 253 // Build a set of non-expired recent dismissals. It will be used for | 253 tasks.debugSetStepName( |
| 254 // client-side filtering of cards. | 254 'parseAndShowNotificationCards-notifications-getAll'); |
| 255 var updatedRecentDismissals = {}; | 255 chrome.notifications.getAll(function(notifications) { |
| 256 var currentTimeMs = Date.now(); | 256 console.log('parseAndShowNotificationCards-getAll ' + |
| 257 for (var notificationId in items.recentDismissals) { | 257 JSON.stringify(notifications)); |
| 258 if (currentTimeMs - items.recentDismissals[notificationId] < | 258 // Build a set of non-expired recent dismissals. It will be used for |
| 259 DISMISS_RETENTION_TIME_MS) { | 259 // client-side filtering of cards. |
| 260 updatedRecentDismissals[notificationId] = | 260 var updatedRecentDismissals = {}; |
| 261 items.recentDismissals[notificationId]; | 261 var currentTimeMs = Date.now(); |
| 262 for (var notificationId in items.recentDismissals) { | |
| 263 if (currentTimeMs - items.recentDismissals[notificationId] < | |
| 264 DISMISS_RETENTION_TIME_MS) { | |
| 265 updatedRecentDismissals[notificationId] = | |
| 266 items.recentDismissals[notificationId]; | |
| 267 } | |
| 262 } | 268 } |
| 263 } | |
| 264 | 269 |
| 265 // Mark existing notifications that received an update in this server | 270 // Mark existing notifications that received an update in this server |
| 266 // response. | 271 // response. |
| 267 for (var i = 0; i < cards.length; ++i) { | 272 var updatedNotifications = {}; |
| 268 var notificationId = cards[i].notificationId; | 273 |
| 269 if (!(notificationId in updatedRecentDismissals) && | 274 for (var i = 0; i < cards.length; ++i) { |
| 270 notificationId in items.activeNotifications) { | 275 var notificationId = cards[i].notificationId; |
| 271 items.activeNotifications[notificationId].hasUpdate = true; | 276 if (!(notificationId in updatedRecentDismissals) && |
| 277 notificationId in notifications) { | |
| 278 updatedNotifications[notificationId] = true; | |
| 279 } | |
| 272 } | 280 } |
| 273 } | |
| 274 | 281 |
| 275 // Delete notifications that didn't receive an update. | 282 // Delete notifications that didn't receive an update. |
| 276 for (var notificationId in items.activeNotifications) { | 283 for (var notificationId in notifications) { |
| 277 console.log('parseAndShowNotificationCards-delete-check ' + | 284 console.log('parseAndShowNotificationCards-delete-check ' + |
| 278 notificationId); | 285 notificationId); |
| 279 if (!items.activeNotifications[notificationId].hasUpdate) { | 286 if (!(notificationId in updatedNotifications)) { |
| 280 console.log('parseAndShowNotificationCards-delete ' + notificationId); | 287 console.log('parseAndShowNotificationCards-delete ' + notificationId); |
| 281 chrome.notifications.clear( | 288 chrome.notifications.clear( |
| 282 notificationId, | 289 notificationId, |
| 283 function() {}); | 290 function() {}); |
| 291 } | |
| 284 } | 292 } |
| 285 } | |
| 286 | 293 |
| 287 recordEvent(DiagnosticEvent.CARDS_PARSE_SUCCESS); | 294 recordEvent(DiagnosticEvent.CARDS_PARSE_SUCCESS); |
| 288 | 295 |
| 289 // Create/update notifications and store their new properties. | 296 // Create/update notifications and store their new properties. |
| 290 var notificationsData = {}; | 297 var newNotificationsData = {}; |
| 291 for (var i = 0; i < cards.length; ++i) { | 298 for (var i = 0; i < cards.length; ++i) { |
| 292 var card = cards[i]; | 299 var card = cards[i]; |
| 293 if (!(card.notificationId in updatedRecentDismissals)) { | 300 if (!(card.notificationId in updatedRecentDismissals)) { |
| 294 var activeNotification = items.activeNotifications[card.notificationId]; | 301 var notificationData = items.notificationsData[card.notificationId]; |
| 295 showNotification(card, | 302 var version = notifications[card.notificationId] && |
|
rgustafson
2013/05/31 01:05:36
previousVersion to make this more clear
vadimt
2013/05/31 01:39:44
Done.
| |
| 296 notificationsData, | 303 notificationData && |
| 297 activeNotification && activeNotification.version); | 304 notificationData.version; |
|
skare_
2013/05/30 23:24:33
do you want this to be 0 or undefined otherwise? w
vadimt
2013/05/31 00:45:34
I don't want it to be 0 if first 2 conditions are
| |
| 305 showNotification(card, newNotificationsData, version); | |
| 306 } | |
| 298 } | 307 } |
| 299 } | |
| 300 | 308 |
| 301 updateCardsAttempts.start(parsedResponse.expiration_timestamp_seconds); | 309 updateCardsAttempts.start(parsedResponse.expiration_timestamp_seconds); |
| 302 | 310 |
| 303 storage.set({ | 311 storage.set({ |
| 304 activeNotifications: notificationsData, | 312 notificationsData: newNotificationsData, |
| 305 recentDismissals: updatedRecentDismissals | 313 recentDismissals: updatedRecentDismissals |
| 314 }); | |
| 315 callback(); | |
| 306 }); | 316 }); |
| 307 callback(); | |
| 308 }); | 317 }); |
| 309 } | 318 } |
| 310 | 319 |
| 311 /** | 320 /** |
| 312 * Requests notification cards from the server. | 321 * Requests notification cards from the server. |
| 313 * @param {Location} position Location of this computer. | 322 * @param {Location} position Location of this computer. |
| 314 * @param {function()} callback Completion callback. | 323 * @param {function()} callback Completion callback. |
| 315 */ | 324 */ |
| 316 function requestNotificationCards(position, callback) { | 325 function requestNotificationCards(position, callback) { |
| 317 console.log('requestNotificationCards ' + JSON.stringify(position) + | 326 console.log('requestNotificationCards ' + JSON.stringify(position) + |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 473 }); | 482 }); |
| 474 } | 483 } |
| 475 | 484 |
| 476 /** | 485 /** |
| 477 * Opens URL corresponding to the clicked part of the notification. | 486 * Opens URL corresponding to the clicked part of the notification. |
| 478 * @param {string} notificationId Unique identifier of the notification. | 487 * @param {string} notificationId Unique identifier of the notification. |
| 479 * @param {function(Object): string} selector Function that extracts the url for | 488 * @param {function(Object): string} selector Function that extracts the url for |
| 480 * the clicked area from the button action URLs info. | 489 * the clicked area from the button action URLs info. |
| 481 */ | 490 */ |
| 482 function onNotificationClicked(notificationId, selector) { | 491 function onNotificationClicked(notificationId, selector) { |
| 483 tasks.add(CARD_CLICKED_TASK_NAME, function(callback) { | 492 storage.get('notificationsData', function(items) { |
| 484 tasks.debugSetStepName('onNotificationClicked-get-activeNotifications'); | 493 items.notificationsData = items.notificationsData || {}; |
| 485 storage.get('activeNotifications', function(items) { | |
| 486 items.activeNotifications = items.activeNotifications || {}; | |
| 487 | 494 |
| 488 var actionUrls = items.activeNotifications[notificationId].actionUrls; | 495 var notificationData = items.notificationsData[notificationId]; |
| 489 if (typeof actionUrls != 'object') { | |
| 490 callback(); | |
| 491 return; | |
| 492 } | |
| 493 | 496 |
| 494 var url = selector(actionUrls); | 497 if (!notificationData) { |
|
rgustafson
2013/05/31 01:05:36
Even though this wasn't really added in this CL, c
vadimt
2013/05/31 01:39:44
We could imagine retaining deleted notifications'
rgustafson
2013/05/31 19:07:25
I have to agree that adding the complexity for ret
vadimt
2013/05/31 19:24:05
Thanks for the note anyways!
| |
| 498 // 'notificationsData' in storage may not match the actual list of | |
| 499 // notifications. | |
| 500 return; | |
| 501 } | |
| 495 | 502 |
| 496 if (typeof url != 'string') { | 503 var actionUrls = notificationData.actionUrls; |
| 497 callback(); | 504 if (typeof actionUrls != 'object') { |
| 498 return; | 505 return; |
| 499 } | 506 } |
| 500 | 507 |
| 501 chrome.tabs.create({url: url}, function(tab) { | 508 var url = selector(actionUrls); |
| 502 if (!tab) | 509 |
| 503 chrome.windows.create({url: url}); | 510 if (typeof url != 'string') { |
| 504 }); | 511 return; |
|
skare_
2013/05/30 23:24:33
(from prior CL) -- this seems to be guaranteed to
vadimt
2013/05/31 00:45:34
This is the data that we've received from the serv
| |
| 505 callback(); | 512 } |
| 513 | |
| 514 chrome.tabs.create({url: url}, function(tab) { | |
| 515 if (!tab) | |
| 516 chrome.windows.create({url: url}); | |
| 506 }); | 517 }); |
| 507 }); | 518 }); |
| 508 } | 519 } |
| 509 | 520 |
| 510 /** | 521 /** |
| 511 * Callback for chrome.notifications.onClosed event. | 522 * Callback for chrome.notifications.onClosed event. |
| 512 * @param {string} notificationId Unique identifier of the notification. | 523 * @param {string} notificationId Unique identifier of the notification. |
| 513 * @param {boolean} byUser Whether the notification was closed by the user. | 524 * @param {boolean} byUser Whether the notification was closed by the user. |
| 514 */ | 525 */ |
| 515 function onNotificationClosed(notificationId, byUser) { | 526 function onNotificationClosed(notificationId, byUser) { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 543 } | 554 } |
| 544 | 555 |
| 545 /** | 556 /** |
| 546 * Initializes the event page on install or on browser startup. | 557 * Initializes the event page on install or on browser startup. |
| 547 */ | 558 */ |
| 548 function initialize() { | 559 function initialize() { |
| 549 // Create an update timer for a case when for some reason location request | 560 // Create an update timer for a case when for some reason location request |
| 550 // gets stuck. | 561 // gets stuck. |
| 551 updateCardsAttempts.start(MAXIMUM_POLLING_PERIOD_SECONDS); | 562 updateCardsAttempts.start(MAXIMUM_POLLING_PERIOD_SECONDS); |
| 552 | 563 |
| 553 var initialStorage = { | |
| 554 activeNotifications: {} | |
| 555 }; | |
| 556 storage.set(initialStorage); | |
| 557 | |
| 558 requestLocation(); | 564 requestLocation(); |
| 559 } | 565 } |
| 560 | 566 |
| 561 chrome.runtime.onInstalled.addListener(function(details) { | 567 chrome.runtime.onInstalled.addListener(function(details) { |
| 562 console.log('onInstalled ' + JSON.stringify(details)); | 568 console.log('onInstalled ' + JSON.stringify(details)); |
| 563 if (details.reason != 'chrome_update') { | 569 if (details.reason != 'chrome_update') { |
| 564 initialize(); | 570 initialize(); |
| 565 } | 571 } |
| 566 }); | 572 }); |
| 567 | 573 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 594 | 600 |
| 595 chrome.location.onLocationUpdate.addListener(function(position) { | 601 chrome.location.onLocationUpdate.addListener(function(position) { |
| 596 recordEvent(DiagnosticEvent.LOCATION_UPDATE); | 602 recordEvent(DiagnosticEvent.LOCATION_UPDATE); |
| 597 updateNotificationsCards(position); | 603 updateNotificationsCards(position); |
| 598 }); | 604 }); |
| 599 | 605 |
| 600 chrome.omnibox.onInputEntered.addListener(function(text) { | 606 chrome.omnibox.onInputEntered.addListener(function(text) { |
| 601 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; | 607 localStorage['server_url'] = NOTIFICATION_CARDS_URL = text; |
| 602 initialize(); | 608 initialize(); |
| 603 }); | 609 }); |
| OLD | NEW |