Index: chrome/browser/resources/google_now/background.js |
diff --git a/chrome/browser/resources/google_now/background.js b/chrome/browser/resources/google_now/background.js |
index d2d3f3b83be0ec77b6e048be57e87de770dddcb9..72255cd0691a4367e248046232587a269fbff5b9 100644 |
--- a/chrome/browser/resources/google_now/background.js |
+++ b/chrome/browser/resources/google_now/background.js |
@@ -54,14 +54,14 @@ var MAXIMUM_POLLING_PERIOD_SECONDS = 60 * 60; // 1 hour |
* Initial period for polling for Google Now optin notification after push |
* messaging indicates Google Now is enabled. |
*/ |
-var INITIAL_OPTIN_POLLING_PERIOD_SECONDS = 60; // 1 minute |
+var INITIAL_OPTIN_RECHECK_PERIOD_SECONDS = 60; // 1 minute |
/** |
* Maximum period for polling for Google Now optin notification after push |
* messaging indicates Google Now is enabled. It is expected that the alarm |
* will be stopped after this. |
*/ |
-var MAXIMUM_OPTIN_POLLING_PERIOD_SECONDS = 16 * 60; // 16 minutes |
+var MAXIMUM_OPTIN_RECHECK_PERIOD_SECONDS = 16 * 60; // 16 minutes |
/** |
* Initial period for retrying the server request for dismissing cards. |
@@ -205,6 +205,7 @@ 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('tabs.create', 1); |
@@ -214,11 +215,16 @@ var updateCardsAttempts = buildAttemptManager( |
requestCards, |
INITIAL_POLLING_PERIOD_SECONDS, |
MAXIMUM_POLLING_PERIOD_SECONDS); |
-var optInCheckAttempts = buildAttemptManager( |
+var optInPollAttempts = buildAttemptManager( |
'optin', |
- pollOptedIn, |
- INITIAL_OPTIN_POLLING_PERIOD_SECONDS, |
- MAXIMUM_OPTIN_POLLING_PERIOD_SECONDS); |
+ pollOptedInNoImmediateRecheck, |
+ INITIAL_POLLING_PERIOD_SECONDS, |
+ MAXIMUM_POLLING_PERIOD_SECONDS); |
+var optInRecheckAttempts = buildAttemptManager( |
+ 'optin-recheck', |
+ pollOptedInWithRecheck, |
+ INITIAL_OPTIN_RECHECK_PERIOD_SECONDS, |
+ MAXIMUM_OPTIN_RECHECK_PERIOD_SECONDS); |
var dismissalAttempts = buildAttemptManager( |
'dismiss', |
retryPendingDismissals, |
@@ -425,39 +431,52 @@ function combineGroup(combinedCards, storedGroup) { |
} |
/** |
- * Schedules next cards poll. |
+ * Calculates the soonest poll time from a map of groups as an absolute time. |
* @param {Object.<string, StoredNotificationGroup>} groups Map from group name |
* to group information. |
- * @param {boolean} isOptedIn True if the user is opted in to Google Now. |
+ * @return {number} The next poll time based off of the groups. |
*/ |
-function scheduleNextPoll(groups, isOptedIn) { |
- if (isOptedIn) { |
- var nextPollTime = null; |
- |
- for (var groupName in groups) { |
- var group = groups[groupName]; |
- if (group.nextPollTime !== undefined) { |
- nextPollTime = nextPollTime == null ? |
- group.nextPollTime : Math.min(group.nextPollTime, nextPollTime); |
- } |
+function calculateNextPollTimeMilliseconds(groups) { |
+ var nextPollTime = null; |
+ |
+ for (var groupName in groups) { |
+ var group = groups[groupName]; |
+ if (group.nextPollTime !== undefined) { |
+ nextPollTime = nextPollTime == null ? |
+ group.nextPollTime : Math.min(group.nextPollTime, nextPollTime); |
} |
+ } |
- // At least one of the groups must have nextPollTime. |
- verify(nextPollTime != null, 'scheduleNextPoll: nextPollTime is null'); |
+ // At least one of the groups must have nextPollTime. |
+ verify(nextPollTime != null, 'calculateNextPollTime: nextPollTime is null'); |
+ return nextPollTime; |
+} |
- var nextPollDelaySeconds = Math.max( |
- (nextPollTime - Date.now()) / MS_IN_SECOND, |
- MINIMUM_POLLING_PERIOD_SECONDS); |
- updateCardsAttempts.start(nextPollDelaySeconds); |
- } else { |
- instrumented.metricsPrivate.getVariationParams( |
- 'GoogleNow', function(params) { |
- var optinPollPeriodSeconds = |
- parseInt(params && params.optinPollPeriodSeconds, 10) || |
- DEFAULT_OPTIN_CHECK_PERIOD_SECONDS; |
- updateCardsAttempts.start(optinPollPeriodSeconds); |
- }); |
- } |
+/** |
+ * Schedules next cards poll. |
+ * @param {Object.<string, StoredNotificationGroup>} groups Map from group name |
+ * to group information. |
+ */ |
+function scheduleNextCardsPoll(groups) { |
+ var nextPollTimeMs = calculateNextPollTimeMilliseconds(groups); |
+ |
+ var nextPollDelaySeconds = Math.max( |
+ (nextPollTimeMs - Date.now()) / MS_IN_SECOND, |
+ MINIMUM_POLLING_PERIOD_SECONDS); |
+ updateCardsAttempts.start(nextPollDelaySeconds); |
+} |
+ |
+/** |
+ * Schedules the next opt-in check poll. |
+ */ |
+function scheduleOptInCheckPoll() { |
+ instrumented.metricsPrivate.getVariationParams( |
+ 'GoogleNow', function(params) { |
+ var optinPollPeriodSeconds = |
+ parseInt(params && params.optinPollPeriodSeconds, 10) || |
+ DEFAULT_OPTIN_CHECK_PERIOD_SECONDS; |
+ optInPollAttempts.start(optinPollPeriodSeconds); |
+ }); |
} |
/** |
@@ -488,13 +507,6 @@ function processServerResponse(response) { |
if (response.googleNowDisabled) { |
chrome.storage.local.set({googleNowEnabled: false}); |
- // TODO(robliao): Remove the line below once the server stops sending groups |
- // with 'googleNowDisabled' responses. |
- response.groups = {}; |
- // Google Now was enabled; now it's disabled. This is a state change. |
- onStateChange(); |
- // Start the Google Now Disabled polling period. |
- scheduleNextPoll({}, false); |
// Stop processing now. The state change will clear the cards. |
return Promise.reject(); |
} |
@@ -573,7 +585,7 @@ function processServerResponse(response) { |
updatedGroups[groupName] = storedGroup; |
} |
- scheduleNextPoll(updatedGroups, !response.googleNowDisabled); |
+ scheduleNextCardsPoll(updatedGroups); |
return { |
updatedGroups: updatedGroups, |
recentDismissals: updatedRecentDismissals |
@@ -638,10 +650,27 @@ function requestNotificationGroupsFromServer(groupNames) { |
} |
/** |
+ * Performs an opt-in poll without an immediate recheck. |
+ * If the response is not opted-in, schedule an opt-in check poll. |
+ */ |
+function pollOptedInNoImmediateRecheck() { |
+ requestAndUpdateOptedIn() |
+ .then(function(optedIn) { |
+ if (!optedIn) { |
+ // Request a repoll if we're not opted in. |
+ return Promise.reject(); |
+ } |
+ }) |
+ .catch(function() { |
+ scheduleOptInCheckPoll(); |
+ }); |
+} |
+ |
+/** |
* Requests the account opted-in state from the server and updates any |
* state as necessary. |
* @return {Promise} A promise to request and update the opted-in state. |
- * The promise resolves if the opt-in state is true. |
+ * The promise resolves with the opt-in state. |
*/ |
function requestAndUpdateOptedIn() { |
console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL); |
@@ -654,15 +683,8 @@ function requestAndUpdateOptedIn() { |
return parsedResponse.value; |
} |
}).then(function(optedIn) { |
- if (optedIn) { |
- chrome.storage.local.set({googleNowEnabled: true}); |
- // Google Now was disabled, now it's enabled. This is a state change. |
- onStateChange(); |
- return Promise.resolve(); |
- } else { |
- scheduleNextPoll({}, false); |
- return Promise.reject(); |
- } |
+ chrome.storage.local.set({googleNowEnabled: optedIn}); |
+ return optedIn; |
}); |
} |
@@ -695,12 +717,7 @@ function getGroupsToRequest() { |
*/ |
function requestNotificationCards() { |
console.log('requestNotificationCards'); |
- |
- return isGoogleNowEnabled() |
- .then(function(googleNowEnabled) { |
- return googleNowEnabled ? Promise.resolve() : requestAndUpdateOptedIn(); |
- }) |
- .then(getGroupsToRequest) |
+ return getGroupsToRequest() |
.then(requestNotificationGroupsFromServer) |
.then(processServerResponse) |
.then(function(processedResponse) { |
@@ -731,10 +748,10 @@ function requestCards() { |
console.log('requestCards-task-begin'); |
updateCardsAttempts.isRunning(function(running) { |
if (running) { |
- updateCardsAttempts.planForNext(function() { |
- // The cards are requested only if there are no unsent dismissals. |
- processPendingDismissals().then(requestNotificationCards); |
- }); |
+ // The cards are requested only if there are no unsent dismissals. |
+ processPendingDismissals() |
+ .then(requestNotificationCards) |
+ .catch(updateCardsAttempts.scheduleRetry); |
} |
}); |
}); |
@@ -851,9 +868,7 @@ function processPendingDismissals() { |
*/ |
function retryPendingDismissals() { |
tasks.add(RETRY_DISMISS_TASK_NAME, function() { |
- dismissalAttempts.planForNext(function() { |
- processPendingDismissals(); |
- }); |
+ processPendingDismissals().catch(dismissalAttempts.scheduleRetry); |
}); |
} |
@@ -1006,6 +1021,28 @@ function setShouldPollCards(shouldPollCardsRequest) { |
} |
/** |
+ * Starts or stops the optin check. |
+ * @param {boolean} shouldPollOptInStatus true to start and false to stop |
+ * polling the optin status. |
+ */ |
+function setShouldPollOptInStatus(shouldPollOptInStatus) { |
+ optInPollAttempts.isRunning(function(currentValue) { |
+ if (shouldPollOptInStatus != currentValue) { |
+ console.log( |
+ 'Action Taken setShouldPollOptInStatus=' + shouldPollOptInStatus); |
+ if (shouldPollOptInStatus) { |
+ pollOptedInNoImmediateRecheck(); |
+ } else { |
+ optInPollAttempts.stop(); |
+ } |
+ } else { |
+ console.log( |
+ 'Action Ignored setShouldPollOptInStatus=' + shouldPollOptInStatus); |
+ } |
+ }); |
+} |
+ |
+/** |
* Enables or disables the Google Now background permission. |
* @param {boolean} backgroundEnable true to run in the background. |
* false to not run in the background. |
@@ -1066,13 +1103,13 @@ function updateRunningState( |
'googleNowEnabled=' + googleNowEnabled); |
var shouldPollCards = false; |
+ var shouldPollOptInStatus = false; |
var shouldSetBackground = false; |
- var shouldClearCards = true; |
if (signedIn && notificationEnabled) { |
- shouldClearCards = !googleNowEnabled; |
+ shouldPollCards = googleNowEnabled; |
+ shouldPollOptInStatus = !googleNowEnabled; |
shouldSetBackground = canEnableBackground && googleNowEnabled; |
- shouldPollCards = true; |
} else { |
recordEvent(GoogleNowEvent.STOPPED); |
} |
@@ -1082,11 +1119,12 @@ function updateRunningState( |
console.log( |
'Requested Actions shouldSetBackground=' + shouldSetBackground + ' ' + |
'setShouldPollCards=' + shouldPollCards + ' ' + |
- 'shouldClearCards=' + shouldClearCards); |
+ 'shouldPollOptInStatus=' + shouldPollOptInStatus); |
setBackgroundEnable(shouldSetBackground); |
setShouldPollCards(shouldPollCards); |
- if (shouldClearCards) { |
+ setShouldPollOptInStatus(shouldPollOptInStatus); |
+ if (!shouldPollCards) { |
removeAllCards(); |
} |
} |
@@ -1152,30 +1190,35 @@ function isGoogleNowEnabled() { |
* Sometimes we get the response to the opted in result too soon during |
* push messaging. We'll recheck the optin state a few times before giving up. |
*/ |
-function pollOptedIn() { |
+function pollOptedInWithRecheck() { |
/** |
* Cleans up any state used to recheck the opt-in poll. |
*/ |
function clearPollingState() { |
localStorage.removeItem('optedInCheckCount'); |
- optInCheckAttempts.stop(); |
+ optInRecheckAttempts.stop(); |
} |
if (localStorage.optedInCheckCount === undefined) { |
localStorage.optedInCheckCount = 0; |
- optInCheckAttempts.start(); |
+ optInRecheckAttempts.start(); |
} |
console.log(new Date() + |
' checkOptedIn Attempt ' + localStorage.optedInCheckCount); |
- requestAndUpdateOptedIn().then(function() { |
- clearPollingState(); |
- requestCards(); |
+ requestAndUpdateOptedIn().then(function(optedIn) { |
+ if (optedIn) { |
+ clearPollingState(); |
+ return Promise.resolve(); |
+ } else { |
+ // If we're not opted in, reject to retry. |
+ return Promise.reject(); |
+ } |
}).catch(function() { |
if (localStorage.optedInCheckCount < 5) { |
localStorage.optedInCheckCount++; |
- optInCheckAttempts.planForNext(function() {}); |
+ optInRecheckAttempts.scheduleRetry(); |
} else { |
clearPollingState(); |
} |
@@ -1259,6 +1302,15 @@ instrumented.notifications.onShowSettings.addListener(function() { |
openUrl(SETTINGS_URL); |
}); |
+// Handles state change notifications for the Google Now enabled bit. |
+instrumented.storage.onChanged.addListener(function(changes, areaName) { |
+ if (areaName === 'local') { |
+ if ('googleNowEnabled' in changes) { |
+ onStateChange(); |
+ } |
+ } |
+}); |
+ |
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. |
@@ -1288,7 +1340,7 @@ instrumented.pushMessaging.onMessage.addListener(function(message) { |
notificationGroups: items.notificationGroups |
}); |
- pollOptedIn(); |
+ pollOptedInWithRecheck(); |
} |
}); |
}); |