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

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

Issue 844503005: Convert now component to use GCM rather than pushMessaging. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: responseType = text to application/json Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/browser/resources/google_now/background_test_util.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 'use strict'; 5 'use strict';
6 6
7 /** 7 /**
8 * @fileoverview The event page for Google Now for Chrome implementation. 8 * @fileoverview The event page for Google Now for Chrome implementation.
9 * The Google Now event page gets Google Now cards from the server and shows 9 * The Google Now event page gets Google Now cards from the server and shows
10 * them as Chrome notifications. 10 * them as Chrome notifications.
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 */ 88 */
89 var DEFAULT_OPTIN_CHECK_PERIOD_SECONDS = 60 * 60 * 24 * 7; // 1 week 89 var DEFAULT_OPTIN_CHECK_PERIOD_SECONDS = 60 * 60 * 24 * 7; // 1 week
90 90
91 /** 91 /**
92 * URL to open when the user clicked on a link for the our notification 92 * URL to open when the user clicked on a link for the our notification
93 * settings. 93 * settings.
94 */ 94 */
95 var SETTINGS_URL = 'https://support.google.com/chrome/?p=ib_google_now_welcome'; 95 var SETTINGS_URL = 'https://support.google.com/chrome/?p=ib_google_now_welcome';
96 96
97 /** 97 /**
98 * GCM registration URL.
99 */
100 var GCM_REGISTRATION_URL =
101 'https://android.googleapis.com/gcm/googlenotification';
102
103 /**
104 * DevConsole project ID for GCM API use.
105 */
106 var GCM_PROJECT_ID = '437902709571';
107
108 /**
98 * Number of cards that need an explanatory link. 109 * Number of cards that need an explanatory link.
99 */ 110 */
100 var EXPLANATORY_CARDS_LINK_THRESHOLD = 4; 111 var EXPLANATORY_CARDS_LINK_THRESHOLD = 4;
101 112
102 /** 113 /**
103 * Names for tasks that can be created by the extension. 114 * Names for tasks that can be created by the extension.
104 */ 115 */
105 var UPDATE_CARDS_TASK_NAME = 'update-cards'; 116 var UPDATE_CARDS_TASK_NAME = 'update-cards';
106 var DISMISS_CARD_TASK_NAME = 'dismiss-card'; 117 var DISMISS_CARD_TASK_NAME = 'dismiss-card';
107 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss'; 118 var RETRY_DISMISS_TASK_NAME = 'retry-dismiss';
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 // send dismissals is scheduled. 193 // send dismissals is scheduled.
183 return true; 194 return true;
184 } 195 }
185 196
186 return false; 197 return false;
187 } 198 }
188 199
189 var tasks = buildTaskManager(areTasksConflicting); 200 var tasks = buildTaskManager(areTasksConflicting);
190 201
191 // Add error processing to API calls. 202 // Add error processing to API calls.
203 wrapper.instrumentChromeApiFunction('gcm.onMessage.addListener', 0);
204 wrapper.instrumentChromeApiFunction('gcm.register', 1);
192 wrapper.instrumentChromeApiFunction('metricsPrivate.getVariationParams', 1); 205 wrapper.instrumentChromeApiFunction('metricsPrivate.getVariationParams', 1);
193 wrapper.instrumentChromeApiFunction('notifications.clear', 1); 206 wrapper.instrumentChromeApiFunction('notifications.clear', 1);
194 wrapper.instrumentChromeApiFunction('notifications.create', 2); 207 wrapper.instrumentChromeApiFunction('notifications.create', 2);
195 wrapper.instrumentChromeApiFunction('notifications.getPermissionLevel', 0); 208 wrapper.instrumentChromeApiFunction('notifications.getPermissionLevel', 0);
196 wrapper.instrumentChromeApiFunction('notifications.update', 2); 209 wrapper.instrumentChromeApiFunction('notifications.update', 2);
197 wrapper.instrumentChromeApiFunction('notifications.getAll', 0); 210 wrapper.instrumentChromeApiFunction('notifications.getAll', 0);
198 wrapper.instrumentChromeApiFunction( 211 wrapper.instrumentChromeApiFunction(
199 'notifications.onButtonClicked.addListener', 0); 212 'notifications.onButtonClicked.addListener', 0);
200 wrapper.instrumentChromeApiFunction('notifications.onClicked.addListener', 0); 213 wrapper.instrumentChromeApiFunction('notifications.onClicked.addListener', 0);
201 wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0); 214 wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0);
202 wrapper.instrumentChromeApiFunction( 215 wrapper.instrumentChromeApiFunction(
203 'notifications.onPermissionLevelChanged.addListener', 0); 216 'notifications.onPermissionLevelChanged.addListener', 0);
204 wrapper.instrumentChromeApiFunction( 217 wrapper.instrumentChromeApiFunction(
205 'notifications.onShowSettings.addListener', 0); 218 'notifications.onShowSettings.addListener', 0);
206 wrapper.instrumentChromeApiFunction('permissions.contains', 1); 219 wrapper.instrumentChromeApiFunction('permissions.contains', 1);
207 wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0);
208 wrapper.instrumentChromeApiFunction('storage.onChanged.addListener', 0);
209 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0); 220 wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0);
210 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0); 221 wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0);
222 wrapper.instrumentChromeApiFunction('storage.onChanged.addListener', 0);
211 wrapper.instrumentChromeApiFunction('tabs.create', 1); 223 wrapper.instrumentChromeApiFunction('tabs.create', 1);
212 224
213 var updateCardsAttempts = buildAttemptManager( 225 var updateCardsAttempts = buildAttemptManager(
214 'cards-update', 226 'cards-update',
215 requestCards, 227 requestCards,
216 INITIAL_POLLING_PERIOD_SECONDS, 228 INITIAL_POLLING_PERIOD_SECONDS,
217 MAXIMUM_POLLING_PERIOD_SECONDS); 229 MAXIMUM_POLLING_PERIOD_SECONDS);
218 var optInPollAttempts = buildAttemptManager( 230 var optInPollAttempts = buildAttemptManager(
219 'optin', 231 'optin',
220 pollOptedInNoImmediateRecheck, 232 pollOptedInNoImmediateRecheck,
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after
1008 // We don't clear localStorage since those values are still relevant 1020 // We don't clear localStorage since those values are still relevant
1009 // across Google Now start-stop events. 1021 // across Google Now start-stop events.
1010 chrome.storage.local.clear(); 1022 chrome.storage.local.clear();
1011 } 1023 }
1012 1024
1013 /** 1025 /**
1014 * Initializes the event page on install or on browser startup. 1026 * Initializes the event page on install or on browser startup.
1015 */ 1027 */
1016 function initialize() { 1028 function initialize() {
1017 recordEvent(GoogleNowEvent.EXTENSION_START); 1029 recordEvent(GoogleNowEvent.EXTENSION_START);
1030 registerForGcm();
1018 onStateChange(); 1031 onStateChange();
1019 } 1032 }
1020 1033
1021 /** 1034 /**
1022 * Starts or stops the main pipeline for polling cards. 1035 * Starts or stops the main pipeline for polling cards.
1023 * @param {boolean} shouldPollCardsRequest true to start and 1036 * @param {boolean} shouldPollCardsRequest true to start and
1024 * false to stop polling cards. 1037 * false to stop polling cards.
1025 */ 1038 */
1026 function setShouldPollCards(shouldPollCardsRequest) { 1039 function setShouldPollCards(shouldPollCardsRequest) {
1027 updateCardsAttempts.isRunning(function(currentValue) { 1040 updateCardsAttempts.isRunning(function(currentValue) {
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
1197 * opt-in state. 1210 * opt-in state.
1198 */ 1211 */
1199 function isGoogleNowEnabled() { 1212 function isGoogleNowEnabled() {
1200 return fillFromChromeLocalStorage({googleNowEnabled: false}) 1213 return fillFromChromeLocalStorage({googleNowEnabled: false})
1201 .then(function(items) { 1214 .then(function(items) {
1202 return items.googleNowEnabled; 1215 return items.googleNowEnabled;
1203 }); 1216 });
1204 } 1217 }
1205 1218
1206 /** 1219 /**
1220 * Ensures the extension is ready to listen for GCM messages.
1221 */
1222 function registerForGcm() {
1223 // We don't need to use the key yet, just ensure the channel is set up.
1224 getGcmNotificationKey();
1225 }
1226
1227 /**
1228 * Returns a Promise resolving to either a cached or new GCM notification key.
1229 * Rejects if registration fails.
1230 * @return {Promise} A Promise that resolves to a potentially-cached GCM key.
1231 */
1232 function getGcmNotificationKey() {
1233 return fillFromChromeLocalStorage({gcmNotificationKey: undefined})
1234 .then(function(items) {
1235 if (items.gcmNotificationKey) {
1236 console.log('Reused gcm key from storage.');
1237 return Promise.resolve(items.gcmNotificationKey);
1238 }
1239 return requestNewGcmNotificationKey();
1240 });
1241 }
1242
1243 /**
1244 * Returns a promise resolving to a GCM Notificaiton Key. May call
1245 * chrome.gcm.register() first if required. Rejects on registration failure.
1246 * @return {Promise} A Promise that resolves to a fresh GCM Notification key.
1247 */
1248 function requestNewGcmNotificationKey() {
1249 return getGcmRegistrationId().then(function(gcmId) {
1250 authenticationManager.getAuthToken().then(function(token) {
1251 authenticationManager.getLogin().then(function(username) {
1252 return new Promise(function(resolve, reject) {
1253 var xhr = new XMLHttpRequest();
1254 xhr.responseType = 'application/json';
1255 xhr.open('POST', GCM_REGISTRATION_URL, true);
1256 xhr.setRequestHeader('Content-Type', 'application/json');
1257 xhr.setRequestHeader('Authorization', 'Bearer ' + token);
1258 xhr.setRequestHeader('project_id', GCM_PROJECT_ID);
1259 var payload = {
1260 'operation': 'add',
1261 'notification_key_name': username,
1262 'registration_ids': [gcmId]
1263 };
1264 xhr.onloadend = function() {
1265 if (xhr.status != 200) {
1266 reject();
1267 }
1268 var obj = JSON.parse(xhr.responseText);
1269 var key = obj && obj.notification_key;
1270 if (!key) {
1271 reject();
1272 }
1273 console.log('gcm notification key POST: ' + key);
1274 chrome.storage.local.set({gcmNotificationKey: key});
1275 resolve(key);
1276 };
1277 xhr.send(JSON.stringify(payload));
1278 });
1279 });
1280 }).catch(function() {
1281 // Couldn't obtain a GCM ID. Ignore and fallback to polling.
1282 });
1283 });
1284 }
1285
1286 /**
1287 * Returns a promise resolving to either a cached or new GCM registration ID.
1288 * Rejects if registration fails.
1289 * @return {Promise} A Promise that resolves to a GCM registration ID.
1290 */
1291 function getGcmRegistrationId() {
1292 return fillFromChromeLocalStorage({gcmRegistrationId: undefined})
1293 .then(function(items) {
1294 if (items.gcmRegistrationId) {
1295 console.log('Reused gcm registration id from storage.');
1296 return Promise.resolve(items.gcmRegistrationId);
1297 }
1298
1299 return new Promise(function(resolve, reject) {
1300 instrumented.gcm.register([GCM_PROJECT_ID], function(registrationId) {
1301 console.log('gcm.register(): ' + registrationId);
1302 if (registrationId) {
1303 chrome.storage.local.set({gcmRegistrationId: registrationId});
1304 resolve(registrationId);
1305 } else {
1306 reject();
1307 }
1308 });
1309 });
1310 });
1311 }
1312
1313 /**
1207 * Polls the optin state. 1314 * Polls the optin state.
1208 * Sometimes we get the response to the opted in result too soon during 1315 * Sometimes we get the response to the opted in result too soon during
1209 * push messaging. We'll recheck the optin state a few times before giving up. 1316 * push messaging. We'll recheck the optin state a few times before giving up.
1210 */ 1317 */
1211 function pollOptedInWithRecheck() { 1318 function pollOptedInWithRecheck() {
1212 /** 1319 /**
1213 * Cleans up any state used to recheck the opt-in poll. 1320 * Cleans up any state used to recheck the opt-in poll.
1214 */ 1321 */
1215 function clearPollingState() { 1322 function clearPollingState() {
1216 localStorage.removeItem('optedInCheckCount'); 1323 localStorage.removeItem('optedInCheckCount');
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
1327 1434
1328 // Handles state change notifications for the Google Now enabled bit. 1435 // Handles state change notifications for the Google Now enabled bit.
1329 instrumented.storage.onChanged.addListener(function(changes, areaName) { 1436 instrumented.storage.onChanged.addListener(function(changes, areaName) {
1330 if (areaName === 'local') { 1437 if (areaName === 'local') {
1331 if ('googleNowEnabled' in changes) { 1438 if ('googleNowEnabled' in changes) {
1332 onStateChange(); 1439 onStateChange();
1333 } 1440 }
1334 } 1441 }
1335 }); 1442 });
1336 1443
1337 instrumented.pushMessaging.onMessage.addListener(function(message) { 1444 instrumented.gcm.onMessage.addListener(function(message) {
1338 // message.payload will be '' when the extension first starts. 1445 console.log('gcm.onMessage ' + JSON.stringify(message));
1339 // Each time after signing in, we'll get latest payload for all channels. 1446 if (!message || !message.data) {
1340 // So, we need to poll the server only when the payload is non-empty and has 1447 return;
1341 // changed. 1448 }
1342 console.log('pushMessaging.onMessage ' + JSON.stringify(message)); 1449
1343 if (message.payload.indexOf('REQUEST_CARDS') == 0) { 1450 var payload = message.data.payload;
1451 var tag = message.data.tag;
1452 if (payload.indexOf('REQUEST_CARDS') == 0) {
1344 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() { 1453 tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() {
1345 // Accept promise rejection on failure since it's safer to do nothing, 1454 // Accept promise rejection on failure since it's safer to do nothing,
1346 // preventing polling the server when the payload really didn't change. 1455 // preventing polling the server when the payload really didn't change.
1347 fillFromChromeLocalStorage({ 1456 fillFromChromeLocalStorage({
1348 lastPollNowPayloads: {}, 1457 lastPollNowPayloads: {},
1349 /** @type {Object<string, StoredNotificationGroup>} */ 1458 /** @type {Object<string, StoredNotificationGroup>} */
1350 notificationGroups: {} 1459 notificationGroups: {}
1351 }, PromiseRejection.ALLOW).then(function(items) { 1460 }, PromiseRejection.ALLOW).then(function(items) {
1352 if (items.lastPollNowPayloads[message.subchannelId] != 1461 if (items.lastPollNowPayloads[tag] != payload) {
1353 message.payload) { 1462 items.lastPollNowPayloads[tag] = payload;
1354 items.lastPollNowPayloads[message.subchannelId] = message.payload;
1355 1463
1356 items.notificationGroups['PUSH' + message.subchannelId] = { 1464 items.notificationGroups['PUSH' + tag] = {
1357 cards: [], 1465 cards: [],
1358 nextPollTime: Date.now() 1466 nextPollTime: Date.now()
1359 }; 1467 };
1360 1468
1361 chrome.storage.local.set({ 1469 chrome.storage.local.set({
1362 lastPollNowPayloads: items.lastPollNowPayloads, 1470 lastPollNowPayloads: items.lastPollNowPayloads,
1363 notificationGroups: items.notificationGroups 1471 notificationGroups: items.notificationGroups
1364 }); 1472 });
1365 1473
1366 pollOptedInWithRecheck(); 1474 pollOptedInWithRecheck();
1367 } 1475 }
1368 }); 1476 });
1369 }); 1477 });
1370 } 1478 }
1371 }); 1479 });
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/google_now/background_test_util.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698