Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(322)

Side by Side Diff: chrome/browser/resources/google_now/background.js

Issue 107033002: Combining cards instead of merging (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More rgustafson's notes Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/browser/resources/google_now/background_unittest.gtestjs » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 var UPDATE_CARDS_TASK_NAME = 'update-cards'; 95 var UPDATE_CARDS_TASK_NAME = 'update-cards';
96 var DISMISS_CARD_TASK_NAME = 'dismiss-card'; 96 var DISMISS_CARD_TASK_NAME = 'dismiss-card';
97 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; 97 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss';
98 var STATE_CHANGED_TASK_NAME = 'state-changed'; 98 var STATE_CHANGED_TASK_NAME = 'state-changed';
99 var SHOW_ON_START_TASK_NAME = 'show-cards-on-start'; 99 var SHOW_ON_START_TASK_NAME = 'show-cards-on-start';
100 var ON_PUSH_MESSAGE_START_TASK_NAME = 'on-push-message'; 100 var ON_PUSH_MESSAGE_START_TASK_NAME = 'on-push-message';
101 101
102 var LOCATION_WATCH_NAME = 'location-watch'; 102 var LOCATION_WATCH_NAME = 'location-watch';
103 103
104 /** 104 /**
105 * Notification as it's sent by the server. 105 * Group as received from the server.
106 * 106 *
107 * @typedef {{ 107 * @typedef {{
108 * notificationId: string, 108 * nextPollSeconds: (string|undefined),
109 * chromeNotificationId: string, 109 * rank: (number|undefined),
110 * trigger: Object=, 110 * requested: (boolean|undefined)
111 * version: number,
112 * chromeNotificationOptions: Object,
113 * actionUrls: Object=,
114 * dismissal: Object
115 * }} 111 * }}
116 */ 112 */
117 var UnmergedNotification; 113 var ReceivedGroup;
114
115 /**
116 * Server response with notifications and groups.
117 *
118 * @typedef {{
119 * googleNowDisabled: (boolean|undefined),
120 * groups: Object.<string, ReceivedGroup>,
121 * notifications: Array.<ReceivedNotification>
122 * }}
123 */
124 var ServerResponse;
118 125
119 /** 126 /**
120 * Notification group as the client stores it. |cardsTimestamp| and |rank| are 127 * Notification group as the client stores it. |cardsTimestamp| and |rank| are
121 * defined if |cards| is non-empty. |nextPollTime| is undefined if the server 128 * defined if |cards| is non-empty. |nextPollTime| is undefined if the server
122 * (1) never sent 'nextPollSeconds' for the group or 129 * (1) never sent 'nextPollSeconds' for the group or
123 * (2) didn't send 'nextPollSeconds' with the last group update containing a 130 * (2) didn't send 'nextPollSeconds' with the last group update containing a
124 * cards update and all the times after that. 131 * cards update and all the times after that.
125 * 132 *
126 * @typedef {{ 133 * @typedef {{
127 * cards: Array.<UnmergedNotification>, 134 * cards: Array.<ReceivedNotification>,
128 * cardsTimestamp: number=, 135 * cardsTimestamp: (number|undefined),
129 * nextPollTime: number=, 136 * nextPollTime: (number|undefined),
130 * rank: number= 137 * rank: (number|undefined)
131 * }} 138 * }}
132 */ 139 */
133 var StorageGroup; 140 var StoredNotificationGroup;
141
142 /**
143 * Pending (not yet successfully sent) dismissal for a received notification.
144 * |time| is the moment when the user requested dismissal.
145 *
146 * @typedef {{
147 * chromeNotificationId: ChromeNotificationId,
148 * time: number,
149 * dismissalData: DismissalData
150 * }}
151 */
152 var PendingDismissal;
134 153
135 /** 154 /**
136 * Checks if a new task can't be scheduled when another task is already 155 * Checks if a new task can't be scheduled when another task is already
137 * scheduled. 156 * scheduled.
138 * @param {string} newTaskName Name of the new task. 157 * @param {string} newTaskName Name of the new task.
139 * @param {string} scheduledTaskName Name of the scheduled task. 158 * @param {string} scheduledTaskName Name of the scheduled task.
140 * @return {boolean} Whether the new task conflicts with the existing task. 159 * @return {boolean} Whether the new task conflicts with the existing task.
141 */ 160 */
142 function areTasksConflicting(newTaskName, scheduledTaskName) { 161 function areTasksConflicting(newTaskName, scheduledTaskName) {
143 if (newTaskName == UPDATE_CARDS_TASK_NAME && 162 if (newTaskName == UPDATE_CARDS_TASK_NAME &&
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 } else { 285 } else {
267 originalOnLoadEnd(event); 286 originalOnLoadEnd(event);
268 } 287 }
269 }); 288 });
270 289
271 callbackBoolean(true); 290 callbackBoolean(true);
272 }); 291 });
273 } 292 }
274 293
275 /** 294 /**
276 * Shows parsed and merged cards as notifications. 295 * Shows parsed and combined cards as notifications.
277 * @param {Object.<string, MergedCard>} cards Map from chromeNotificationId to 296 * @param {Object.<ChromeNotificationId, CombinedCard>} cards Map from
278 * the merged card, containing cards to show. 297 * chromeNotificationId to the combined card, containing cards to show.
279 * @param {function(CardCreateInfo)=} onCardShown Optional parameter called when 298 * @param {function(ReceivedNotification)=} onCardShown Optional parameter
280 * each card is shown. 299 * called when each card is shown.
281 */ 300 */
282 function showNotificationCards(cards, onCardShown) { 301 function showNotificationCards(cards, onCardShown) {
283 console.log('showNotificationCards ' + JSON.stringify(cards)); 302 console.log('showNotificationCards ' + JSON.stringify(cards));
284 303
285 instrumented.storage.local.get(['notificationsData', 'recentDismissals'], 304 instrumented.notifications.getAll(function(notifications) {
286 function(items) { 305 console.log('showNotificationCards-getAll ' +
287 console.log('showNotificationCards-get ' + 306 JSON.stringify(notifications));
288 JSON.stringify(items)); 307 notifications = notifications || {};
289 items = items || {};
290 items.notificationsData = items.notificationsData || {};
291 items.recentDismissals = items.recentDismissals || {};
292 308
293 instrumented.notifications.getAll(function(notifications) { 309 // Mark notifications that didn't receive an update as having received
294 console.log('showNotificationCards-getAll ' + 310 // an empty update.
295 JSON.stringify(notifications)); 311 for (var chromeNotificationId in notifications) {
296 notifications = notifications || {}; 312 cards[chromeNotificationId] = cards[chromeNotificationId] || [];
313 }
297 314
298 // Build a set of non-expired recent dismissals. It will be used for 315 /** @type {Object.<string, NotificationDataEntry>} */
299 // client-side filtering of cards. 316 var notificationsData = {};
300 var updatedRecentDismissals = {};
301 var currentTimeMs = Date.now();
302 for (var chromeNotificationId in items.recentDismissals) {
303 if (currentTimeMs - items.recentDismissals[chromeNotificationId] <
304 DISMISS_RETENTION_TIME_MS) {
305 updatedRecentDismissals[chromeNotificationId] =
306 items.recentDismissals[chromeNotificationId];
307 delete cards[chromeNotificationId];
308 }
309 }
310 317
311 // Delete notifications that didn't receive an update. 318 // Create/update/delete notifications.
312 for (var chromeNotificationId in notifications) { 319 for (var chromeNotificationId in cards) {
313 console.log('showNotificationCards-delete-check ' + 320 notificationsData[chromeNotificationId] = cardSet.update(
314 chromeNotificationId); 321 chromeNotificationId,
315 if (!(chromeNotificationId in cards)) { 322 cards[chromeNotificationId],
316 console.log( 323 onCardShown);
317 'showNotificationCards-delete ' + chromeNotificationId); 324 }
318 cardSet.clear(chromeNotificationId, false); 325 chrome.storage.local.set({notificationsData: notificationsData});
319 } 326 });
320 }
321
322 // Create/update notifications and store their new properties.
323 var newNotificationsData = {};
324 for (var chromeNotificationId in cards) {
325 var notificationData =
326 items.notificationsData[chromeNotificationId];
327 var previousVersion = notifications[chromeNotificationId] &&
328 notificationData &&
329 notificationData.cardCreateInfo &&
330 notificationData.cardCreateInfo.version;
331 newNotificationsData[chromeNotificationId] = cardSet.update(
332 chromeNotificationId,
333 cards[chromeNotificationId],
334 previousVersion,
335 onCardShown);
336 }
337
338 chrome.storage.local.set({
339 notificationsData: newNotificationsData,
340 recentDismissals: updatedRecentDismissals
341 });
342 });
343 });
344 } 327 }
345 328
346 /** 329 /**
347 * Removes all cards and card state on Google Now close down. 330 * Removes all cards and card state on Google Now close down.
348 * For example, this occurs when the geolocation preference is unchecked in the 331 * For example, this occurs when the geolocation preference is unchecked in the
349 * content settings. 332 * content settings.
350 */ 333 */
351 function removeAllCards() { 334 function removeAllCards() {
352 console.log('removeAllCards'); 335 console.log('removeAllCards');
353 336
354 // TODO(robliao): Once Google Now clears its own checkbox in the 337 // TODO(robliao): Once Google Now clears its own checkbox in the
355 // notifications center and bug 260376 is fixed, the below clearing 338 // notifications center and bug 260376 is fixed, the below clearing
356 // code is no longer necessary. 339 // code is no longer necessary.
357 instrumented.notifications.getAll(function(notifications) { 340 instrumented.notifications.getAll(function(notifications) {
358 notifications = notifications || {}; 341 notifications = notifications || {};
359 for (var chromeNotificationId in notifications) { 342 for (var chromeNotificationId in notifications) {
360 instrumented.notifications.clear(chromeNotificationId, function() {}); 343 instrumented.notifications.clear(chromeNotificationId, function() {});
361 } 344 }
362 chrome.storage.local.remove(['notificationsData', 'notificationGroups']); 345 chrome.storage.local.remove(['notificationsData', 'notificationGroups']);
363 }); 346 });
364 } 347 }
365 348
366 /** 349 /**
367 * Merges an unmerged notification into a merged card with same ID. 350 * Adds a card group into a set of combined cards.
368 * @param {MergedCard=} mergedCard Existing merged card or undefined if a merged 351 * @param {Object.<ChromeNotificationId, CombinedCard>} combinedCards Map from
369 * card doesn't exist (i.e. we see this ID for the first time while 352 * chromeNotificationId to a combined card.
370 * merging). 353 * This is an input/output parameter.
371 * @param {UnmergedNotification} unmergedNotification Notification as it was 354 * @param {StoredNotificationGroup} storedGroup Group to combine into the
372 * received from the server. 355 * combined card set.
373 * @param {number} notificationTimestamp The moment the unmerged card was
374 * received.
375 * @param {number} notificationGroupRank Rank of the group of the unmerged card.
376 * @return {MergedCard} Result of merging |unmergedNotification| into
377 * |mergedCard|.
378 */ 356 */
379 function mergeCards( 357 function combineGroup(combinedCards, storedGroup) {
380 mergedCard, 358 for (var i = 0; i < storedGroup.cards.length; i++) {
381 unmergedNotification, 359 /** @type {ReceivedNotification} */
382 notificationTimestamp, 360 var receivedNotification = storedGroup.cards[i];
383 notificationGroupRank) {
384 var result = mergedCard || {dismissals: []};
385 361
386 var priority = mergedCard ? 362 /** @type {UncombinedNotification} */
387 Math.max( 363 var uncombinedNotification = {
388 mergedCard.notification.priority, 364 receivedNotification: receivedNotification,
389 unmergedNotification.chromeNotificationOptions.priority) : 365 showTime: receivedNotification.trigger.showTimeSec &&
390 unmergedNotification.chromeNotificationOptions.priority; 366 (storedGroup.cardsTimestamp +
367 receivedNotification.trigger.showTimeSec * MS_IN_SECOND),
368 hideTime: storedGroup.cardsTimestamp +
369 receivedNotification.trigger.hideTimeSec * MS_IN_SECOND
370 };
391 371
392 if (!mergedCard || notificationGroupRank > mergedCard.groupRank) { 372 var combinedCard =
393 result.groupRank = notificationGroupRank; 373 combinedCards[receivedNotification.chromeNotificationId] || [];
394 var showTime = unmergedNotification.trigger && 374 combinedCard.push(uncombinedNotification);
395 unmergedNotification.trigger.showTimeSec && 375 combinedCards[receivedNotification.chromeNotificationId] = combinedCard;
396 (notificationTimestamp +
397 unmergedNotification.trigger.showTimeSec * MS_IN_SECOND);
398 var hideTime = unmergedNotification.trigger &&
399 unmergedNotification.trigger.hideTimeSec &&
400 (notificationTimestamp +
401 unmergedNotification.trigger.hideTimeSec * MS_IN_SECOND);
402 result.trigger = {
403 showTime: showTime,
404 hideTime: hideTime
405 };
406 }
407
408 if (!mergedCard || notificationTimestamp > mergedCard.timestamp) {
409 result.timestamp = notificationTimestamp;
410 result.notification = unmergedNotification.chromeNotificationOptions;
411 result.actionUrls = unmergedNotification.actionUrls;
412 result.version = unmergedNotification.version;
413 }
414
415 result.locationBased =
416 result.locationBased || unmergedNotification.locationBased;
417
418 result.notification.priority = priority;
419 var dismissalData = {
420 notificationId: unmergedNotification.notificationId,
421 parameters: unmergedNotification.dismissal
422 };
423 result.dismissals.push(dismissalData);
424
425 return result;
426 }
427
428 /**
429 * Merges a card group into a set of merged cards.
430 * @param {Object.<string, MergedCard>} mergedCards Map from
431 * chromeNotificationId to a merged card.
432 * This is an input/output parameter.
433 * @param {StorageGroup} storageGroup Group to merge into the merged card set.
434 */
435 function mergeGroup(mergedCards, storageGroup) {
436 for (var i = 0; i < storageGroup.cards.length; i++) {
437 var card = storageGroup.cards[i];
438 mergedCards[card.chromeNotificationId] = mergeCards(
439 mergedCards[card.chromeNotificationId],
440 card,
441 storageGroup.cardsTimestamp,
442 storageGroup.rank);
443 } 376 }
444 } 377 }
445 378
446 /** 379 /**
447 * Schedules next cards poll. 380 * Schedules next cards poll.
448 * @param {Object.<string, StorageGroup>} groups Map from group name to group 381 * @param {Object.<string, StoredNotificationGroup>} groups Map from group name
449 * information. 382 * to group information.
450 * @param {boolean} isOptedIn True if the user is opted in to Google Now. 383 * @param {boolean} isOptedIn True if the user is opted in to Google Now.
451 */ 384 */
452 function scheduleNextPoll(groups, isOptedIn) { 385 function scheduleNextPoll(groups, isOptedIn) {
453 if (isOptedIn) { 386 if (isOptedIn) {
454 var nextPollTime = null; 387 var nextPollTime = null;
455 388
456 for (var groupName in groups) { 389 for (var groupName in groups) {
457 var group = groups[groupName]; 390 var group = groups[groupName];
458 if (group.nextPollTime !== undefined) { 391 if (group.nextPollTime !== undefined) {
459 nextPollTime = nextPollTime == null ? 392 nextPollTime = nextPollTime == null ?
(...skipping 13 matching lines...) Expand all
473 'GoogleNow', function(params) { 406 'GoogleNow', function(params) {
474 var optinPollPeriodSeconds = 407 var optinPollPeriodSeconds =
475 parseInt(params && params.optinPollPeriodSeconds, 10) || 408 parseInt(params && params.optinPollPeriodSeconds, 10) ||
476 DEFAULT_OPTIN_CHECK_PERIOD_SECONDS; 409 DEFAULT_OPTIN_CHECK_PERIOD_SECONDS;
477 updateCardsAttempts.start(optinPollPeriodSeconds); 410 updateCardsAttempts.start(optinPollPeriodSeconds);
478 }); 411 });
479 } 412 }
480 } 413 }
481 414
482 /** 415 /**
483 * Merges notification groups into a set of Chrome notifications and shows them. 416 * Combines notification groups into a set of Chrome notifications and shows
484 * @param {Object.<string, StorageGroup>} notificationGroups Map from group name 417 * them.
485 * to group information. 418 * @param {Object.<string, StoredNotificationGroup>} notificationGroups Map from
486 * @param {function(CardCreateInfo)=} onCardShown Optional parameter called when 419 * group name to group information.
487 * each card is shown. 420 * @param {function(ReceivedNotification)=} onCardShown Optional parameter
421 * called when each card is shown.
488 */ 422 */
489 function mergeAndShowNotificationCards(notificationGroups, onCardShown) { 423 function combineAndShowNotificationCards(notificationGroups, onCardShown) {
490 var mergedCards = {}; 424 console.log('combineAndShowNotificationCards ' +
425 JSON.stringify(notificationGroups));
426 /** @type {Object.<ChromeNotificationId, CombinedCard>} */
427 var combinedCards = {};
491 428
492 for (var groupName in notificationGroups) 429 for (var groupName in notificationGroups)
493 mergeGroup(mergedCards, notificationGroups[groupName]); 430 combineGroup(combinedCards, notificationGroups[groupName]);
494 431
495 showNotificationCards(mergedCards, onCardShown); 432 showNotificationCards(combinedCards, onCardShown);
496 } 433 }
497 434
498 /** 435 /**
499 * Parses JSON response from the notification server, shows notifications and 436 * Parses JSON response from the notification server, shows notifications and
500 * schedules next update. 437 * schedules next update.
501 * @param {string} response Server response. 438 * @param {string} response Server response.
502 * @param {function(CardCreateInfo)=} onCardShown Optional parameter called when 439 * @param {function(ReceivedNotification)=} onCardShown Optional parameter
503 * each card is shown. 440 * called when each card is shown.
504 */ 441 */
505 function parseAndShowNotificationCards(response, onCardShown) { 442 function parseAndShowNotificationCards(response, onCardShown) {
506 console.log('parseAndShowNotificationCards ' + response); 443 console.log('parseAndShowNotificationCards ' + response);
444 /** @type {ServerResponse} */
507 var parsedResponse = JSON.parse(response); 445 var parsedResponse = JSON.parse(response);
508 446
509 if (parsedResponse.googleNowDisabled) { 447 if (parsedResponse.googleNowDisabled) {
510 chrome.storage.local.set({googleNowEnabled: false}); 448 chrome.storage.local.set({googleNowEnabled: false});
511 // TODO(vadimt): Remove the line below once the server stops sending groups 449 // TODO(vadimt): Remove the line below once the server stops sending groups
512 // with 'googleNowDisabled' responses. 450 // with 'googleNowDisabled' responses.
513 parsedResponse.groups = {}; 451 parsedResponse.groups = {};
514 // Google Now was enabled; now it's disabled. This is a state change. 452 // Google Now was enabled; now it's disabled. This is a state change.
515 onStateChange(); 453 onStateChange();
516 } 454 }
517 455
518 var receivedGroups = parsedResponse.groups; 456 var receivedGroups = parsedResponse.groups;
519 457
520 // Populate groups with corresponding cards. 458 instrumented.storage.local.get(['notificationGroups', 'recentDismissals'],
521 if (parsedResponse.notifications) { 459 function(items) {
522 for (var i = 0; i != parsedResponse.notifications.length; ++i) {
523 var card = parsedResponse.notifications[i];
524 var group = receivedGroups[card.groupName];
525 group.cards = group.cards || [];
526 group.cards.push(card);
527 }
528 }
529
530 instrumented.storage.local.get('notificationGroups', function(items) {
531 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items)); 460 console.log('parseAndShowNotificationCards-get ' + JSON.stringify(items));
robliao 2013/12/07 00:51:29 Style: These need to be tabbed over two spaces.
vadimt 2013/12/07 01:04:24 Done.
532 items = items || {}; 461 items = items || {};
462 /** @type {Object.<string, StoredNotificationGroup>} */
533 items.notificationGroups = items.notificationGroups || {}; 463 items.notificationGroups = items.notificationGroups || {};
464 /** @type {Object.<NotificationId, number>} */
465 items.recentDismissals = items.recentDismissals || {};
534 466
467 // Build a set of non-expired recent dismissals. It will be used for
468 // client-side filtering of cards.
469 /** @type {Object.<NotificationId, number>} */
470 var updatedRecentDismissals = {};
535 var now = Date.now(); 471 var now = Date.now();
472 for (var notificationId in items.recentDismissals) {
473 var dismissalAge = now - items.recentDismissals[notificationId];
474 if (dismissalAge < DISMISS_RETENTION_TIME_MS) {
475 updatedRecentDismissals[notificationId] =
476 items.recentDismissals[notificationId];
477 }
478 }
479
480 // Populate groups with corresponding cards.
481 if (parsedResponse.notifications) {
482 for (var i = 0; i < parsedResponse.notifications.length; ++i) {
483 /** @type {ReceivedNotification} */
484 var card = parsedResponse.notifications[i];
485 if (!(card.notificationId in updatedRecentDismissals)) {
486 var group = receivedGroups[card.groupName];
487 group.cards = group.cards || [];
488 group.cards.push(card);
489 }
490 }
491 }
536 492
537 // Build updated set of groups. 493 // Build updated set of groups.
538 var updatedGroups = {}; 494 var updatedGroups = {};
539 495
540 for (var groupName in receivedGroups) { 496 for (var groupName in receivedGroups) {
541 var receivedGroup = receivedGroups[groupName]; 497 var receivedGroup = receivedGroups[groupName];
542 var storageGroup = items.notificationGroups[groupName] || { 498 var storedGroup = items.notificationGroups[groupName] || {
543 cards: [], 499 cards: [],
544 cardsTimestamp: undefined, 500 cardsTimestamp: undefined,
545 nextPollTime: undefined, 501 nextPollTime: undefined,
546 rank: undefined 502 rank: undefined
547 }; 503 };
548 504
549 if (receivedGroup.requested) 505 if (receivedGroup.requested)
550 receivedGroup.cards = receivedGroup.cards || []; 506 receivedGroup.cards = receivedGroup.cards || [];
551 507
552 if (receivedGroup.cards) { 508 if (receivedGroup.cards) {
553 // If the group contains a cards update, all its fields will get new 509 // If the group contains a cards update, all its fields will get new
554 // values. 510 // values.
555 storageGroup.cards = receivedGroup.cards; 511 storedGroup.cards = receivedGroup.cards;
556 storageGroup.cardsTimestamp = now; 512 storedGroup.cardsTimestamp = now;
557 storageGroup.rank = receivedGroup.rank; 513 storedGroup.rank = receivedGroup.rank;
558 storageGroup.nextPollTime = undefined; 514 storedGroup.nextPollTime = undefined;
559 // The code below assigns nextPollTime a defined value if 515 // The code below assigns nextPollTime a defined value if
560 // nextPollSeconds is specified in the received group. 516 // nextPollSeconds is specified in the received group.
561 // If the group's cards are not updated, and nextPollSeconds is 517 // If the group's cards are not updated, and nextPollSeconds is
562 // unspecified, this method doesn't change group's nextPollTime. 518 // unspecified, this method doesn't change group's nextPollTime.
563 } 519 }
564 520
565 // 'nextPollSeconds' may be sent even for groups that don't contain cards 521 // 'nextPollSeconds' may be sent even for groups that don't contain cards
566 // updates. 522 // updates.
567 if (receivedGroup.nextPollSeconds !== undefined) { 523 if (receivedGroup.nextPollSeconds !== undefined) {
568 storageGroup.nextPollTime = 524 storedGroup.nextPollTime =
569 now + receivedGroup.nextPollSeconds * MS_IN_SECOND; 525 now + receivedGroup.nextPollSeconds * MS_IN_SECOND;
570 } 526 }
571 527
572 updatedGroups[groupName] = storageGroup; 528 updatedGroups[groupName] = storedGroup;
573 } 529 }
574 530
575 scheduleNextPoll(updatedGroups, !parsedResponse.googleNowDisabled); 531 scheduleNextPoll(updatedGroups, !parsedResponse.googleNowDisabled);
576 chrome.storage.local.set({notificationGroups: updatedGroups}); 532 chrome.storage.local.set({
577 mergeAndShowNotificationCards(updatedGroups, onCardShown); 533 notificationGroups: updatedGroups,
534 recentDismissals: updatedRecentDismissals
535 });
536 combineAndShowNotificationCards(updatedGroups, onCardShown);
578 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); 537 recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS);
579 }); 538 });
580 } 539 }
581 540
582 /** 541 /**
583 * Update Location Cards Shown Count. 542 * Update Location Cards Shown Count.
584 * @param {Object} cardCreateInfo Card Create Info 543 * @param {ReceivedNotification} receivedNotification Notification as it was
544 * received from the server.
585 */ 545 */
586 function countLocationCard(cardCreateInfo) { 546 function countLocationCard(receivedNotification) {
587 if (cardCreateInfo.locationBased) { 547 if (receivedNotification.locationBased) {
588 localStorage['locationCardsShown']++; 548 localStorage['locationCardsShown']++;
589 } 549 }
590 } 550 }
591 551
592 /** 552 /**
593 * Requests notification cards from the server for specified groups. 553 * Requests notification cards from the server for specified groups.
594 * @param {Array.<string>} groupNames Names of groups that need to be refreshed. 554 * @param {Array.<string>} groupNames Names of groups that need to be refreshed.
595 */ 555 */
596 function requestNotificationGroups(groupNames) { 556 function requestNotificationGroups(groupNames) {
597 console.log('requestNotificationGroups from ' + NOTIFICATION_CARDS_URL + 557 console.log('requestNotificationGroups from ' + NOTIFICATION_CARDS_URL +
(...skipping 15 matching lines...) Expand all
613 }); 573 });
614 574
615 console.log('requestNotificationGroups: request=' + requestParameters); 575 console.log('requestNotificationGroups: request=' + requestParameters);
616 576
617 var request = buildServerRequest('GET', 'notifications' + requestParameters); 577 var request = buildServerRequest('GET', 'notifications' + requestParameters);
618 578
619 request.onloadend = function(event) { 579 request.onloadend = function(event) {
620 console.log('requestNotificationGroups-onloadend ' + request.status); 580 console.log('requestNotificationGroups-onloadend ' + request.status);
621 if (request.status == HTTP_OK) { 581 if (request.status == HTTP_OK) {
622 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); 582 recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
623 parseAndShowNotificationCards(request.response, cardShownCallback); 583 parseAndShowNotificationCards(request.responseText, cardShownCallback);
624 } 584 }
625 }; 585 };
626 586
627 setAuthorization(request, function(success) { 587 setAuthorization(request, function(success) {
628 if (success) 588 if (success)
629 request.send(); 589 request.send();
630 }); 590 });
631 } 591 }
632 592
633 /** 593 /**
634 * Requests the account opted-in state from the server. 594 * Requests the account opted-in state from the server.
635 * @param {function()} optedInCallback Function that will be called if 595 * @param {function()} optedInCallback Function that will be called if
636 * opted-in state is 'true'. 596 * opted-in state is 'true'.
637 */ 597 */
638 function requestOptedIn(optedInCallback) { 598 function requestOptedIn(optedInCallback) {
639 console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL); 599 console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL);
640 600
641 var request = buildServerRequest('GET', 'settings/optin'); 601 var request = buildServerRequest('GET', 'settings/optin');
642 602
643 request.onloadend = function(event) { 603 request.onloadend = function(event) {
644 console.log( 604 console.log(
645 'requestOptedIn-onloadend ' + request.status + ' ' + request.response); 605 'requestOptedIn-onloadend ' + request.status + ' ' + request.response);
646 if (request.status == HTTP_OK) { 606 if (request.status == HTTP_OK) {
647 var parsedResponse = JSON.parse(request.response); 607 var parsedResponse = JSON.parse(request.responseText);
648 if (parsedResponse.value) { 608 if (parsedResponse.value) {
649 chrome.storage.local.set({googleNowEnabled: true}); 609 chrome.storage.local.set({googleNowEnabled: true});
650 optedInCallback(); 610 optedInCallback();
651 // Google Now was disabled, now it's enabled. This is a state change. 611 // Google Now was disabled, now it's enabled. This is a state change.
652 onStateChange(); 612 onStateChange();
653 } else { 613 } else {
654 scheduleNextPoll({}, false); 614 scheduleNextPoll({}, false);
655 } 615 }
656 } 616 }
657 }; 617 };
658 618
659 setAuthorization(request, function(success) { 619 setAuthorization(request, function(success) {
660 if (success) 620 if (success)
661 request.send(); 621 request.send();
662 }); 622 });
663 } 623 }
664 624
665 /** 625 /**
666 * Requests notification cards from the server. 626 * Requests notification cards from the server.
667 * @param {Location} position Location of this computer. 627 * @param {Location=} position Location of this computer.
668 */ 628 */
669 function requestNotificationCards(position) { 629 function requestNotificationCards(position) {
670 console.log('requestNotificationCards ' + JSON.stringify(position)); 630 console.log('requestNotificationCards ' + JSON.stringify(position));
671 631
672 instrumented.storage.local.get( 632 instrumented.storage.local.get(
673 ['notificationGroups', 'googleNowEnabled'], function(items) { 633 ['notificationGroups', 'googleNowEnabled'], function(items) {
674 console.log('requestNotificationCards-storage-get ' + 634 console.log('requestNotificationCards-storage-get ' +
675 JSON.stringify(items)); 635 JSON.stringify(items));
676 items = items || {}; 636 items = items || {};
637 /** @type {Object.<string, StoredNotificationGroup>} */
638 items.notificationGroups = items.notificationGroups || {};
677 639
678 var groupsToRequest = []; 640 var groupsToRequest = [];
679 641
680 if (items.notificationGroups) { 642 var now = Date.now();
681 var now = Date.now();
682 643
683 for (var groupName in items.notificationGroups) { 644 for (var groupName in items.notificationGroups) {
684 var group = items.notificationGroups[groupName]; 645 var group = items.notificationGroups[groupName];
685 if (group.nextPollTime !== undefined && group.nextPollTime <= now) 646 if (group.nextPollTime !== undefined && group.nextPollTime <= now)
686 groupsToRequest.push(groupName); 647 groupsToRequest.push(groupName);
687 }
688 } 648 }
689 649
690 if (items.googleNowEnabled) { 650 if (items.googleNowEnabled) {
691 requestNotificationGroups(groupsToRequest); 651 requestNotificationGroups(groupsToRequest);
692 } else { 652 } else {
693 requestOptedIn(function() { 653 requestOptedIn(function() {
694 requestNotificationGroups(groupsToRequest); 654 requestNotificationGroups(groupsToRequest);
695 }); 655 });
696 } 656 }
697 }); 657 });
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 * Stops getting the location. 689 * Stops getting the location.
730 */ 690 */
731 function stopRequestLocation() { 691 function stopRequestLocation() {
732 console.log('stopRequestLocation'); 692 console.log('stopRequestLocation');
733 chrome.location.clearWatch(LOCATION_WATCH_NAME); 693 chrome.location.clearWatch(LOCATION_WATCH_NAME);
734 } 694 }
735 695
736 /** 696 /**
737 * Obtains new location; requests and shows notification cards based on this 697 * Obtains new location; requests and shows notification cards based on this
738 * location. 698 * location.
739 * @param {Location} position Location of this computer. 699 * @param {Location=} position Location of this computer.
740 */ 700 */
741 function updateNotificationsCards(position) { 701 function updateNotificationsCards(position) {
742 console.log('updateNotificationsCards ' + JSON.stringify(position) + 702 console.log('updateNotificationsCards ' + JSON.stringify(position) +
743 ' @' + new Date()); 703 ' @' + new Date());
744 tasks.add(UPDATE_CARDS_TASK_NAME, function() { 704 tasks.add(UPDATE_CARDS_TASK_NAME, function() {
745 console.log('updateNotificationsCards-task-begin'); 705 console.log('updateNotificationsCards-task-begin');
746 updateCardsAttempts.isRunning(function(running) { 706 updateCardsAttempts.isRunning(function(running) {
747 if (running) { 707 if (running) {
748 updateCardsAttempts.planForNext(function() { 708 updateCardsAttempts.planForNext(function() {
749 processPendingDismissals(function(success) { 709 processPendingDismissals(function(success) {
750 if (success) { 710 if (success) {
751 // The cards are requested only if there are no unsent dismissals. 711 // The cards are requested only if there are no unsent dismissals.
752 requestNotificationCards(position); 712 requestNotificationCards(position);
753 } 713 }
754 }); 714 });
755 }); 715 });
756 } 716 }
757 }); 717 });
758 }); 718 });
759 } 719 }
760 720
761 /** 721 /**
762 * Sends a server request to dismiss a card. 722 * Sends a server request to dismiss a card.
763 * @param {string} chromeNotificationId chrome.notifications ID of the card. 723 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of
724 * the card.
764 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in 725 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in
765 * milliseconds since epoch. 726 * milliseconds since epoch.
766 * @param {DismissalData} dismissalData Data to build a dismissal request. 727 * @param {DismissalData} dismissalData Data to build a dismissal request.
767 * @param {function(boolean)} callbackBoolean Completion callback with 'done' 728 * @param {function(boolean)} callbackBoolean Completion callback with 'done'
768 * parameter. 729 * parameter.
769 */ 730 */
770 function requestCardDismissal( 731 function requestCardDismissal(
771 chromeNotificationId, dismissalTimeMs, dismissalData, callbackBoolean) { 732 chromeNotificationId, dismissalTimeMs, dismissalData, callbackBoolean) {
772 console.log('requestDismissingCard ' + chromeNotificationId + ' from ' + 733 console.log('requestDismissingCard ' + chromeNotificationId +
773 NOTIFICATION_CARDS_URL); 734 ' from ' + NOTIFICATION_CARDS_URL +
735 ', dismissalData=' + JSON.stringify(dismissalData));
774 736
775 var dismissalAge = Date.now() - dismissalTimeMs; 737 var dismissalAge = Date.now() - dismissalTimeMs;
776 738
777 if (dismissalAge > MAXIMUM_DISMISSAL_AGE_MS) { 739 if (dismissalAge > MAXIMUM_DISMISSAL_AGE_MS) {
778 callbackBoolean(true); 740 callbackBoolean(true);
779 return; 741 return;
780 } 742 }
781 743
782 recordEvent(GoogleNowEvent.DISMISS_REQUEST_TOTAL); 744 recordEvent(GoogleNowEvent.DISMISS_REQUEST_TOTAL);
783 745
784 var request = 'notifications/' + dismissalData.notificationId + 746 var requestParameters = 'notifications/' + dismissalData.notificationId +
785 '?age=' + dismissalAge + 747 '?age=' + dismissalAge +
786 '&chromeNotificationId=' + chromeNotificationId; 748 '&chromeNotificationId=' + chromeNotificationId;
787 749
788 for (var paramField in dismissalData.parameters) 750 for (var paramField in dismissalData.parameters)
789 request += ('&' + paramField + '=' + dismissalData.parameters[paramField]); 751 requestParameters += ('&' + paramField +
752 '=' + dismissalData.parameters[paramField]);
790 753
791 console.log('requestCardDismissal: request=' + request); 754 console.log('requestCardDismissal: requestParameters=' + requestParameters);
792 755
793 var request = buildServerRequest('DELETE', request); 756 var request = buildServerRequest('DELETE', requestParameters);
794 request.onloadend = function(event) { 757 request.onloadend = function(event) {
795 console.log('requestDismissingCard-onloadend ' + request.status); 758 console.log('requestDismissingCard-onloadend ' + request.status);
796 if (request.status == HTTP_NOCONTENT) 759 if (request.status == HTTP_NOCONTENT)
797 recordEvent(GoogleNowEvent.DISMISS_REQUEST_SUCCESS); 760 recordEvent(GoogleNowEvent.DISMISS_REQUEST_SUCCESS);
798 761
799 // A dismissal doesn't require further retries if it was successful or 762 // A dismissal doesn't require further retries if it was successful or
800 // doesn't have a chance for successful completion. 763 // doesn't have a chance for successful completion.
801 var done = request.status == HTTP_NOCONTENT || 764 var done = request.status == HTTP_NOCONTENT ||
802 request.status == HTTP_BAD_REQUEST || 765 request.status == HTTP_BAD_REQUEST ||
803 request.status == HTTP_METHOD_NOT_ALLOWED; 766 request.status == HTTP_METHOD_NOT_ALLOWED;
(...skipping 12 matching lines...) Expand all
816 * Tries to send dismiss requests for all pending dismissals. 779 * Tries to send dismiss requests for all pending dismissals.
817 * @param {function(boolean)} callbackBoolean Completion callback with 'success' 780 * @param {function(boolean)} callbackBoolean Completion callback with 'success'
818 * parameter. Success means that no pending dismissals are left. 781 * parameter. Success means that no pending dismissals are left.
819 */ 782 */
820 function processPendingDismissals(callbackBoolean) { 783 function processPendingDismissals(callbackBoolean) {
821 instrumented.storage.local.get(['pendingDismissals', 'recentDismissals'], 784 instrumented.storage.local.get(['pendingDismissals', 'recentDismissals'],
822 function(items) { 785 function(items) {
823 console.log('processPendingDismissals-storage-get ' + 786 console.log('processPendingDismissals-storage-get ' +
824 JSON.stringify(items)); 787 JSON.stringify(items));
825 items = items || {}; 788 items = items || {};
789 /** @type {Array.<PendingDismissal>} */
826 items.pendingDismissals = items.pendingDismissals || []; 790 items.pendingDismissals = items.pendingDismissals || [];
791 /** @type {Object.<NotificationId, number>} */
827 items.recentDismissals = items.recentDismissals || {}; 792 items.recentDismissals = items.recentDismissals || {};
828 793
829 var dismissalsChanged = false; 794 var dismissalsChanged = false;
830 795
831 function onFinish(success) { 796 function onFinish(success) {
832 if (dismissalsChanged) { 797 if (dismissalsChanged) {
833 chrome.storage.local.set({ 798 chrome.storage.local.set({
834 pendingDismissals: items.pendingDismissals, 799 pendingDismissals: items.pendingDismissals,
835 recentDismissals: items.recentDismissals 800 recentDismissals: items.recentDismissals
836 }); 801 });
837 } 802 }
838 callbackBoolean(success); 803 callbackBoolean(success);
839 } 804 }
840 805
841 function doProcessDismissals() { 806 function doProcessDismissals() {
842 if (items.pendingDismissals.length == 0) { 807 if (items.pendingDismissals.length == 0) {
843 dismissalAttempts.stop(); 808 dismissalAttempts.stop();
844 onFinish(true); 809 onFinish(true);
845 return; 810 return;
846 } 811 }
847 812
848 // Send dismissal for the first card, and if successful, repeat 813 // Send dismissal for the first card, and if successful, repeat
849 // recursively with the rest. 814 // recursively with the rest.
815 /** @type {PendingDismissal} */
850 var dismissal = items.pendingDismissals[0]; 816 var dismissal = items.pendingDismissals[0];
851 requestCardDismissal( 817 requestCardDismissal(
852 dismissal.chromeNotificationId, 818 dismissal.chromeNotificationId,
853 dismissal.time, 819 dismissal.time,
854 dismissal.dismissalData, 820 dismissal.dismissalData,
855 function(done) { 821 function(done) {
856 if (done) { 822 if (done) {
857 dismissalsChanged = true; 823 dismissalsChanged = true;
858 items.pendingDismissals.splice(0, 1); 824 items.pendingDismissals.splice(0, 1);
859 items.recentDismissals[dismissal.chromeNotificationId] = 825 items.recentDismissals[
826 dismissal.dismissalData.notificationId] =
860 Date.now(); 827 Date.now();
861 doProcessDismissals(); 828 doProcessDismissals();
862 } else { 829 } else {
863 onFinish(false); 830 onFinish(false);
864 } 831 }
865 }); 832 });
866 } 833 }
867 834
868 doProcessDismissals(); 835 doProcessDismissals();
869 }); 836 });
(...skipping 18 matching lines...) Expand all
888 instrumented.tabs.create({url: url}, function(tab) { 855 instrumented.tabs.create({url: url}, function(tab) {
889 if (tab) 856 if (tab)
890 chrome.windows.update(tab.windowId, {focused: true}); 857 chrome.windows.update(tab.windowId, {focused: true});
891 else 858 else
892 chrome.windows.create({url: url, focused: true}); 859 chrome.windows.create({url: url, focused: true});
893 }); 860 });
894 } 861 }
895 862
896 /** 863 /**
897 * Opens URL corresponding to the clicked part of the notification. 864 * Opens URL corresponding to the clicked part of the notification.
898 * @param {string} chromeNotificationId chrome.notifications ID of the card. 865 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of
899 * @param {function(Object): string} selector Function that extracts the url for 866 * the card.
900 * the clicked area from the button action URLs info. 867 * @param {function((ActionUrls|undefined)): (string|undefined)} selector
868 * Function that extracts the url for the clicked area from the button
869 * action URLs info.
901 */ 870 */
902 function onNotificationClicked(chromeNotificationId, selector) { 871 function onNotificationClicked(chromeNotificationId, selector) {
903 instrumented.storage.local.get('notificationsData', function(items) { 872 instrumented.storage.local.get('notificationsData', function(items) {
873 /** @type {(NotificationDataEntry|undefined)} */
904 var notificationData = items && 874 var notificationData = items &&
905 items.notificationsData && 875 items.notificationsData &&
906 items.notificationsData[chromeNotificationId]; 876 items.notificationsData[chromeNotificationId];
907 877
908 if (!notificationData) 878 if (!notificationData)
909 return; 879 return;
910 880
911 var url = selector(notificationData.actionUrls); 881 var url = selector(notificationData.actionUrls);
912 if (!url) 882 if (!url)
913 return; 883 return;
914 884
915 openUrl(url); 885 openUrl(url);
916 }); 886 });
917 } 887 }
918 888
919 /** 889 /**
920 * Callback for chrome.notifications.onClosed event. 890 * Callback for chrome.notifications.onClosed event.
921 * @param {string} chromeNotificationId chrome.notifications ID of the card. 891 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of
892 * the card.
922 * @param {boolean} byUser Whether the notification was closed by the user. 893 * @param {boolean} byUser Whether the notification was closed by the user.
923 */ 894 */
924 function onNotificationClosed(chromeNotificationId, byUser) { 895 function onNotificationClosed(chromeNotificationId, byUser) {
925 if (!byUser) 896 if (!byUser)
926 return; 897 return;
927 898
928 // At this point we are guaranteed that the notification is a now card. 899 // At this point we are guaranteed that the notification is a now card.
929 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); 900 chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed');
930 901
931 tasks.add(DISMISS_CARD_TASK_NAME, function() { 902 tasks.add(DISMISS_CARD_TASK_NAME, function() {
932 dismissalAttempts.start(); 903 dismissalAttempts.start();
933 904
934 instrumented.storage.local.get( 905 instrumented.storage.local.get(
935 ['pendingDismissals', 'notificationsData'], function(items) { 906 ['pendingDismissals', 'notificationsData'], function(items) {
936 items = items || {}; 907 items = items || {};
908 /** @type {Array.<PendingDismissal>} */
937 items.pendingDismissals = items.pendingDismissals || []; 909 items.pendingDismissals = items.pendingDismissals || [];
910 /** @type {Object.<string, NotificationDataEntry>} */
938 items.notificationsData = items.notificationsData || {}; 911 items.notificationsData = items.notificationsData || {};
939 912
940 // Deleting the notification in case it was re-added while this task was 913 /** @type {NotificationDataEntry} */
941 // scheduled, waiting for execution; also cleaning notification's data 914 var notificationData = items.notificationsData[chromeNotificationId] || {
942 // from storage. 915 timestamp: Date.now(),
943 cardSet.clear(chromeNotificationId, true); 916 combinedCard: []
917 };
944 918
945 var notificationData = items.notificationsData[chromeNotificationId]; 919 var dismissalResult =
920 cardSet.onDismissal(chromeNotificationId, notificationData);
946 921
947 if (notificationData && notificationData.dismissals) { 922 for (var i = 0; i < dismissalResult.dismissals.length; i++) {
948 for (var i = 0; i < notificationData.dismissals.length; i++) { 923 /** @type {PendingDismissal} */
949 var dismissal = { 924 var dismissal = {
950 chromeNotificationId: chromeNotificationId, 925 chromeNotificationId: chromeNotificationId,
951 time: Date.now(), 926 time: Date.now(),
952 dismissalData: notificationData.dismissals[i] 927 dismissalData: dismissalResult.dismissals[i]
953 }; 928 };
954 items.pendingDismissals.push(dismissal); 929 items.pendingDismissals.push(dismissal);
955 } 930 }
956 931
957 chrome.storage.local.set({pendingDismissals: items.pendingDismissals}); 932 items.notificationsData[chromeNotificationId] =
958 } 933 dismissalResult.notificationData;
934
935 chrome.storage.local.set({
936 pendingDismissals: items.pendingDismissals,
937 notificationsData: items.notificationsData
938 });
959 939
960 processPendingDismissals(function(success) {}); 940 processPendingDismissals(function(success) {});
961 }); 941 });
962 }); 942 });
963 } 943 }
964 944
965 /** 945 /**
966 * Initializes the polling system to start monitoring location and fetching 946 * Initializes the polling system to start monitoring location and fetching
967 * cards. 947 * cards.
968 */ 948 */
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1133 instrumented.runtime.onStartup.addListener(function() { 1113 instrumented.runtime.onStartup.addListener(function() {
1134 console.log('onStartup'); 1114 console.log('onStartup');
1135 1115
1136 // Show notifications received by earlier polls. Doing this as early as 1116 // Show notifications received by earlier polls. Doing this as early as
1137 // possible to reduce latency of showing first notifications. This mimics how 1117 // possible to reduce latency of showing first notifications. This mimics how
1138 // persistent notifications will work. 1118 // persistent notifications will work.
1139 tasks.add(SHOW_ON_START_TASK_NAME, function() { 1119 tasks.add(SHOW_ON_START_TASK_NAME, function() {
1140 instrumented.storage.local.get('notificationGroups', function(items) { 1120 instrumented.storage.local.get('notificationGroups', function(items) {
1141 console.log('onStartup-get ' + JSON.stringify(items)); 1121 console.log('onStartup-get ' + JSON.stringify(items));
1142 items = items || {}; 1122 items = items || {};
1123 /** @type {Object.<string, StoredNotificationGroup>} */
1143 items.notificationGroups = items.notificationGroups || {}; 1124 items.notificationGroups = items.notificationGroups || {};
1144 1125
1145 mergeAndShowNotificationCards(items.notificationGroups); 1126 combineAndShowNotificationCards(items.notificationGroups);
1146 }); 1127 });
1147 }); 1128 });
1148 1129
1149 initialize(); 1130 initialize();
1150 }); 1131 });
1151 1132
1152 instrumented. 1133 instrumented.
1153 preferencesPrivate. 1134 preferencesPrivate.
1154 googleGeolocationAccessEnabled. 1135 googleGeolocationAccessEnabled.
1155 onChange. 1136 onChange.
(...skipping 15 matching lines...) Expand all
1171 return actionUrls && actionUrls.messageUrl; 1152 return actionUrls && actionUrls.messageUrl;
1172 }); 1153 });
1173 }); 1154 });
1174 1155
1175 instrumented.notifications.onButtonClicked.addListener( 1156 instrumented.notifications.onButtonClicked.addListener(
1176 function(chromeNotificationId, buttonIndex) { 1157 function(chromeNotificationId, buttonIndex) {
1177 chrome.metricsPrivate.recordUserAction( 1158 chrome.metricsPrivate.recordUserAction(
1178 'GoogleNow.ButtonClicked' + buttonIndex); 1159 'GoogleNow.ButtonClicked' + buttonIndex);
1179 onNotificationClicked(chromeNotificationId, function(actionUrls) { 1160 onNotificationClicked(chromeNotificationId, function(actionUrls) {
1180 var url = actionUrls.buttonUrls[buttonIndex]; 1161 var url = actionUrls.buttonUrls[buttonIndex];
1181 verify(url, 'onButtonClicked: no url for a button'); 1162 verify(url !== undefined, 'onButtonClicked: no url for a button');
1182 return url; 1163 return url;
1183 }); 1164 });
1184 }); 1165 });
1185 1166
1186 instrumented.notifications.onClosed.addListener(onNotificationClosed); 1167 instrumented.notifications.onClosed.addListener(onNotificationClosed);
1187 1168
1188 instrumented.notifications.onPermissionLevelChanged.addListener( 1169 instrumented.notifications.onPermissionLevelChanged.addListener(
1189 function(permissionLevel) { 1170 function(permissionLevel) {
1190 console.log('Notifications permissionLevel Change'); 1171 console.log('Notifications permissionLevel Change');
1191 onStateChange(); 1172 onStateChange();
(...skipping 23 matching lines...) Expand all
1215 if (!items) 1196 if (!items)
1216 return; 1197 return;
1217 1198
1218 // If this is the first time we get lastPollNowPayloads, initialize it. 1199 // If this is the first time we get lastPollNowPayloads, initialize it.
1219 items.lastPollNowPayloads = items.lastPollNowPayloads || {}; 1200 items.lastPollNowPayloads = items.lastPollNowPayloads || {};
1220 1201
1221 if (items.lastPollNowPayloads[message.subchannelId] != 1202 if (items.lastPollNowPayloads[message.subchannelId] !=
1222 message.payload) { 1203 message.payload) {
1223 items.lastPollNowPayloads[message.subchannelId] = message.payload; 1204 items.lastPollNowPayloads[message.subchannelId] = message.payload;
1224 1205
1206 /** @type {Object.<string, StoredNotificationGroup>} */
1225 items.notificationGroups = items.notificationGroups || {}; 1207 items.notificationGroups = items.notificationGroups || {};
1226 items.notificationGroups['PUSH' + message.subchannelId] = { 1208 items.notificationGroups['PUSH' + message.subchannelId] = {
1227 cards: [], 1209 cards: [],
1228 nextPollTime: Date.now() 1210 nextPollTime: Date.now()
1229 }; 1211 };
1230 1212
1231 chrome.storage.local.set({ 1213 chrome.storage.local.set({
1232 lastPollNowPayloads: items.lastPollNowPayloads, 1214 lastPollNowPayloads: items.lastPollNowPayloads,
1233 notificationGroups: items.notificationGroups 1215 notificationGroups: items.notificationGroups
1234 }); 1216 });
1235 1217
1236 updateNotificationsCards(); 1218 updateNotificationsCards();
1237 } 1219 }
1238 }); 1220 });
1239 }); 1221 });
1240 } 1222 }
1241 }); 1223 });
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/google_now/background_unittest.gtestjs » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698