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

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java

Issue 1263773007: [Android] Enable session invalidations while the RecentTabsPage is open (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
index 7c9f8ee37ad2bc56bc911cffdf5f667d8b3d1f49..b2bf677110ee60d165c946801f40dd6eb816af56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
@@ -6,6 +6,8 @@ package org.chromium.chrome.browser.invalidation;
import android.content.Context;
import android.content.Intent;
+import android.os.Handler;
+import android.os.SystemClock;
import org.chromium.base.ApplicationState;
import org.chromium.base.ApplicationStatus;
@@ -25,6 +27,98 @@ import java.util.HashSet;
* client library used by Sync.
*/
public class InvalidationController implements ApplicationStatus.ApplicationStateListener {
+ /**
+ * Timer which can be paused. When the timer is paused, the execution of its scheduled task is
+ * delayed till the timer is resumed.
+ */
+ private static class Timer {
+ private Handler mHandler;
+
+ /**
+ * Runnable which is added to the handler's message queue.
+ */
+ private Runnable mHandlerRunnable;
+
+ /**
+ * User provided task.
+ */
+ private Runnable mRunnable;
+
+ /**
+ * Time at which the task is scheduled.
+ */
+ private long mScheduledTime;
+
+ public Timer() {
+ mHandler = new Handler();
+ }
+
+ /**
+ * Sets the task to run. The task will run after the delay or once {@link #resume()} is
+ * called, whichever occurs last. The previously scheduled task, if any, is cancelled.
+ * @param r Task to run.
+ * @param delayMs Delay in milliseconds after which to run the task.
+ */
+ public void setRunnable(Runnable r, long delayMs) {
+ cancel();
+ mRunnable = r;
+ mScheduledTime = SystemClock.elapsedRealtime() + delayMs;
+ }
+
+ /**
+ * Blocks the task from being run.
+ */
+ public void pause() {
+ if (mHandlerRunnable == null) return;
+
+ mHandler.removeCallbacks(mHandlerRunnable);
+ mHandlerRunnable = null;
+ }
+
+ /**
+ * Unblocks the task from being run. If the task was scheduled for a time in the past, runs
+ * the task. Does nothing if no task is scheduled.
+ */
+ public void resume() {
+ if (mRunnable == null || mHandlerRunnable != null) return;
+
+ long delayMs = Math.max(mScheduledTime - SystemClock.elapsedRealtime(), 0);
+ mHandlerRunnable = new Runnable() {
+ @Override
+ public void run() {
+ Runnable r = mRunnable;
+ mRunnable = null;
+ mHandlerRunnable = null;
+ r.run();
+ }
+ };
+ mHandler.postDelayed(mHandlerRunnable, delayMs);
+ }
+
+ /**
+ * Cancels the scheduled task, if any.
+ */
+ public void cancel() {
+ pause();
+ mRunnable = null;
+ }
+ }
+
+ /**
+ * The amount of time after the RecentTabsPage is opened to register for session sync
+ * invalidations. The delay is designed so that only users who linger on the RecentTabsPage
+ * register for session sync invalidations. How long users spend on the RecentTabsPage is
+ * measured by the NewTabPage.RecentTabsPage.TimeVisibleAndroid UMA metric.
+ */
+ private static final int REGISTER_FOR_SESSION_SYNC_INVALIDATIONS_DELAY_MS = 20000;
+
+ /**
+ * The amount of time after the RecentTabsPage is closed to unregister for session sync
+ * invalidations. The delay is long to avoid registering and unregistering a lot if the user
+ * visits the RecentTabsPage a lot.
+ */
+ private static final int UNREGISTER_FOR_SESSION_SYNC_INVALIDATIONS_DELAY_MS = 3600000; // 1hr
+
private static final Object LOCK = new Object();
private static InvalidationController sInstance;
@@ -32,18 +126,43 @@ public class InvalidationController implements ApplicationStatus.ApplicationStat
private final Context mContext;
/**
- * Whether session sync invalidations should be disabled.
+ * Whether session sync invalidations can be disabled.
+ */
+ private final boolean mCanDisableSessionInvalidations;
+
+ /**
+ * Whether the controller was started.
+ */
+ private boolean mStarted;
+
+ /**
+ * Used to schedule tasks to enable and disable session sync invalidations.
+ */
+ private Timer mEnableSessionInvalidationsTimer;
+
+ /**
+ * Whether session sync invalidations are enabled.
+ */
+ private boolean mSessionInvalidationsEnabled;
+
+ /**
+ * The number of open RecentTabsPages
*/
- private final boolean mDisableSessionInvalidations;
+ private int mNumRecentTabPages;
/**
* Updates the sync invalidation types that the client is registered for based on the preferred
* sync types. Starts the client if needed.
*/
public void ensureStartedAndUpdateRegisteredTypes() {
+ mStarted = true;
+ // Do not apply changes to {@link #mSessionInvalidationsEnabled} yet because the timer task
+ // may be scheduled far into the future.
+ mEnableSessionInvalidationsTimer.resume();
+
HashSet<ModelType> typesToRegister = new HashSet<ModelType>();
typesToRegister.addAll(ProfileSyncService.get(mContext).getPreferredDataTypes());
- if (mDisableSessionInvalidations) {
+ if (!mSessionInvalidationsEnabled) {
typesToRegister.remove(ModelType.SESSION);
typesToRegister.remove(ModelType.FAVICON_TRACKING);
typesToRegister.remove(ModelType.FAVICON_IMAGE);
@@ -60,6 +179,8 @@ public class InvalidationController implements ApplicationStatus.ApplicationStat
* Starts the invalidation client without updating the registered invalidation types.
*/
private void start() {
+ mStarted = true;
+ mEnableSessionInvalidationsTimer.resume();
Intent intent = new Intent(mContext, InvalidationClientService.class);
mContext.startService(intent);
}
@@ -68,12 +189,39 @@ public class InvalidationController implements ApplicationStatus.ApplicationStat
* Stops the invalidation client.
*/
public void stop() {
+ mStarted = false;
+ mEnableSessionInvalidationsTimer.pause();
Intent intent = new Intent(mContext, InvalidationClientService.class);
intent.putExtra(InvalidationIntentProtocol.EXTRA_STOP, true);
mContext.startService(intent);
}
/**
+ * Called when a RecentTabsPage is opened.
+ */
+ public void onRecentTabsPageOpened() {
+ if (!mCanDisableSessionInvalidations) return;
+
+ ++mNumRecentTabPages;
+ if (mNumRecentTabPages == 1) {
+ setSessionInvalidationsEnabled(true, REGISTER_FOR_SESSION_SYNC_INVALIDATIONS_DELAY_MS);
+ }
+ }
+
+ /**
+ * Called when a RecentTabsPage is closed.
+ */
+ public void onRecentTabsPageClosed() {
+ if (!mCanDisableSessionInvalidations) return;
+
+ --mNumRecentTabPages;
+ if (mNumRecentTabPages == 0) {
+ setSessionInvalidationsEnabled(
+ false, UNREGISTER_FOR_SESSION_SYNC_INVALIDATIONS_DELAY_MS);
+ }
+ }
+
+ /**
* Returns the instance that will use {@code context} to issue intents.
*
* Calling this method will create the instance if it does not yet exist.
@@ -81,29 +229,56 @@ public class InvalidationController implements ApplicationStatus.ApplicationStat
public static InvalidationController get(Context context) {
synchronized (LOCK) {
if (sInstance == null) {
- boolean disableSessionInvalidations =
+ boolean canDisableSessionInvalidations =
FieldTrialList.findFullName("AndroidSessionNotifications")
.equals("Disabled");
- sInstance = new InvalidationController(context, disableSessionInvalidations);
+ sInstance = new InvalidationController(context, canDisableSessionInvalidations);
}
return sInstance;
}
}
/**
+ * Schedules a task to enable/disable session sync invalidations. Cancels any previously
+ * scheduled tasks to enable/disable session sync invalidations.
+ * @param enabled whether to enable or disable session sync invalidations.
+ * @param delayMs Delay in milliseconds after which to apply change.
+ */
+ private void setSessionInvalidationsEnabled(final boolean enabled, long delayMs) {
+ mEnableSessionInvalidationsTimer.cancel();
+ if (mSessionInvalidationsEnabled == enabled) return;
+
+ mEnableSessionInvalidationsTimer.setRunnable(new Runnable() {
+ @Override
+ public void run() {
+ mSessionInvalidationsEnabled = enabled;
+ ensureStartedAndUpdateRegisteredTypes();
+ }
+ }, delayMs);
+ if (mStarted) {
+ mEnableSessionInvalidationsTimer.resume();
+ }
+ }
+
+ /**
* Creates an instance using {@code context} to send intents.
*/
@VisibleForTesting
- InvalidationController(Context context, boolean disableSessionInvalidations) {
+ InvalidationController(Context context, boolean canDisableSessionInvalidations) {
Context appContext = context.getApplicationContext();
if (appContext == null) throw new NullPointerException("Unable to get application context");
mContext = appContext;
- mDisableSessionInvalidations = disableSessionInvalidations;
+ mCanDisableSessionInvalidations = canDisableSessionInvalidations;
+ mSessionInvalidationsEnabled = !mCanDisableSessionInvalidations;
+ mEnableSessionInvalidationsTimer = new Timer();
+
ApplicationStatus.registerApplicationStateListener(this);
}
@Override
public void onApplicationStateChange(int newState) {
+ // The isSyncEnabled() check is used to check whether the InvalidationController would be
+ // started if it did not stop itself when the application is paused.
if (AndroidSyncSettings.isSyncEnabled(mContext)) {
if (newState == ApplicationState.HAS_RUNNING_ACTIVITIES) {
start();
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698