12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)'use strict'; 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @fileoverview The event page for Google Now for Chrome implementation. 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * The Google Now event page gets Google Now cards from the server and shows 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * them as Chrome notifications. 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * The service performs periodic updating of Google Now cards. 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Each updating of the cards includes 4 steps: 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * 1. Processing requests for cards dismissals that are not yet sent to the 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * server. 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * 2. Making a server request. 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * 3. Showing the received cards as notifications. 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// TODO(robliao): Decide what to do in incognito mode. 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Standard response code for successful HTTP requests. This is the only success 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * code the server will send. 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var HTTP_OK = 200; 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)var HTTP_NOCONTENT = 204; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvar HTTP_BAD_REQUEST = 400; 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvar HTTP_UNAUTHORIZED = 401; 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvar HTTP_FORBIDDEN = 403; 31ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvar HTTP_METHOD_NOT_ALLOWED = 405; 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)var MS_IN_SECOND = 1000; 344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)var MS_IN_MINUTE = 60 * 1000; 354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Initial period for polling for Google Now Notifications cards to use when the 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * period from the server is not available. 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)var INITIAL_POLLING_PERIOD_SECONDS = 5 * 60; // 5 minutes 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Mininal period for polling for Google Now Notifications cards. 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */ 454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)var MINIMUM_POLLING_PERIOD_SECONDS = 5 * 60; // 5 minutes 464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/** 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Maximal period for polling for Google Now Notifications cards to use when the 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * period from the server is not available. 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)var MAXIMUM_POLLING_PERIOD_SECONDS = 30 * 60; // 30 minutes 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/** 54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Initial period for polling for Google Now optin notification after push 55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * messaging indicates Google Now is enabled. 56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)var INITIAL_OPTIN_RECHECK_PERIOD_SECONDS = 60; // 1 minute 58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch/** 60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Maximum period for polling for Google Now optin notification after push 61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * messaging indicates Google Now is enabled. It is expected that the alarm 62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * will be stopped after this. 63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)var MAXIMUM_OPTIN_RECHECK_PERIOD_SECONDS = 16 * 60; // 16 minutes 65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch/** 6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * Initial period for retrying the server request for dismissing cards. 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)var INITIAL_RETRY_DISMISS_PERIOD_SECONDS = 60; // 1 minute 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)/** 7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * Maximum period for retrying the server request for dismissing cards. 7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) */ 7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)var MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS = 60 * 60; // 1 hour 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/** 77ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Time we keep retrying dismissals. 78ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch */ 79ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvar MAXIMUM_DISMISSAL_AGE_MS = 24 * 60 * 60 * 1000; // 1 day 80ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 81ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/** 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Time we keep dismissals after successful server dismiss requests. 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000; // 20 minutes 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * Default period for checking whether the user is opted in to Google Now. 880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) */ 890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)var DEFAULT_OPTIN_CHECK_PERIOD_SECONDS = 60 * 60 * 24 * 7; // 1 week 900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)/** 920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * URL to open when the user clicked on a link for the our notification 930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * settings. 940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) */ 950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)var SETTINGS_URL = 'https://support.google.com/chrome/?p=ib_google_now_welcome'; 960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)/** 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Number of cards that need an explanatory link. 990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) */ 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)var EXPLANATORY_CARDS_LINK_THRESHOLD = 4; 1010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 1020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)/** 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Names for tasks that can be created by the extension. 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var UPDATE_CARDS_TASK_NAME = 'update-cards'; 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var DISMISS_CARD_TASK_NAME = 'dismiss-card'; 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; 108a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)var STATE_CHANGED_TASK_NAME = 'state-changed'; 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)var SHOW_ON_START_TASK_NAME = 'show-cards-on-start'; 1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)var ON_PUSH_MESSAGE_START_TASK_NAME = 'on-push-message'; 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/** 113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Group as received from the server. 1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * 1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @typedef {{ 116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * nextPollSeconds: (string|undefined), 117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * rank: (number|undefined), 118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * requested: (boolean|undefined) 1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * }} 1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */ 121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)var ReceivedGroup; 122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)/** 124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Server response with notifications and groups. 125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * 126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @typedef {{ 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * googleNowDisabled: (boolean|undefined), 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * groups: Object.<string, ReceivedGroup>, 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * notifications: Array.<ReceivedNotification> 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * }} 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) */ 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)var ServerResponse; 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/** 1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Notification group as the client stores it. |cardsTimestamp| and |rank| are 1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * defined if |cards| is non-empty. |nextPollTime| is undefined if the server 1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * (1) never sent 'nextPollSeconds' for the group or 1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * (2) didn't send 'nextPollSeconds' with the last group update containing a 1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * cards update and all the times after that. 1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * 1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @typedef {{ 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * cards: Array.<ReceivedNotification>, 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * cardsTimestamp: (number|undefined), 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * nextPollTime: (number|undefined), 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * rank: (number|undefined) 1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * }} 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */ 148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)var StoredNotificationGroup; 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)/** 151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Pending (not yet successfully sent) dismissal for a received notification. 152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * |time| is the moment when the user requested dismissal. 153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @typedef {{ 155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * chromeNotificationId: ChromeNotificationId, 156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * time: number, 157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * dismissalData: DismissalData 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * }} 159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) */ 160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)var PendingDismissal; 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/** 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Checks if a new task can't be scheduled when another task is already 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * scheduled. 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {string} newTaskName Name of the new task. 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @param {string} scheduledTaskName Name of the scheduled task. 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {boolean} Whether the new task conflicts with the existing task. 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function areTasksConflicting(newTaskName, scheduledTaskName) { 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (newTaskName == UPDATE_CARDS_TASK_NAME && 171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scheduledTaskName == UPDATE_CARDS_TASK_NAME) { 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If a card update is requested while an old update is still scheduled, we 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // don't need the new update. 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (newTaskName == RETRY_DISMISS_TASK_NAME && 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (scheduledTaskName == UPDATE_CARDS_TASK_NAME || 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scheduledTaskName == DISMISS_CARD_TASK_NAME || 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scheduledTaskName == RETRY_DISMISS_TASK_NAME)) { 181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // No need to schedule retry-dismiss action if another action that tries to 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // send dismissals is scheduled. 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)var tasks = buildTaskManager(areTasksConflicting); 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Add error processing to API calls. 192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('metricsPrivate.getVariationParams', 1); 1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)wrapper.instrumentChromeApiFunction('notifications.clear', 1); 194424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('notifications.create', 2); 1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)wrapper.instrumentChromeApiFunction('notifications.getPermissionLevel', 0); 196424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('notifications.update', 2); 197424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('notifications.getAll', 0); 198424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction( 199ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 'notifications.onButtonClicked.addListener', 0); 200424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('notifications.onClicked.addListener', 0); 201424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0); 202424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction( 2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 'notifications.onPermissionLevelChanged.addListener', 0); 2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)wrapper.instrumentChromeApiFunction( 2050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 'notifications.onShowSettings.addListener', 0); 206424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('permissions.contains', 1); 2078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0); 208010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)wrapper.instrumentChromeApiFunction('storage.onChanged.addListener', 0); 209424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0); 210424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0); 211424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)wrapper.instrumentChromeApiFunction('tabs.create', 1); 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)var updateCardsAttempts = buildAttemptManager( 21490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 'cards-update', 215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) requestCards, 21690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) INITIAL_POLLING_PERIOD_SECONDS, 21790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAXIMUM_POLLING_PERIOD_SECONDS); 218010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)var optInPollAttempts = buildAttemptManager( 219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 'optin', 220010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) pollOptedInNoImmediateRecheck, 221010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) INITIAL_POLLING_PERIOD_SECONDS, 222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) MAXIMUM_POLLING_PERIOD_SECONDS); 223010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)var optInRecheckAttempts = buildAttemptManager( 224010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 'optin-recheck', 225010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) pollOptedInWithRecheck, 226010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) INITIAL_OPTIN_RECHECK_PERIOD_SECONDS, 227010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) MAXIMUM_OPTIN_RECHECK_PERIOD_SECONDS); 22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)var dismissalAttempts = buildAttemptManager( 22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 'dismiss', 23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) retryPendingDismissals, 23190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) INITIAL_RETRY_DISMISS_PERIOD_SECONDS, 23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS); 233558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvar cardSet = buildCardSet(); 23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 235a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)var authenticationManager = buildAuthenticationManager(); 236a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/** 238a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * Google Now UMA event identifier. 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @enum {number} 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 241a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)var GoogleNowEvent = { 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) REQUEST_FOR_CARDS_TOTAL: 0, 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) REQUEST_FOR_CARDS_SUCCESS: 1, 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CARDS_PARSE_SUCCESS: 2, 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DISMISS_REQUEST_TOTAL: 3, 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DISMISS_REQUEST_SUCCESS: 4, 24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) LOCATION_REQUEST: 5, 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DELETED_LOCATION_UPDATE: 6, 249eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EXTENSION_START: 7, 2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DELETED_SHOW_WELCOME_TOAST: 8, 251a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) STOPPED: 9, 2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) DELETED_USER_SUPPRESSED: 10, 253effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch SIGNED_OUT: 11, 254effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch NOTIFICATION_DISABLED: 12, 255effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch GOOGLE_NOW_DISABLED: 13, 256effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch EVENTS_TOTAL: 14 // EVENTS_TOTAL is not an event; all new events need to be 257a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // added before it. 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/** 261a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * Records a Google Now Event. 262a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * @param {GoogleNowEvent} event Event identifier. 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function recordEvent(event) { 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) var metricDescription = { 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) metricName: 'GoogleNow.Event', 267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) type: 'histogram-linear', 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) min: 1, 269a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) max: GoogleNowEvent.EVENTS_TOTAL, 270a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) buckets: GoogleNowEvent.EVENTS_TOTAL + 1 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) }; 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) chrome.metricsPrivate.recordValue(metricDescription, event); 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 277effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Records a notification clicked event. 278effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * @param {number|undefined} cardTypeId Card type ID. 279effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochfunction recordNotificationClick(cardTypeId) { 281effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (cardTypeId !== undefined) { 282effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chrome.metricsPrivate.recordSparseValue( 283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 'GoogleNow.Card.Clicked', cardTypeId); 284effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 285effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 286effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 287effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch/** 288effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Records a button clicked event. 289effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * @param {number|undefined} cardTypeId Card type ID. 290effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * @param {number} buttonIndex Button Index 291effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 292effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochfunction recordButtonClick(cardTypeId, buttonIndex) { 293effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (cardTypeId !== undefined) { 294effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chrome.metricsPrivate.recordSparseValue( 295effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 'GoogleNow.Card.Button.Clicked' + buttonIndex, cardTypeId); 296effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 297effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 298effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 299effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch/** 300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * Checks the result of the HTTP Request and updates the authentication 301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * manager on any failure. 302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * @param {string} token Authentication token to validate against an 303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * XMLHttpRequest. 304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * @return {function(XMLHttpRequest)} Function that validates the token with the 305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * supplied XMLHttpRequest. 306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */ 307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)function checkAuthenticationStatus(token) { 308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return function(request) { 309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (request.status == HTTP_FORBIDDEN || 310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request.status == HTTP_UNAUTHORIZED) { 311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) authenticationManager.removeToken(token); 312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)/** 317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * Builds and sends an authenticated request to the notification server. 318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * @param {string} method Request method. 319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * @param {string} handlerName Server handler to send the request to. 320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * @param {string=} opt_contentType Value for the Content-type header. 321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * @return {Promise} A promise to issue a request to the server. 322c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * The promise rejects if the response is not within the HTTP 200 range. 323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) */ 324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)function requestFromServer(method, handlerName, opt_contentType) { 325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return authenticationManager.getAuthToken().then(function(token) { 326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var request = buildServerRequest(method, handlerName, opt_contentType); 327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch request.setRequestHeader('Authorization', 'Bearer ' + token); 328c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch var requestPromise = new Promise(function(resolve, reject) { 329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request.addEventListener('loadend', function() { 330c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if ((200 <= request.status) && (request.status < 300)) { 331c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch resolve(request); 332c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } else { 333c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch reject(request); 334c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }, false); 336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) request.send(); 337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch }); 338c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch requestPromise.catch(checkAuthenticationStatus(token)); 339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return requestPromise; 340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch }); 341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/** 344c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Shows the notification groups as notification cards. 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * @param {Object.<string, StoredNotificationGroup>} notificationGroups Map from 3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * group name to group information. 347c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @param {function(ReceivedNotification)=} opt_onCardShown Optional parameter 348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * called when each card is shown. 349c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @return {Promise} A promise to show the notification groups as cards. 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 351c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochfunction showNotificationGroups(notificationGroups, opt_onCardShown) { 352a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** @type {Object.<ChromeNotificationId, CombinedCard>} */ 353c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch var cards = combineCardsFromGroups(notificationGroups); 354c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch console.log('showNotificationGroups ' + JSON.stringify(cards)); 355ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 356c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return new Promise(function(resolve) { 357c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch instrumented.notifications.getAll(function(notifications) { 358c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch console.log('showNotificationGroups-getAll ' + 359c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch JSON.stringify(notifications)); 360c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch notifications = notifications || {}; 361c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 362c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Mark notifications that didn't receive an update as having received 363c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // an empty update. 364c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch for (var chromeNotificationId in notifications) { 365c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch cards[chromeNotificationId] = cards[chromeNotificationId] || []; 366c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 367ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 368a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** @type {Object.<ChromeNotificationId, NotificationDataEntry>} */ 369c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch var notificationsData = {}; 370c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 371c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Create/update/delete notifications. 372c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch for (var chromeNotificationId in cards) { 373c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch notificationsData[chromeNotificationId] = cardSet.update( 374c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch chromeNotificationId, 375c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch cards[chromeNotificationId], 376c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch notificationGroups, 377c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch opt_onCardShown); 378c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 379c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch chrome.storage.local.set({notificationsData: notificationsData}); 380c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch resolve(); 381c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch }); 382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) }); 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 386a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * Removes all cards and card state on Google Now close down. 387a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) */ 388a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)function removeAllCards() { 389a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) console.log('removeAllCards'); 390a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 391a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // TODO(robliao): Once Google Now clears its own checkbox in the 392a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // notifications center and bug 260376 is fixed, the below clearing 393a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // code is no longer necessary. 394ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch instrumented.notifications.getAll(function(notifications) { 3953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) notifications = notifications || {}; 3964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (var chromeNotificationId in notifications) { 3974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) instrumented.notifications.clear(chromeNotificationId, function() {}); 398a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 3994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) chrome.storage.local.remove(['notificationsData', 'notificationGroups']); 4004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) }); 4014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 4024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/** 404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * Adds a card group into a set of combined cards. 405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {Object.<ChromeNotificationId, CombinedCard>} combinedCards Map from 406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * chromeNotificationId to a combined card. 407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * This is an input/output parameter. 408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {StoredNotificationGroup} storedGroup Group to combine into the 409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * combined card set. 4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */ 411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)function combineGroup(combinedCards, storedGroup) { 412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (var i = 0; i < storedGroup.cards.length; i++) { 413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /** @type {ReceivedNotification} */ 414a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var receivedNotification = storedGroup.cards[i]; 415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /** @type {UncombinedNotification} */ 417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var uncombinedNotification = { 418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) receivedNotification: receivedNotification, 419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) showTime: receivedNotification.trigger.showTimeSec && 420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) (storedGroup.cardsTimestamp + 421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) receivedNotification.trigger.showTimeSec * MS_IN_SECOND), 422a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hideTime: storedGroup.cardsTimestamp + 423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) receivedNotification.trigger.hideTimeSec * MS_IN_SECOND 4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) }; 4254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var combinedCard = 427a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) combinedCards[receivedNotification.chromeNotificationId] || []; 428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) combinedCard.push(uncombinedNotification); 429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) combinedCards[receivedNotification.chromeNotificationId] = combinedCard; 4304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 4324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/** 434010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * Calculates the soonest poll time from a map of groups as an absolute time. 435a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {Object.<string, StoredNotificationGroup>} groups Map from group name 436a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * to group information. 437010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @return {number} The next poll time based off of the groups. 4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */ 439010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)function calculateNextPollTimeMilliseconds(groups) { 440010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) var nextPollTime = null; 441010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 442010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) for (var groupName in groups) { 443010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) var group = groups[groupName]; 444010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (group.nextPollTime !== undefined) { 445010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) nextPollTime = nextPollTime == null ? 446010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) group.nextPollTime : Math.min(group.nextPollTime, nextPollTime); 4471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 448010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 4494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 450010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // At least one of the groups must have nextPollTime. 451010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) verify(nextPollTime != null, 'calculateNextPollTime: nextPollTime is null'); 452010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return nextPollTime; 453010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 455010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)/** 456010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * Schedules next cards poll. 457010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {Object.<string, StoredNotificationGroup>} groups Map from group name 458010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * to group information. 459010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) */ 460010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)function scheduleNextCardsPoll(groups) { 461010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) var nextPollTimeMs = calculateNextPollTimeMilliseconds(groups); 462010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 463010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) var nextPollDelaySeconds = Math.max( 464010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) (nextPollTimeMs - Date.now()) / MS_IN_SECOND, 465010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) MINIMUM_POLLING_PERIOD_SECONDS); 466010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) updateCardsAttempts.start(nextPollDelaySeconds); 467010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 468010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 469010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)/** 470010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * Schedules the next opt-in check poll. 471010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) */ 472010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)function scheduleOptInCheckPoll() { 473010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) instrumented.metricsPrivate.getVariationParams( 474010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 'GoogleNow', function(params) { 475010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) var optinPollPeriodSeconds = 476010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) parseInt(params && params.optinPollPeriodSeconds, 10) || 477010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DEFAULT_OPTIN_CHECK_PERIOD_SECONDS; 478010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) optInPollAttempts.start(optinPollPeriodSeconds); 479010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) }); 4804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 4814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/** 483c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Combines notification groups into a set of Chrome notifications. 484a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {Object.<string, StoredNotificationGroup>} notificationGroups Map from 485a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * group name to group information. 486c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @return {Object.<ChromeNotificationId, CombinedCard>} Cards to show. 4874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */ 488c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochfunction combineCardsFromGroups(notificationGroups) { 489c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch console.log('combineCardsFromGroups ' + JSON.stringify(notificationGroups)); 490a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /** @type {Object.<ChromeNotificationId, CombinedCard>} */ 491a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var combinedCards = {}; 4924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (var groupName in notificationGroups) 494a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) combineGroup(combinedCards, notificationGroups[groupName]); 4954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 496c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return combinedCards; 4974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 4984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/** 500c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Processes a server response for consumption by showNotificationGroups. 5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * @param {ServerResponse} response Server response. 502c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @return {Promise} A promise to process the server response and provide 503c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * updated groups. Rejects if the server response shouldn't be processed. 5044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */ 505c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochfunction processServerResponse(response) { 5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) console.log('processServerResponse ' + JSON.stringify(response)); 5074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (response.googleNowDisabled) { 5090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) chrome.storage.local.set({googleNowEnabled: false}); 510a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Stop processing now. The state change will clear the cards. 511a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return Promise.reject(); 5120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) } 5130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var receivedGroups = response.groups; 5154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 516c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return fillFromChromeLocalStorage({ 517a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** @type {Object.<string, StoredNotificationGroup>} */ 518a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) notificationGroups: {}, 519a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** @type {Object.<ServerNotificationId, number>} */ 520a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) recentDismissals: {} 521a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }).then(function(items) { 522a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) console.log('processServerResponse-get ' + JSON.stringify(items)); 523a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 524a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Build a set of non-expired recent dismissals. It will be used for 525a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // client-side filtering of cards. 526a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** @type {Object.<ServerNotificationId, number>} */ 527a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var updatedRecentDismissals = {}; 528a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var now = Date.now(); 529a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch for (var serverNotificationId in items.recentDismissals) { 530a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch var dismissalAge = now - items.recentDismissals[serverNotificationId]; 531a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (dismissalAge < DISMISS_RETENTION_TIME_MS) { 532a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch updatedRecentDismissals[serverNotificationId] = 533a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch items.recentDismissals[serverNotificationId]; 534a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 535a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 5364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 537a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Populate groups with corresponding cards. 538a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (response.notifications) { 539a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (var i = 0; i < response.notifications.length; ++i) { 540a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** @type {ReceivedNotification} */ 541a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var card = response.notifications[i]; 542a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!(card.notificationId in updatedRecentDismissals)) { 543a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var group = receivedGroups[card.groupName]; 544a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) group.cards = group.cards || []; 545a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) group.cards.push(card); 546a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 547a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 548a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 5494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 550a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Build updated set of groups. 551a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var updatedGroups = {}; 552a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 553a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (var groupName in receivedGroups) { 554a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var receivedGroup = receivedGroups[groupName]; 555a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var storedGroup = items.notificationGroups[groupName] || { 556a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) cards: [], 557a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) cardsTimestamp: undefined, 558a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) nextPollTime: undefined, 559a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) rank: undefined 560a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }; 561a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 562a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (receivedGroup.requested) 563a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) receivedGroup.cards = receivedGroup.cards || []; 564a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 565a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (receivedGroup.cards) { 566a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If the group contains a cards update, all its fields will get new 567a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // values. 568a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) storedGroup.cards = receivedGroup.cards; 569a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) storedGroup.cardsTimestamp = now; 570a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) storedGroup.rank = receivedGroup.rank; 571a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) storedGroup.nextPollTime = undefined; 572a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The code below assigns nextPollTime a defined value if 573a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // nextPollSeconds is specified in the received group. 574a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If the group's cards are not updated, and nextPollSeconds is 575a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // unspecified, this method doesn't change group's nextPollTime. 576a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 5774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 578a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // 'nextPollSeconds' may be sent even for groups that don't contain 579a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // cards updates. 580a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (receivedGroup.nextPollSeconds !== undefined) { 581a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) storedGroup.nextPollTime = 582a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) now + receivedGroup.nextPollSeconds * MS_IN_SECOND; 583a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 5844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 585a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) updatedGroups[groupName] = storedGroup; 586a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 5874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 588010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) scheduleNextCardsPoll(updatedGroups); 589c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return { 590c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch updatedGroups: updatedGroups, 591c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch recentDismissals: updatedRecentDismissals 592c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch }; 593a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 594a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 595a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 596a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)/** 5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Update the Explanatory Total Cards Shown Count. 5980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) */ 5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)function countExplanatoryCard() { 6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) localStorage['explanatoryCardsShown']++; 6010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 6020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 6030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)/** 604c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Determines if cards should have an explanation link. 605c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @return {boolean} true if an explanatory card should be shown. 606c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch */ 607c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochfunction shouldShowExplanatoryCard() { 608c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch var isBelowThreshold = 609c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch localStorage['explanatoryCardsShown'] < EXPLANATORY_CARDS_LINK_THRESHOLD; 610c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return isBelowThreshold; 611c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 612c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 613c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch/** 6148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * Requests notification cards from the server for specified groups. 6158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) * @param {Array.<string>} groupNames Names of groups that need to be refreshed. 616c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @return {Promise} A promise to request the specified notification groups. 6178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) */ 618c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochfunction requestNotificationGroupsFromServer(groupNames) { 619c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch console.log( 620c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 'requestNotificationGroupsFromServer from ' + NOTIFICATION_CARDS_URL + 6218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ', groupNames=' + JSON.stringify(groupNames)); 6228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 6238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL); 6248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 6258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) var requestParameters = '?timeZoneOffsetMs=' + 6260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) (-new Date().getTimezoneOffset() * MS_IN_MINUTE); 6270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 628c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (shouldShowExplanatoryCard()) { 6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) requestParameters += '&cardExplanation=true'; 6300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) } 6318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 6328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) groupNames.forEach(function(groupName) { 6338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) requestParameters += ('&requestTypes=' + groupName); 6348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) }); 6358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 636a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) requestParameters += '&uiLocale=' + navigator.language; 6378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 638c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch console.log( 639c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 'requestNotificationGroupsFromServer: request=' + requestParameters); 6400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 641c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return requestFromServer('GET', 'notifications' + requestParameters).then( 642a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) function(request) { 643c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch console.log( 644c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 'requestNotificationGroupsFromServer-received ' + request.status); 645a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (request.status == HTTP_OK) { 646a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS); 647c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return JSON.parse(request.responseText); 648a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 649a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 6500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 6510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 6520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)/** 653010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * Performs an opt-in poll without an immediate recheck. 654010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * If the response is not opted-in, schedule an opt-in check poll. 655010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) */ 656010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)function pollOptedInNoImmediateRecheck() { 657010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) requestAndUpdateOptedIn() 658010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) .then(function(optedIn) { 659010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!optedIn) { 660010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Request a repoll if we're not opted in. 661010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return Promise.reject(); 662010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 663010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) }) 664010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) .catch(function() { 665010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) scheduleOptInCheckPoll(); 666010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) }); 667010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 668010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 669010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)/** 670c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Requests the account opted-in state from the server and updates any 671c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * state as necessary. 672c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @return {Promise} A promise to request and update the opted-in state. 673010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * The promise resolves with the opt-in state. 6740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) */ 675c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochfunction requestAndUpdateOptedIn() { 6760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL); 6770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 678c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return requestFromServer('GET', 'settings/optin').then(function(request) { 6790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) console.log( 680a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'requestOptedIn-received ' + request.status + ' ' + request.response); 6810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (request.status == HTTP_OK) { 682a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var parsedResponse = JSON.parse(request.responseText); 683c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return parsedResponse.value; 684c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 685c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch }).then(function(optedIn) { 686010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) chrome.storage.local.set({googleNowEnabled: optedIn}); 687010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return optedIn; 6888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) }); 6898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 6908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 6918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)/** 692c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Determines the groups that need to be requested right now. 693c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @return {Promise} A promise to determine the groups to request. 6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 695c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochfunction getGroupsToRequest() { 696c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return fillFromChromeLocalStorage({ 697a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /** @type {Object.<string, StoredNotificationGroup>} */ 698c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch notificationGroups: {} 699a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }).then(function(items) { 700c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch console.log('getGroupsToRequest-storage-get ' + JSON.stringify(items)); 7018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) var groupsToRequest = []; 702a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var now = Date.now(); 7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 704a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (var groupName in items.notificationGroups) { 705a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var group = items.notificationGroups[groupName]; 706a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (group.nextPollTime !== undefined && group.nextPollTime <= now) 707a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) groupsToRequest.push(groupName); 708eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 709c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return groupsToRequest; 710c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch }); 711c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 7124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 713c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch/** 714c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Requests notification cards from the server. 715c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @return {Promise} A promise to request the notification cards. 716c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Rejects if the cards won't be requested. 717c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch */ 718c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochfunction requestNotificationCards() { 719c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch console.log('requestNotificationCards'); 720010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return getGroupsToRequest() 721c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch .then(requestNotificationGroupsFromServer) 722c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch .then(processServerResponse) 723c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch .then(function(processedResponse) { 724c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch var onCardShown = 725c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch shouldShowExplanatoryCard() ? countExplanatoryCard : undefined; 726c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return showNotificationGroups( 727c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch processedResponse.updatedGroups, onCardShown).then(function() { 728c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch chrome.storage.local.set({ 729c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch notificationGroups: processedResponse.updatedGroups, 730c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch recentDismissals: processedResponse.updatedRecentDismissals 731c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch }); 732c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS); 733c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 734c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch ); 7350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) }); 7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 7395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * Determines if an immediate retry should occur based off of the given groups. 7405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * The NOR group is expected most often and less latency sensitive, so we will 7415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * simply wait MAXIMUM_POLLING_PERIOD_SECONDS before trying again. 7425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @param {Array.<string>} groupNames Names of groups that need to be refreshed. 7435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @return {boolean} Whether a retry should occur. 7445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */ 7455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)function shouldScheduleRetryFromGroupList(groupNames) { 7465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return (groupNames.length != 1) || (groupNames[0] !== 'NOR'); 7475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 7485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 7495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/** 750a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * Requests and shows notification cards. 7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 752a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)function requestCards() { 753a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) console.log('requestCards @' + new Date()); 754a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // LOCATION_REQUEST is a legacy histogram value when we requested location. 755a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // This corresponds to the extension attempting to request for cards. 756a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // We're keeping the name the same to keep our histograms in order. 757a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) recordEvent(GoogleNowEvent.LOCATION_REQUEST); 7584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tasks.add(UPDATE_CARDS_TASK_NAME, function() { 759a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) console.log('requestCards-task-begin'); 760a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) updateCardsAttempts.isRunning(function(running) { 761a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (running) { 762010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // The cards are requested only if there are no unsent dismissals. 763010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) processPendingDismissals() 764010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) .then(requestNotificationCards) 7655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) .catch(function() { 7665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return getGroupsToRequest().then(function(groupsToRequest) { 7675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (shouldScheduleRetryFromGroupList(groupsToRequest)) { 7685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) updateCardsAttempts.scheduleRetry(); 7695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 7705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) }); 7715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) }); 772a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }); 7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }); 7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 778c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Sends a server request to dismiss a card. 779a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of 780a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * the card. 781c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @param {number} dismissalTimeMs Time of the user's dismissal of the card in 782c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * milliseconds since epoch. 7834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DismissalData} dismissalData Data to build a dismissal request. 784a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * @return {Promise} A promise to request the card dismissal, rejects on error. 785c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 786c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function requestCardDismissal( 787a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) chromeNotificationId, dismissalTimeMs, dismissalData) { 788a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) console.log('requestDismissingCard ' + chromeNotificationId + 789a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ' from ' + NOTIFICATION_CARDS_URL + 790a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ', dismissalData=' + JSON.stringify(dismissalData)); 791ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 792ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch var dismissalAge = Date.now() - dismissalTimeMs; 793ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 794ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (dismissalAge > MAXIMUM_DISMISSAL_AGE_MS) { 79523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return Promise.resolve(); 796ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 797ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 798a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) recordEvent(GoogleNowEvent.DISMISS_REQUEST_TOTAL); 7994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 800a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) var requestParameters = 'notifications/' + dismissalData.notificationId + 8014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) '?age=' + dismissalAge + 8024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) '&chromeNotificationId=' + chromeNotificationId; 8034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 8044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (var paramField in dismissalData.parameters) 805a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) requestParameters += ('&' + paramField + 806a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) '=' + dismissalData.parameters[paramField]); 8074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 808a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) console.log('requestCardDismissal: requestParameters=' + requestParameters); 8094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 810a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return requestFromServer('DELETE', requestParameters).then(function(request) { 811c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) console.log('requestDismissingCard-onloadend ' + request.status); 8124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (request.status == HTTP_NOCONTENT) 813a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) recordEvent(GoogleNowEvent.DISMISS_REQUEST_SUCCESS); 814c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 815ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // A dismissal doesn't require further retries if it was successful or 816ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // doesn't have a chance for successful completion. 817c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return (request.status == HTTP_NOCONTENT) ? 818c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch Promise.resolve() : 819c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch Promise.reject(); 820c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch }).catch(function(request) { 8216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) request = (typeof request === 'object') ? request : {}; 822c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return (request.status == HTTP_BAD_REQUEST || 823c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch request.status == HTTP_METHOD_NOT_ALLOWED) ? 824c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch Promise.resolve() : 825c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch Promise.reject(); 826eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch }); 827c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 828c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 829c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/** 830c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Tries to send dismiss requests for all pending dismissals. 831a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * @return {Promise} A promise to process the pending dismissals. 832a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * The promise is rejected if a problem was encountered. 833c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 834a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)function processPendingDismissals() { 835a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return fillFromChromeLocalStorage({ 836a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** @type {Array.<PendingDismissal>} */ 837a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pendingDismissals: [], 838a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** @type {Object.<ServerNotificationId, number>} */ 839a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) recentDismissals: {} 840a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }).then(function(items) { 841a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) console.log( 842a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'processPendingDismissals-storage-get ' + JSON.stringify(items)); 843c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 844a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var dismissalsChanged = false; 845c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 846a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) function onFinish(success) { 847a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (dismissalsChanged) { 848a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) chrome.storage.local.set({ 849a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pendingDismissals: items.pendingDismissals, 850a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) recentDismissals: items.recentDismissals 851a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 852a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 853a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return success ? Promise.resolve() : Promise.reject(); 854a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 855a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 856a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) function doProcessDismissals() { 857a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (items.pendingDismissals.length == 0) { 858a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) dismissalAttempts.stop(); 859a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return onFinish(true); 860a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 861a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 862a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Send dismissal for the first card, and if successful, repeat 863a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // recursively with the rest. 864a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** @type {PendingDismissal} */ 865a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var dismissal = items.pendingDismissals[0]; 866a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return requestCardDismissal( 867a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) dismissal.chromeNotificationId, 868a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) dismissal.time, 869a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) dismissal.dismissalData).then(function() { 870a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) dismissalsChanged = true; 871a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) items.pendingDismissals.splice(0, 1); 872a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) items.recentDismissals[dismissal.dismissalData.notificationId] = 873a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Date.now(); 874a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return doProcessDismissals(); 875a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }).catch(function() { 876a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return onFinish(false); 877a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 878a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 879a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 880a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return doProcessDismissals(); 881a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 882c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 883c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 884c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/** 885c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Submits a task to send pending dismissals. 886c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 887c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function retryPendingDismissals() { 8884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tasks.add(RETRY_DISMISS_TASK_NAME, function() { 889010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) processPendingDismissals().catch(dismissalAttempts.scheduleRetry); 890c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) }); 891c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 892c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 893c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/** 8940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * Opens a URL in a new tab. 8950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * @param {string} url URL to open. 8960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) */ 8970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)function openUrl(url) { 8980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) instrumented.tabs.create({url: url}, function(tab) { 8990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (tab) 9000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) chrome.windows.update(tab.windowId, {focused: true}); 9010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) else 9020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) chrome.windows.create({url: url, focused: true}); 9030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) }); 9040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 9050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 9060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)/** 9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Opens URL corresponding to the clicked part of the notification. 908a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of 909a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * the card. 910effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * @param {function(NotificationDataEntry): (string|undefined)} selector 911effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Function that extracts the url for the clicked area from the 912effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * notification data entry. 9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 9144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)function onNotificationClicked(chromeNotificationId, selector) { 915a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) fillFromChromeLocalStorage({ 916a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** @type {Object.<ChromeNotificationId, NotificationDataEntry>} */ 917a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) notificationsData: {} 918a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }).then(function(items) { 919a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /** @type {(NotificationDataEntry|undefined)} */ 920effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var notificationDataEntry = items.notificationsData[chromeNotificationId]; 921effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!notificationDataEntry) 922868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 924effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var url = selector(notificationDataEntry); 9253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (!url) 926868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return; 927868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 9280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) openUrl(url); 9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }); 9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 9312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Callback for chrome.notifications.onClosed event. 934a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of 935a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) * the card. 9362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean} byUser Whether the notification was closed by the user. 9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 9384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)function onNotificationClosed(chromeNotificationId, byUser) { 9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!byUser) 9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 942eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // At this point we are guaranteed that the notification is a now card. 943c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed'); 944c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 9454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tasks.add(DISMISS_CARD_TASK_NAME, function() { 94690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) dismissalAttempts.start(); 947c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 948a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) fillFromChromeLocalStorage({ 949a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** @type {Array.<PendingDismissal>} */ 950a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) pendingDismissals: [], 951a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch /** @type {Object.<ChromeNotificationId, NotificationDataEntry>} */ 952a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) notificationsData: {}, 953a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** @type {Object.<string, StoredNotificationGroup>} */ 954a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) notificationGroups: {} 955a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }).then(function(items) { 956a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** @type {NotificationDataEntry} */ 957a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var notificationData = 958a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) items.notificationsData[chromeNotificationId] || 959a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) { 960a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) timestamp: Date.now(), 961a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) combinedCard: [] 962a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }; 963a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 964a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var dismissalResult = 965a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) cardSet.onDismissal( 966a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) chromeNotificationId, 967a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) notificationData, 968a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) items.notificationGroups); 969a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 970a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (var i = 0; i < dismissalResult.dismissals.length; i++) { 971a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** @type {PendingDismissal} */ 972a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) var dismissal = { 973a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) chromeNotificationId: chromeNotificationId, 974a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) time: Date.now(), 975a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) dismissalData: dismissalResult.dismissals[i] 976a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }; 977a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) items.pendingDismissals.push(dismissal); 978a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 979a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 980a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) items.notificationsData[chromeNotificationId] = 981a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) dismissalResult.notificationData; 982a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 983a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) chrome.storage.local.set(items); 984a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 985a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) processPendingDismissals(); 986a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 9872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }); 9882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 9892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 9902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 991a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * Initializes the polling system to start fetching cards. 9922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 993eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochfunction startPollingCards() { 994a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) console.log('startPollingCards'); 995a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Create an update timer for a case when for some reason requesting 996a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // cards gets stuck. 99790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) updateCardsAttempts.start(MAXIMUM_POLLING_PERIOD_SECONDS); 998a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) requestCards(); 9992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 10002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1001eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/** 1002a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * Stops all machinery in the polling system. 1003a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) */ 1004a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)function stopPollingCards() { 1005a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) console.log('stopPollingCards'); 1006a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) updateCardsAttempts.stop(); 1007a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // Since we're stopping everything, clear all runtime storage. 1008c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // We don't clear localStorage since those values are still relevant 1009c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // across Google Now start-stop events. 1010c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch chrome.storage.local.clear(); 1011a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 1012a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1013a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)/** 1014eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Initializes the event page on install or on browser startup. 1015eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */ 1016eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochfunction initialize() { 1017a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) recordEvent(GoogleNowEvent.EXTENSION_START); 1018a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) onStateChange(); 1019a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 1020a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1021a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)/** 1022a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch * Starts or stops the main pipeline for polling cards. 1023a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * @param {boolean} shouldPollCardsRequest true to start and 1024a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * false to stop polling cards. 1025a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) */ 10264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)function setShouldPollCards(shouldPollCardsRequest) { 1027a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) updateCardsAttempts.isRunning(function(currentValue) { 1028a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (shouldPollCardsRequest != currentValue) { 1029a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) console.log('Action Taken setShouldPollCards=' + shouldPollCardsRequest); 1030a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (shouldPollCardsRequest) 1031a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) startPollingCards(); 1032a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) else 1033a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) stopPollingCards(); 1034ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } else { 1035ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch console.log( 1036ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 'Action Ignored setShouldPollCards=' + shouldPollCardsRequest); 1037a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 1038a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) }); 1039a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 1040a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1041a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)/** 1042010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * Starts or stops the optin check. 1043010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {boolean} shouldPollOptInStatus true to start and false to stop 1044010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * polling the optin status. 1045010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) */ 1046010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)function setShouldPollOptInStatus(shouldPollOptInStatus) { 1047010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) optInPollAttempts.isRunning(function(currentValue) { 1048010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (shouldPollOptInStatus != currentValue) { 1049010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) console.log( 1050010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 'Action Taken setShouldPollOptInStatus=' + shouldPollOptInStatus); 1051010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (shouldPollOptInStatus) { 1052010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) pollOptedInNoImmediateRecheck(); 1053010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } else { 1054010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) optInPollAttempts.stop(); 1055010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 1056010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } else { 1057010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) console.log( 1058010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 'Action Ignored setShouldPollOptInStatus=' + shouldPollOptInStatus); 1059010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 1060010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) }); 1061010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 1062010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 1063010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)/** 10643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * Enables or disables the Google Now background permission. 10653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * @param {boolean} backgroundEnable true to run in the background. 10663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * false to not run in the background. 10673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */ 10684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)function setBackgroundEnable(backgroundEnable) { 10693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) instrumented.permissions.contains({permissions: ['background']}, 10703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) function(hasPermission) { 10713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (backgroundEnable != hasPermission) { 10723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) console.log('Action Taken setBackgroundEnable=' + backgroundEnable); 10733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (backgroundEnable) 10744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) chrome.permissions.request({permissions: ['background']}); 10753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) else 10764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) chrome.permissions.remove({permissions: ['background']}); 10773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } else { 10783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) console.log('Action Ignored setBackgroundEnable=' + backgroundEnable); 10793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 10803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) }); 10813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 10823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 10833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)/** 1084effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Record why this extension would not poll for cards. 1085effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * @param {boolean} signedIn true if the user is signed in. 1086effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * @param {boolean} notificationEnabled true if 1087effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Google Now for Chrome is allowed to show notifications. 1088effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * @param {boolean} googleNowEnabled true if 1089effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * the Google Now is enabled for the user. 1090effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 1091effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochfunction recordEventIfNoCards(signedIn, notificationEnabled, googleNowEnabled) { 1092effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!signedIn) { 1093effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch recordEvent(GoogleNowEvent.SIGNED_OUT); 1094effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } else if (!notificationEnabled) { 1095effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch recordEvent(GoogleNowEvent.NOTIFICATION_DISABLED); 1096effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } else if (!googleNowEnabled) { 1097effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch recordEvent(GoogleNowEvent.GOOGLE_NOW_DISABLED); 1098effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 1099effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 1100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 1101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch/** 1102a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * Does the actual work of deciding what Google Now should do 1103a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * based off of the current state of Chrome. 1104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * @param {boolean} signedIn true if the user is signed in. 11050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * @param {boolean} canEnableBackground true if 11060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * the background permission can be requested. 11071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * @param {boolean} notificationEnabled true if 11081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * Google Now for Chrome is allowed to show notifications. 11090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * @param {boolean} googleNowEnabled true if 11100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * the Google Now is enabled for the user. 1111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) */ 1112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)function updateRunningState( 1113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) signedIn, 11140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) canEnableBackground, 11150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) notificationEnabled, 11160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) googleNowEnabled) { 1117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) console.log( 1118a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 'State Update signedIn=' + signedIn + ' ' + 11190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 'canEnableBackground=' + canEnableBackground + ' ' + 11200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 'notificationEnabled=' + notificationEnabled + ' ' + 11210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 'googleNowEnabled=' + googleNowEnabled); 11224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) var shouldPollCards = false; 1124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) var shouldPollOptInStatus = false; 11253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) var shouldSetBackground = false; 1126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 11271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (signedIn && notificationEnabled) { 1128010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) shouldPollCards = googleNowEnabled; 1129010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) shouldPollOptInStatus = !googleNowEnabled; 1130a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch shouldSetBackground = canEnableBackground && googleNowEnabled; 1131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 1132a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) recordEvent(GoogleNowEvent.STOPPED); 1133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 1134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch recordEventIfNoCards(signedIn, notificationEnabled, googleNowEnabled); 1136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 1137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) console.log( 11383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 'Requested Actions shouldSetBackground=' + shouldSetBackground + ' ' + 1139a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 'setShouldPollCards=' + shouldPollCards + ' ' + 1140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 'shouldPollOptInStatus=' + shouldPollOptInStatus); 1141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 11424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) setBackgroundEnable(shouldSetBackground); 11434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) setShouldPollCards(shouldPollCards); 1144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) setShouldPollOptInStatus(shouldPollOptInStatus); 1145010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!shouldPollCards) { 1146a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch removeAllCards(); 1147a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 1148a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 1149a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)/** 1151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * Coordinates the behavior of Google Now for Chrome depending on 1152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) * Chrome and extension state. 1153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) */ 1154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)function onStateChange() { 11554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tasks.add(STATE_CHANGED_TASK_NAME, function() { 11565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Promise.all([ 1157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) authenticationManager.isSignedIn(), 11585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) canEnableBackground(), 11595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) isNotificationsEnabled(), 11605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) isGoogleNowEnabled()]) 11615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) .then(function(results) { 11625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) updateRunningState.apply(null, results); 11635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }); 11645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }); 11655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 11665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 11675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/** 11685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Determines if background mode should be requested. 11695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * @return {Promise} A promise to determine if background can be enabled. 11705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 11715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)function canEnableBackground() { 11725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return new Promise(function(resolve) { 11735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instrumented.metricsPrivate.getVariationParams( 11745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 'GoogleNow', 11755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) function(response) { 11765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) resolve(!response || (response.canEnableBackground != 'false')); 11775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }); 11785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }); 11795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 11805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 11815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/** 11825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Checks if Google Now is enabled in the notifications center. 11835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * @return {Promise} A promise to determine if Google Now is enabled 11845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * in the notifications center. 11855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 11865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)function isNotificationsEnabled() { 11875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return new Promise(function(resolve) { 11885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instrumented.notifications.getPermissionLevel(function(level) { 11895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) resolve(level == 'granted'); 11905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }); 11915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }); 11925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 11935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 11945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/** 11955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Gets the previous Google Now opt-in state. 11965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * @return {Promise} A promise to determine the previous Google Now 11975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * opt-in state. 11985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 11995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)function isGoogleNowEnabled() { 1200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return fillFromChromeLocalStorage({googleNowEnabled: false}) 1201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) .then(function(items) { 1202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return items.googleNowEnabled; 1203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }); 1204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 1205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch/** 1207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Polls the optin state. 1208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Sometimes we get the response to the opted in result too soon during 1209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * push messaging. We'll recheck the optin state a few times before giving up. 1210effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 1211010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)function pollOptedInWithRecheck() { 1212effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch /** 1213effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Cleans up any state used to recheck the opt-in poll. 1214effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */ 1215effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch function clearPollingState() { 1216effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch localStorage.removeItem('optedInCheckCount'); 1217010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) optInRecheckAttempts.stop(); 1218effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 1219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 1220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (localStorage.optedInCheckCount === undefined) { 1221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch localStorage.optedInCheckCount = 0; 1222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) optInRecheckAttempts.start(); 1223c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 1224c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 1225c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch console.log(new Date() + 1226c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch ' checkOptedIn Attempt ' + localStorage.optedInCheckCount); 1227c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 1228010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) requestAndUpdateOptedIn().then(function(optedIn) { 1229010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (optedIn) { 1230010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) clearPollingState(); 1231010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return Promise.resolve(); 1232010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } else { 1233010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // If we're not opted in, reject to retry. 1234010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return Promise.reject(); 1235010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 1236c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch }).catch(function() { 1237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (localStorage.optedInCheckCount < 5) { 1238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch localStorage.optedInCheckCount++; 1239010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) optInRecheckAttempts.scheduleRetry(); 1240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } else { 1241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch clearPollingState(); 1242effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 1243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch }); 1244effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 1245effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 1246ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochinstrumented.runtime.onInstalled.addListener(function(details) { 1247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) console.log('onInstalled ' + JSON.stringify(details)); 1248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (details.reason != 'chrome_update') { 12492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) initialize(); 1250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 12512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}); 12522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1253ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochinstrumented.runtime.onStartup.addListener(function() { 1254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) console.log('onStartup'); 12554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 12564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Show notifications received by earlier polls. Doing this as early as 12574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // possible to reduce latency of showing first notifications. This mimics how 12584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // persistent notifications will work. 12594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) tasks.add(SHOW_ON_START_TASK_NAME, function() { 1260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) fillFromChromeLocalStorage({ 1261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) /** @type {Object.<string, StoredNotificationGroup>} */ 1262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) notificationGroups: {} 1263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }).then(function(items) { 1264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) console.log('onStartup-get ' + JSON.stringify(items)); 12654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1266c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch showNotificationGroups(items.notificationGroups).then(function() { 12675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chrome.storage.local.set(items); 12685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }); 12694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) }); 12704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) }); 12714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 12722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) initialize(); 12732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}); 12742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1275a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)authenticationManager.addListener(function() { 1276a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) console.log('signIn State Change'); 1277a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) onStateChange(); 1278a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}); 1279a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1280ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochinstrumented.notifications.onClicked.addListener( 12814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) function(chromeNotificationId) { 1282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) chrome.metricsPrivate.recordUserAction('GoogleNow.MessageClicked'); 1283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch onNotificationClicked(chromeNotificationId, 1284effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch function(notificationDataEntry) { 1285effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var actionUrls = notificationDataEntry.actionUrls; 1286effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var url = actionUrls && actionUrls.messageUrl; 1287effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (url) { 1288effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch recordNotificationClick(notificationDataEntry.cardTypeId); 1289effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 1290effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return url; 1291effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch }); 1292effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch }); 12932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1294ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochinstrumented.notifications.onButtonClicked.addListener( 12954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) function(chromeNotificationId, buttonIndex) { 12964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) chrome.metricsPrivate.recordUserAction( 12974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 'GoogleNow.ButtonClicked' + buttonIndex); 1298effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch onNotificationClicked(chromeNotificationId, 1299effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch function(notificationDataEntry) { 1300effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var actionUrls = notificationDataEntry.actionUrls; 1301effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch var url = actionUrls.buttonUrls[buttonIndex]; 1302effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (url) { 1303effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch recordButtonClick(notificationDataEntry.cardTypeId, buttonIndex); 1304effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } else { 1305effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch verify(false, 'onButtonClicked: no url for a button'); 130646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) console.log( 130746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 'buttonIndex=' + buttonIndex + ' ' + 130846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 'chromeNotificationId=' + chromeNotificationId + ' ' + 130946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 'notificationDataEntry=' + 131046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) JSON.stringify(notificationDataEntry)); 1311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 1312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return url; 1313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch }); 1314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch }); 13152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1316ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochinstrumented.notifications.onClosed.addListener(onNotificationClosed); 1317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 13181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)instrumented.notifications.onPermissionLevelChanged.addListener( 13191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) function(permissionLevel) { 13201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) console.log('Notifications permissionLevel Change'); 13211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) onStateChange(); 13221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) }); 13231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 13240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)instrumented.notifications.onShowSettings.addListener(function() { 13250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) openUrl(SETTINGS_URL); 13260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}); 13270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 1328010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Handles state change notifications for the Google Now enabled bit. 1329010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)instrumented.storage.onChanged.addListener(function(changes, areaName) { 1330010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (areaName === 'local') { 1331010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if ('googleNowEnabled' in changes) { 1332010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) onStateChange(); 1333010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 1334010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) } 1335010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}); 1336010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 13378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)instrumented.pushMessaging.onMessage.addListener(function(message) { 13388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // message.payload will be '' when the extension first starts. 13398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Each time after signing in, we'll get latest payload for all channels. 13408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // So, we need to poll the server only when the payload is non-empty and has 13418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // changed. 13428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) console.log('pushMessaging.onMessage ' + JSON.stringify(message)); 13431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (message.payload.indexOf('REQUEST_CARDS') == 0) { 13448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() { 1345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Accept promise rejection on failure since it's safer to do nothing, 1346a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // preventing polling the server when the payload really didn't change. 1347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) fillFromChromeLocalStorage({ 1348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) lastPollNowPayloads: {}, 1349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) /** @type {Object.<string, StoredNotificationGroup>} */ 1350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) notificationGroups: {} 1351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) }, PromiseRejection.ALLOW).then(function(items) { 13521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (items.lastPollNowPayloads[message.subchannelId] != 13531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) message.payload) { 13541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) items.lastPollNowPayloads[message.subchannelId] = message.payload; 13558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 13560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) items.notificationGroups['PUSH' + message.subchannelId] = { 13570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) cards: [], 13580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) nextPollTime: Date.now() 13590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) }; 13600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 13610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) chrome.storage.local.set({ 13620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) lastPollNowPayloads: items.lastPollNowPayloads, 13630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) notificationGroups: items.notificationGroups 13648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) }); 13650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 1366010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) pollOptedInWithRecheck(); 13678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 13688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) }); 13698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) }); 13708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 137190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}); 1372