DelayedSyncController.java revision 3551c9c881056c480085172ff9840cab31610854
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.chrome.browser.sync;
6
7import android.accounts.Account;
8import android.content.ContentResolver;
9import android.content.Context;
10import android.content.SharedPreferences;
11import android.os.AsyncTask;
12import android.os.Bundle;
13import android.preference.PreferenceManager;
14import android.util.Log;
15
16import com.google.common.annotations.VisibleForTesting;
17
18import org.chromium.base.ActivityStatus;
19import org.chromium.sync.notifier.SyncStatusHelper;
20import org.chromium.sync.signin.AccountManagerHelper;
21
22/**
23 * A class for controlling when a sync should be performed immediately, and when it should be
24 * delayed until Chrome comes to the foreground again.
25 */
26public class DelayedSyncController {
27    private static final String TAG = "DelayedSyncController";
28    private static final String DELAYED_ACCOUNT_NAME = "delayed_account";
29
30    private static class LazyHolder {
31        private static final DelayedSyncController INSTANCE = new DelayedSyncController();
32    }
33
34    public static DelayedSyncController getInstance() {
35        return LazyHolder.INSTANCE;
36    }
37
38    @VisibleForTesting
39    DelayedSyncController() {}
40
41    /**
42     * Resume any syncs that were delayed while Chromium was backgrounded.
43     */
44    public boolean resumeDelayedSyncs(final Context context) {
45        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
46        String accountName = prefs.getString(DELAYED_ACCOUNT_NAME, null);
47        if (accountName == null) {
48            Log.d(TAG, "No delayed sync.");
49            return false;
50        } else {
51            Log.d(TAG, "Handling delayed sync.");
52            Account account = AccountManagerHelper.createAccountFromName(accountName);
53            requestSyncOnBackgroundThread(context, account);
54            return true;
55        }
56    }
57
58    /**
59     * Calls ContentResolver.requestSync() in a separate thread as it performs some blocking
60     * IO operations.
61     */
62    @VisibleForTesting
63    void requestSyncOnBackgroundThread(final Context context, final Account account) {
64        new AsyncTask<Void, Void, Void>() {
65            @Override
66            protected Void doInBackground(Void... unused) {
67                String contractAuthority =
68                        SyncStatusHelper.get(context).getContractAuthority();
69                ContentResolver.requestSync(account, contractAuthority, new Bundle());
70                return null;
71            }
72        }.execute();
73    }
74
75    /**
76     * Stores preferences to indicate that an invalidation has arrived, but dropped on the floor.
77     */
78    void setDelayedSync(Context ctx, String accountName) {
79        SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(ctx).edit();
80        editor.putString(DELAYED_ACCOUNT_NAME, accountName);
81        editor.apply();
82    }
83
84    /**
85     * If there is a delayed sync, it will be cleared.
86     */
87    @VisibleForTesting
88    void clearDelayedSyncs(Context context) {
89        setDelayedSync(context, null);
90    }
91
92    @VisibleForTesting
93    boolean shouldPerformSync(Context ctx, Bundle extras, Account account) {
94        boolean manualSync = isManualSync(extras);
95
96        if (manualSync || ActivityStatus.getState() == ActivityStatus.RESUMED) {
97            clearDelayedSyncs(ctx);
98            return true;
99        } else {
100            Log.d(TAG, "Delaying sync.");
101            setDelayedSync(ctx, account.name);
102            return false;
103        }
104    }
105
106    private static boolean isManualSync(Bundle extras) {
107        boolean manualSync = false;
108        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) {
109            manualSync = true;
110            Log.d(TAG, "Manual sync requested.");
111        }
112        return manualSync;
113    }
114}
115