Commit af1b9859 authored by skare's avatar skare Committed by Commit bot

Convert now component to use GCM rather than pushMessaging.

BUG=447455

Review URL: https://codereview.chromium.org/844503005

Cr-Commit-Position: refs/heads/master@{#317450}
parent e10fe54d
......@@ -94,6 +94,17 @@ var DEFAULT_OPTIN_CHECK_PERIOD_SECONDS = 60 * 60 * 24 * 7; // 1 week
*/
var SETTINGS_URL = 'https://support.google.com/chrome/?p=ib_google_now_welcome';
/**
* GCM registration URL.
*/
var GCM_REGISTRATION_URL =
'https://android.googleapis.com/gcm/googlenotification';
/**
* DevConsole project ID for GCM API use.
*/
var GCM_PROJECT_ID = '437902709571';
/**
* Number of cards that need an explanatory link.
*/
......@@ -189,6 +200,8 @@ function areTasksConflicting(newTaskName, scheduledTaskName) {
var tasks = buildTaskManager(areTasksConflicting);
// Add error processing to API calls.
wrapper.instrumentChromeApiFunction('gcm.onMessage.addListener', 0);
wrapper.instrumentChromeApiFunction('gcm.register', 1);
wrapper.instrumentChromeApiFunction('metricsPrivate.getVariationParams', 1);
wrapper.instrumentChromeApiFunction('notifications.clear', 1);
wrapper.instrumentChromeApiFunction('notifications.create', 2);
......@@ -204,10 +217,9 @@ wrapper.instrumentChromeApiFunction(
wrapper.instrumentChromeApiFunction(
'notifications.onShowSettings.addListener', 0);
wrapper.instrumentChromeApiFunction('permissions.contains', 1);
wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0);
wrapper.instrumentChromeApiFunction('storage.onChanged.addListener', 0);
wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0);
wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0);
wrapper.instrumentChromeApiFunction('storage.onChanged.addListener', 0);
wrapper.instrumentChromeApiFunction('tabs.create', 1);
var updateCardsAttempts = buildAttemptManager(
......@@ -1015,6 +1027,7 @@ function stopPollingCards() {
*/
function initialize() {
recordEvent(GoogleNowEvent.EXTENSION_START);
registerForGcm();
onStateChange();
}
......@@ -1203,6 +1216,100 @@ function isGoogleNowEnabled() {
});
}
/**
* Ensures the extension is ready to listen for GCM messages.
*/
function registerForGcm() {
// We don't need to use the key yet, just ensure the channel is set up.
getGcmNotificationKey();
}
/**
* Returns a Promise resolving to either a cached or new GCM notification key.
* Rejects if registration fails.
* @return {Promise} A Promise that resolves to a potentially-cached GCM key.
*/
function getGcmNotificationKey() {
return fillFromChromeLocalStorage({gcmNotificationKey: undefined})
.then(function(items) {
if (items.gcmNotificationKey) {
console.log('Reused gcm key from storage.');
return Promise.resolve(items.gcmNotificationKey);
}
return requestNewGcmNotificationKey();
});
}
/**
* Returns a promise resolving to a GCM Notificaiton Key. May call
* chrome.gcm.register() first if required. Rejects on registration failure.
* @return {Promise} A Promise that resolves to a fresh GCM Notification key.
*/
function requestNewGcmNotificationKey() {
return getGcmRegistrationId().then(function(gcmId) {
authenticationManager.getAuthToken().then(function(token) {
authenticationManager.getLogin().then(function(username) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.responseType = 'application/json';
xhr.open('POST', GCM_REGISTRATION_URL, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.setRequestHeader('project_id', GCM_PROJECT_ID);
var payload = {
'operation': 'add',
'notification_key_name': username,
'registration_ids': [gcmId]
};
xhr.onloadend = function() {
if (xhr.status != 200) {
reject();
}
var obj = JSON.parse(xhr.responseText);
var key = obj && obj.notification_key;
if (!key) {
reject();
}
console.log('gcm notification key POST: ' + key);
chrome.storage.local.set({gcmNotificationKey: key});
resolve(key);
};
xhr.send(JSON.stringify(payload));
});
});
}).catch(function() {
// Couldn't obtain a GCM ID. Ignore and fallback to polling.
});
});
}
/**
* Returns a promise resolving to either a cached or new GCM registration ID.
* Rejects if registration fails.
* @return {Promise} A Promise that resolves to a GCM registration ID.
*/
function getGcmRegistrationId() {
return fillFromChromeLocalStorage({gcmRegistrationId: undefined})
.then(function(items) {
if (items.gcmRegistrationId) {
console.log('Reused gcm registration id from storage.');
return Promise.resolve(items.gcmRegistrationId);
}
return new Promise(function(resolve, reject) {
instrumented.gcm.register([GCM_PROJECT_ID], function(registrationId) {
console.log('gcm.register(): ' + registrationId);
if (registrationId) {
chrome.storage.local.set({gcmRegistrationId: registrationId});
resolve(registrationId);
} else {
reject();
}
});
});
});
}
/**
* Polls the optin state.
* Sometimes we get the response to the opted in result too soon during
......@@ -1334,13 +1441,15 @@ instrumented.storage.onChanged.addListener(function(changes, areaName) {
}
});
instrumented.pushMessaging.onMessage.addListener(function(message) {
// message.payload will be '' when the extension first starts.
// Each time after signing in, we'll get latest payload for all channels.
// So, we need to poll the server only when the payload is non-empty and has
// changed.
console.log('pushMessaging.onMessage ' + JSON.stringify(message));
if (message.payload.indexOf('REQUEST_CARDS') == 0) {
instrumented.gcm.onMessage.addListener(function(message) {
console.log('gcm.onMessage ' + JSON.stringify(message));
if (!message || !message.data) {
return;
}
var payload = message.data.payload;
var tag = message.data.tag;
if (payload.indexOf('REQUEST_CARDS') == 0) {
tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() {
// Accept promise rejection on failure since it's safer to do nothing,
// preventing polling the server when the payload really didn't change.
......@@ -1349,11 +1458,10 @@ instrumented.pushMessaging.onMessage.addListener(function(message) {
/** @type {Object<string, StoredNotificationGroup>} */
notificationGroups: {}
}, PromiseRejection.ALLOW).then(function(items) {
if (items.lastPollNowPayloads[message.subchannelId] !=
message.payload) {
items.lastPollNowPayloads[message.subchannelId] = message.payload;
if (items.lastPollNowPayloads[tag] != payload) {
items.lastPollNowPayloads[tag] = payload;
items.notificationGroups['PUSH' + message.subchannelId] = {
items.notificationGroups['PUSH' + tag] = {
cards: [],
nextPollTime: Date.now()
};
......
......@@ -18,12 +18,12 @@ var buildAttemptManager = emptyMock;
var buildCardSet = emptyMock;
var instrumented = {};
mockChromeEvent(instrumented, 'gcm.onMessage');
mockChromeEvent(instrumented, 'notifications.onButtonClicked');
mockChromeEvent(instrumented, 'notifications.onClicked');
mockChromeEvent(instrumented, 'notifications.onClosed');
mockChromeEvent(instrumented, 'notifications.onPermissionLevelChanged');
mockChromeEvent(instrumented, 'notifications.onShowSettings');
mockChromeEvent(instrumented, 'pushMessaging.onMessage');
mockChromeEvent(instrumented, 'runtime.onInstalled');
mockChromeEvent(instrumented, 'runtime.onStartup');
mockChromeEvent(instrumented, 'storage.onChanged');
......
......@@ -713,6 +713,10 @@ function expectInitialization(fixture) {
fixture.mockGlobals.stubs().recordEvent(ANYTHING);
fixture.mockGlobals.
expects(once()).recordEvent(GoogleNowEvent.EXTENSION_START);
fixture.mockApis.expects(once())
.fillFromChromeLocalStorage(eqJSON({gcmNotificationKey: undefined}))
.will(returnValue(Promise.resolve({gcmNotificationKey: 'gcmkey'})));
}
TEST_F(TEST_NAME,'Initialize_SignedOut', function() {
......
......@@ -11,16 +11,17 @@
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhqJr32OFD/bMXW4Md7jMfd7LbwHXVc6x5bBQG5U+dloofoxrICDR20yur/40mQ8O//0sS1b8srvbab1CRlSrxoNCr9T80NAkfzx0gHyVS+p1Zow+1FzLMu9PiGwwFyN80HIB7GI/dIa0wC9K/2OrrzcHEhVH96DacTtWQqjfDVtZPjT7Xwv23dgoWcpbkRC86jMJot3dmX9xnn0KzoVc9gDOHSIkBLbkkr6Sp3LGXCCM4L0DJgxdFwaLr5WBzgC3y5x0/wwPIwN4PtIaK3BhH6njlksfnKwwIJ9iRT41V4BqbWu4mszO/7VJ3HJyw2DBpIc2grU9ZRRxrV3fRQG4wIDAQAB",
"permissions": [
"alarms",
"gcm",
"identity",
"metricsPrivate",
"notifications",
"pushMessaging",
"storage",
"tabs",
"webstorePrivate",
"*://*.google.com/*",
"*://*.gstatic.com/*",
"https://*.googleapis.com/chromenow/v1/*",
"https://*.googleapis.com/gcm/*",
"https://*.googleusercontent.com/*"
],
"optional_permissions": ["background"],
......@@ -31,6 +32,9 @@
},
"oauth2": {
"auto_approve": true,
"scopes": ["https://www.googleapis.com/auth/googlenow"]
"scopes": [
"https://www.googleapis.com/auth/gcm",
"https://www.googleapis.com/auth/googlenow"
]
}
}
......@@ -981,16 +981,26 @@ function buildAuthenticationManager() {
});
}
/**
* Determines the active account's login (username).
* @return {Promise} A promise to determine the current account's login.
*/
function getLogin() {
return new Promise(function(resolve) {
instrumented.webstorePrivate.getBrowserLogin(function(accountInfo) {
resolve(accountInfo.login);
});
});
}
/**
* Determines whether there is an account attached to the profile.
* @return {Promise} A promise to determine if there is an account attached
* to the profile.
*/
function isSignedIn() {
return new Promise(function(resolve) {
instrumented.webstorePrivate.getBrowserLogin(function(accountInfo) {
resolve(!!accountInfo.login);
});
return getLogin().then(function(login) {
return Promise.resolve(!!login);
});
}
......@@ -1055,6 +1065,7 @@ function buildAuthenticationManager() {
return {
addListener: addListener,
getAuthToken: getAuthToken,
getLogin: getLogin,
isSignedIn: isSignedIn,
removeToken: removeToken
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment