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