Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.sync; | 5 package org.chromium.sync; |
| 6 | 6 |
| 7 import android.accounts.Account; | 7 import android.accounts.Account; |
| 8 import android.content.ContentResolver; | 8 import android.content.ContentResolver; |
| 9 import android.content.Context; | 9 import android.content.Context; |
| 10 import android.content.SyncStatusObserver; | 10 import android.content.SyncStatusObserver; |
| 11 import android.os.StrictMode; | 11 import android.os.StrictMode; |
| 12 | 12 |
| 13 import org.chromium.base.ObserverList; | 13 import org.chromium.base.ObserverList; |
| 14 import org.chromium.base.VisibleForTesting; | 14 import org.chromium.base.VisibleForTesting; |
| 15 import org.chromium.sync.signin.AccountManagerHelper; | 15 import org.chromium.sync.signin.AccountManagerHelper; |
| 16 import org.chromium.sync.signin.ChromeSigninController; | |
| 17 | 16 |
| 18 import javax.annotation.concurrent.NotThreadSafe; | |
| 19 import javax.annotation.concurrent.ThreadSafe; | 17 import javax.annotation.concurrent.ThreadSafe; |
| 20 | 18 |
| 21 /** | 19 /** |
| 22 * A helper class to handle the current status of sync for Chrome in Android set tings. | 20 * A helper class to handle the current status of sync for Chrome in Android set tings. |
| 23 * | 21 * |
| 24 * It also provides an observer to be used whenever Android sync settings change . | 22 * It also provides an observer to be used whenever Android sync settings change . |
| 25 * | 23 * |
| 26 * To retrieve an instance of this class, call AndroidSyncSettings.get(someConte xt). | 24 * To retrieve an instance of this class, call AndroidSyncSettings.get(someConte xt). |
| 27 * | |
| 28 * All new public methods MUST call notifyObservers at the end. | |
| 29 */ | 25 */ |
| 30 @ThreadSafe | 26 @ThreadSafe |
| 31 public class AndroidSyncSettings { | 27 public class AndroidSyncSettings { |
| 32 | 28 |
| 33 /** | |
| 34 * In-memory holder of the sync configurations for a given account. On each | |
| 35 * access, updates the cache if the account has changed. This lazy-updating | |
| 36 * model is appropriate as the account changes rarely but may not be known | |
| 37 * when initially constructed. So long as we keep a single account, no | |
| 38 * expensive calls to Android are made. | |
| 39 */ | |
| 40 @NotThreadSafe | |
| 41 @VisibleForTesting | |
| 42 public static class CachedAccountSyncSettings { | |
| 43 private final String mContractAuthority; | |
| 44 private final SyncContentResolverDelegate mSyncContentResolverDelegate; | |
| 45 private Account mAccount; | |
| 46 private boolean mDidUpdate; | |
| 47 private boolean mSyncAutomatically; | |
| 48 private int mIsSyncable; | |
| 49 | |
| 50 public CachedAccountSyncSettings(String contractAuthority, | |
| 51 SyncContentResolverDelegate contentResolverWrapper) { | |
| 52 mContractAuthority = contractAuthority; | |
| 53 mSyncContentResolverDelegate = contentResolverWrapper; | |
| 54 } | |
| 55 | |
| 56 private void ensureSettingsAreForAccount(Account account) { | |
| 57 assert account != null; | |
| 58 if (account.equals(mAccount)) return; | |
| 59 updateSyncSettingsForAccount(account); | |
| 60 mDidUpdate = true; | |
| 61 } | |
| 62 | |
| 63 public void clearUpdateStatus() { | |
| 64 mDidUpdate = false; | |
| 65 } | |
| 66 | |
| 67 public boolean getDidUpdateStatus() { | |
| 68 return mDidUpdate; | |
| 69 } | |
| 70 | |
| 71 // Calling this method may have side-effects. | |
| 72 public boolean getSyncAutomatically(Account account) { | |
| 73 ensureSettingsAreForAccount(account); | |
| 74 return mSyncAutomatically; | |
| 75 } | |
| 76 | |
| 77 public void updateSyncSettingsForAccount(Account account) { | |
| 78 if (account == null) return; | |
| 79 updateSyncSettingsForAccountInternal(account); | |
| 80 } | |
| 81 | |
| 82 public void setIsSyncable(Account account) { | |
| 83 ensureSettingsAreForAccount(account); | |
| 84 if (mIsSyncable == 1) return; | |
| 85 setIsSyncableInternal(account); | |
| 86 } | |
| 87 | |
| 88 public void setSyncAutomatically(Account account, boolean value) { | |
| 89 ensureSettingsAreForAccount(account); | |
| 90 if (mSyncAutomatically == value) return; | |
| 91 setSyncAutomaticallyInternal(account, value); | |
| 92 } | |
| 93 | |
| 94 @VisibleForTesting | |
| 95 protected void updateSyncSettingsForAccountInternal(Account account) { | |
| 96 // Null check here otherwise Findbugs complains. | |
| 97 if (account == null) return; | |
| 98 | |
| 99 boolean oldSyncAutomatically = mSyncAutomatically; | |
| 100 int oldIsSyncable = mIsSyncable; | |
| 101 Account oldAccount = mAccount; | |
| 102 | |
| 103 mAccount = account; | |
| 104 | |
| 105 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites (); | |
| 106 mSyncAutomatically = mSyncContentResolverDelegate.getSyncAutomatical ly( | |
| 107 account, mContractAuthority); | |
| 108 mIsSyncable = mSyncContentResolverDelegate.getIsSyncable(account, mC ontractAuthority); | |
| 109 StrictMode.setThreadPolicy(oldPolicy); | |
| 110 mDidUpdate = (oldIsSyncable != mIsSyncable) | |
| 111 || (oldSyncAutomatically != mSyncAutomatically) | |
| 112 || (!account.equals(oldAccount)); | |
| 113 } | |
| 114 | |
| 115 @VisibleForTesting | |
| 116 protected void setIsSyncableInternal(Account account) { | |
| 117 mIsSyncable = 1; | |
| 118 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites (); | |
| 119 mSyncContentResolverDelegate.setIsSyncable(account, mContractAuthori ty, 1); | |
| 120 StrictMode.setThreadPolicy(oldPolicy); | |
| 121 mDidUpdate = true; | |
| 122 } | |
| 123 | |
| 124 @VisibleForTesting | |
| 125 protected void setSyncAutomaticallyInternal(Account account, boolean val ue) { | |
| 126 mSyncAutomatically = value; | |
| 127 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites (); | |
| 128 mSyncContentResolverDelegate.setSyncAutomatically(account, mContract Authority, value); | |
| 129 StrictMode.setThreadPolicy(oldPolicy); | |
| 130 mDidUpdate = true; | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 public static final String TAG = "AndroidSyncSettings"; | 29 public static final String TAG = "AndroidSyncSettings"; |
| 135 | 30 |
| 136 /** | 31 // Lock for ensuring singleton instantiation across threads. |
| 137 * Lock for ensuring singleton instantiation across threads. | 32 private static final Object LOCK = new Object(); |
| 138 */ | |
| 139 private static final Object INSTANCE_LOCK = new Object(); | |
| 140 | 33 |
| 141 private static AndroidSyncSettings sAndroidSyncSettings; | 34 private static AndroidSyncSettings sAndroidSyncSettings; |
| 142 | 35 |
| 143 private final String mContractAuthority; | 36 private final String mContractAuthority; |
| 144 | 37 |
| 145 private final Context mApplicationContext; | 38 private final Context mApplicationContext; |
| 146 | 39 |
| 147 private final SyncContentResolverDelegate mSyncContentResolverDelegate; | 40 private final SyncContentResolverDelegate mSyncContentResolverDelegate; |
| 148 | 41 |
| 149 private boolean mCachedMasterSyncAutomatically; | 42 private Account mAccount = null; |
| 150 | 43 |
| 151 // Instantiation of AndroidSyncSettings is guarded by a lock so volatile is unneeded. | 44 private boolean mIsSyncable = false; |
| 152 private CachedAccountSyncSettings mCachedSettings; | 45 |
| 46 private boolean mChromeSyncEnabled = false; | |
| 47 | |
| 48 private boolean mMasterSyncEnabled = false; | |
| 153 | 49 |
| 154 private final ObserverList<AndroidSyncSettingsObserver> mObservers = | 50 private final ObserverList<AndroidSyncSettingsObserver> mObservers = |
| 155 new ObserverList<AndroidSyncSettingsObserver>(); | 51 new ObserverList<AndroidSyncSettingsObserver>(); |
| 156 | 52 |
| 157 /** | 53 /** |
| 158 * Provides notifications when Android sync settings have changed. | 54 * Provides notifications when Android sync settings have changed. |
| 159 */ | 55 */ |
| 160 public interface AndroidSyncSettingsObserver { | 56 public interface AndroidSyncSettingsObserver { |
| 161 public void androidSyncSettingsChanged(); | 57 public void androidSyncSettingsChanged(); |
| 162 } | 58 } |
| 163 | 59 |
| 164 /** | 60 /** |
| 61 * A factory method for the AndroidSyncSettings. | |
| 62 * | |
| 63 * It is possible to override the {@link SyncContentResolverDelegate} to use in tests for the | |
| 64 * instance of the AndroidSyncSettings by calling overrideForTests(...) with | |
| 65 * your {@link SyncContentResolverDelegate}. | |
| 66 * | |
| 67 * @param context the ApplicationContext is retrieved from the context used as an argument. | |
| 68 * @return a singleton instance of the AndroidSyncSettings | |
| 69 */ | |
| 70 public static AndroidSyncSettings get(Context context) { | |
| 71 synchronized (LOCK) { | |
| 72 if (sAndroidSyncSettings == null) { | |
| 73 SyncContentResolverDelegate contentResolver = | |
| 74 new SystemSyncContentResolverDelegate(); | |
| 75 sAndroidSyncSettings = new AndroidSyncSettings(context, contentR esolver); | |
| 76 } | |
| 77 } | |
| 78 return sAndroidSyncSettings; | |
| 79 } | |
| 80 | |
| 81 @VisibleForTesting | |
| 82 public static void overrideForTests(Context context, | |
| 83 SyncContentResolverDelegate contentResolver) { | |
| 84 synchronized (LOCK) { | |
| 85 sAndroidSyncSettings = new AndroidSyncSettings(context, contentResol ver); | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 /** | |
| 165 * @param context the context | 90 * @param context the context |
| 166 * @param syncContentResolverDelegate an implementation of {@link SyncConten tResolverDelegate}. | 91 * @param syncContentResolverDelegate an implementation of {@link SyncConten tResolverDelegate}. |
| 167 */ | 92 */ |
| 168 private AndroidSyncSettings(Context context, | 93 private AndroidSyncSettings(Context context, |
| 169 SyncContentResolverDelegate syncContentResolverDelegate, | 94 SyncContentResolverDelegate syncContentResolverDelegate) { |
| 170 CachedAccountSyncSettings cachedAccountSettings) { | |
| 171 mApplicationContext = context.getApplicationContext(); | 95 mApplicationContext = context.getApplicationContext(); |
| 172 mSyncContentResolverDelegate = syncContentResolverDelegate; | 96 mSyncContentResolverDelegate = syncContentResolverDelegate; |
| 173 mContractAuthority = getContractAuthority(); | 97 mContractAuthority = getContractAuthority(); |
| 174 mCachedSettings = cachedAccountSettings; | |
| 175 | 98 |
| 176 updateMasterSyncAutomaticallySetting(); | 99 updateCachedSettings(); |
| 177 | 100 |
| 178 mSyncContentResolverDelegate.addStatusChangeListener( | 101 mSyncContentResolverDelegate.addStatusChangeListener( |
| 179 ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, | 102 ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, |
| 180 new AndroidSyncSettingsChangedObserver()); | 103 new AndroidSyncSettingsChangedObserver()); |
| 181 } | 104 } |
| 182 | 105 |
| 183 private void updateMasterSyncAutomaticallySetting() { | |
| 184 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); | |
| 185 synchronized (mCachedSettings) { | |
| 186 mCachedMasterSyncAutomatically = mSyncContentResolverDelegate | |
| 187 .getMasterSyncAutomatically(); | |
| 188 } | |
| 189 StrictMode.setThreadPolicy(oldPolicy); | |
| 190 } | |
| 191 | |
| 192 /** | 106 /** |
| 193 * A factory method for the AndroidSyncSettings. | |
| 194 * | |
| 195 * It is possible to override the {@link SyncContentResolverDelegate} to use in tests for the | |
| 196 * instance of the AndroidSyncSettings by calling overrideAndroidSyncSetting sForTests(...) with | |
| 197 * your {@link SyncContentResolverDelegate}. | |
| 198 * | |
| 199 * @param context the ApplicationContext is retrieved from the context used as an argument. | |
| 200 * @return a singleton instance of the AndroidSyncSettings | |
| 201 */ | |
| 202 public static AndroidSyncSettings get(Context context) { | |
| 203 synchronized (INSTANCE_LOCK) { | |
| 204 if (sAndroidSyncSettings == null) { | |
| 205 SyncContentResolverDelegate contentResolverDelegate = | |
| 206 new SystemSyncContentResolverDelegate(); | |
| 207 CachedAccountSyncSettings cache = new CachedAccountSyncSettings( | |
| 208 context.getPackageName(), contentResolverDelegate); | |
| 209 sAndroidSyncSettings = new AndroidSyncSettings( | |
| 210 context, contentResolverDelegate, cache); | |
| 211 } | |
| 212 } | |
| 213 return sAndroidSyncSettings; | |
| 214 } | |
| 215 | |
| 216 /** | |
| 217 * Tests might want to consider overriding the context and {@link SyncConten tResolverDelegate} | |
| 218 * so they do not use the real ContentResolver in Android. | |
| 219 * | |
| 220 * @param context the context to use | |
| 221 * @param syncContentResolverDelegate the {@link SyncContentResolverDelegate } to use | |
| 222 */ | |
| 223 @VisibleForTesting | |
| 224 public static void overrideAndroidSyncSettingsForTests(Context context, | |
| 225 SyncContentResolverDelegate syncContentResolverDelegate, | |
| 226 CachedAccountSyncSettings cachedAccountSettings) { | |
| 227 synchronized (INSTANCE_LOCK) { | |
| 228 if (sAndroidSyncSettings != null) { | |
| 229 throw new IllegalStateException("AndroidSyncSettings already exi sts"); | |
| 230 } | |
| 231 sAndroidSyncSettings = new AndroidSyncSettings(context, syncContentR esolverDelegate, | |
| 232 cachedAccountSettings); | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 @VisibleForTesting | |
| 237 public static void overrideAndroidSyncSettingsForTests(Context context, | |
| 238 SyncContentResolverDelegate syncContentResolverDelegate) { | |
| 239 CachedAccountSyncSettings cachedAccountSettings = new CachedAccountSyncS ettings( | |
| 240 context.getPackageName(), syncContentResolverDelegate); | |
| 241 overrideAndroidSyncSettingsForTests(context, syncContentResolverDelegate , | |
| 242 cachedAccountSettings); | |
| 243 } | |
| 244 | |
| 245 /** | |
| 246 * Returns the contract authority to use when requesting sync. | |
| 247 */ | |
| 248 public String getContractAuthority() { | |
| 249 return mApplicationContext.getPackageName(); | |
| 250 } | |
| 251 | |
| 252 /** | |
| 253 * Add a new AndroidSyncSettingsObserver. | |
| 254 */ | |
| 255 public void registerObserver(AndroidSyncSettingsObserver observer) { | |
| 256 mObservers.addObserver(observer); | |
| 257 } | |
| 258 | |
| 259 /** | |
| 260 * Remove an AndroidSyncSettingsObserver that was previously added. | |
| 261 */ | |
| 262 public void unregisterObserver(AndroidSyncSettingsObserver observer) { | |
| 263 mObservers.removeObserver(observer); | |
| 264 } | |
| 265 | |
| 266 /** | |
| 267 * Checks whether sync is currently enabled from Chrome for a given account. | |
| 268 * | |
| 269 * It checks both the master sync for the device, and Chrome sync setting fo r the given account. | |
| 270 * | |
| 271 * @param account the account to check if Chrome sync is enabled on. | |
| 272 * @return true if sync is on, false otherwise | |
| 273 */ | |
| 274 public boolean isSyncEnabled(Account account) { | |
| 275 if (account == null) return false; | |
| 276 boolean returnValue; | |
| 277 synchronized (mCachedSettings) { | |
| 278 returnValue = mCachedMasterSyncAutomatically | |
| 279 && mCachedSettings.getSyncAutomatically(account); | |
| 280 } | |
| 281 | |
| 282 notifyObserversIfAccountSettingsChanged(); | |
| 283 return returnValue; | |
| 284 } | |
| 285 | |
| 286 /** | |
| 287 * Checks whether sync is currently enabled from Chrome for the currently si gned in account. | 107 * Checks whether sync is currently enabled from Chrome for the currently si gned in account. |
| 288 * | 108 * |
| 289 * It checks both the master sync for the device, and Chrome sync setting fo r the given account. | 109 * It checks both the master sync for the device, and Chrome sync setting fo r the given account. |
| 290 * If no user is currently signed in it returns false. | 110 * If no user is currently signed in it returns false. |
| 291 * | 111 * |
| 292 * @return true if sync is on, false otherwise | 112 * @return true if sync is on, false otherwise |
| 293 */ | 113 */ |
| 294 public boolean isSyncEnabled() { | 114 public boolean isSyncEnabled() { |
| 295 return isSyncEnabled(ChromeSigninController.get(mApplicationContext).get SignedInUser()); | 115 return mMasterSyncEnabled && mChromeSyncEnabled; |
| 296 } | 116 } |
| 297 | 117 |
| 298 /** | 118 /** |
| 299 * Checks whether sync is currently enabled from Chrome for a given account. | 119 * Checks whether sync is currently enabled from Chrome for a given account. |
| 300 * | 120 * |
| 301 * It checks only Chrome sync setting for the given account, | 121 * It checks only Chrome sync setting for the given account, |
| 302 * and ignores the master sync setting. | 122 * and ignores the master sync setting. |
| 303 * | 123 * |
| 304 * @param account the account to check if Chrome sync is enabled on. | 124 * @param account the account to check if Chrome sync is enabled on. |
| 305 * @return true if sync is on, false otherwise | 125 * @return true if sync is on, false otherwise |
| 306 */ | 126 */ |
| 307 public boolean isChromeSyncEnabled(Account account) { | 127 public boolean isChromeSyncEnabled() { |
| 308 if (account == null) return false; | 128 return mChromeSyncEnabled; |
| 309 | |
| 310 boolean returnValue; | |
| 311 synchronized (mCachedSettings) { | |
| 312 returnValue = mCachedSettings.getSyncAutomatically(account); | |
| 313 } | |
| 314 | |
| 315 notifyObserversIfAccountSettingsChanged(); | |
| 316 return returnValue; | |
| 317 } | 129 } |
| 318 | 130 |
| 319 /** | 131 /** |
| 320 * Checks whether the master sync flag for Android is currently set. | 132 * Checks whether the master sync flag for Android is currently enabled. |
| 321 * | |
| 322 * @return true if the global master sync is on, false otherwise | |
| 323 */ | 133 */ |
| 324 public boolean isMasterSyncEnabled() { | 134 public boolean isMasterSyncEnabled() { |
| 325 synchronized (mCachedSettings) { | 135 return mMasterSyncEnabled; |
| 326 return mCachedMasterSyncAutomatically; | 136 } |
| 137 | |
| 138 /** | |
| 139 * Make sure Chrome is syncable, and enable sync. | |
| 140 */ | |
| 141 public void enableChromeSync() { | |
| 142 makeSyncable(); | |
| 143 setChromeSyncEnabled(true); | |
|
nyquist
2015/02/06 03:03:56
This class is marked as @ThreadSafe. Is it still s
maxbogue
2015/02/10 09:20:00
makeSyncable is now ensureSyncable and is called f
| |
| 144 } | |
| 145 | |
| 146 /** | |
| 147 * Disables Android Chrome sync | |
| 148 */ | |
| 149 public void disableChromeSync() { | |
| 150 setChromeSyncEnabled(false); | |
| 151 } | |
| 152 | |
| 153 /** | |
| 154 * Must be called when a new account is signed in. | |
| 155 */ | |
| 156 public void updateAccount(Account account) { | |
| 157 mAccount = account; | |
| 158 if (updateCachedSettings()) { | |
| 159 notifyObservers(); | |
| 327 } | 160 } |
| 328 } | 161 } |
| 329 | 162 |
| 330 /** | 163 /** |
| 331 * Make sure Chrome is syncable, and enable sync. | 164 * Returns the contract authority to use when requesting sync. |
| 332 * | |
| 333 * @param account the account to enable sync on | |
| 334 */ | 165 */ |
| 335 public void enableChromeSync(Account account) { | 166 public String getContractAuthority() { |
| 336 makeSyncable(account); | 167 return mApplicationContext.getPackageName(); |
| 337 | |
| 338 synchronized (mCachedSettings) { | |
| 339 mCachedSettings.setSyncAutomatically(account, true); | |
| 340 } | |
| 341 | |
| 342 notifyObserversIfAccountSettingsChanged(); | |
| 343 } | 168 } |
| 344 | 169 |
| 345 /** | 170 /** |
| 346 * Disables Android Chrome sync | 171 * Add a new AndroidSyncSettingsObserver. |
| 347 * | |
| 348 * @param account the account to disable Chrome sync on | |
| 349 */ | 172 */ |
| 350 public void disableChromeSync(Account account) { | 173 public void registerObserver(AndroidSyncSettingsObserver observer) { |
| 351 synchronized (mCachedSettings) { | 174 mObservers.addObserver(observer); |
|
nyquist
2015/02/06 03:03:56
I believe ObserverList is marked @NotThreadSafe, b
maxbogue
2015/02/10 09:20:00
Done for register and unregister.
| |
| 352 mCachedSettings.setSyncAutomatically(account, false); | |
| 353 } | |
| 354 | |
| 355 notifyObserversIfAccountSettingsChanged(); | |
| 356 } | 175 } |
| 357 | 176 |
| 358 /** | 177 /** |
| 359 * Register with Android Sync Manager. This is what causes the "Chrome" opti on to appear in | 178 * Remove an AndroidSyncSettingsObserver that was previously added. |
| 360 * Settings -> Accounts / Sync . | |
| 361 * | |
| 362 * @param account the account to enable Chrome sync on | |
| 363 */ | 179 */ |
| 364 private void makeSyncable(Account account) { | 180 public void unregisterObserver(AndroidSyncSettingsObserver observer) { |
| 365 synchronized (mCachedSettings) { | 181 mObservers.removeObserver(observer); |
| 366 mCachedSettings.setIsSyncable(account); | 182 } |
| 367 } | 183 |
| 184 private synchronized void setChromeSyncEnabled(boolean value) { | |
|
nyquist
2015/02/06 03:03:56
This synchronizes on the instance of this object,
maxbogue
2015/02/10 09:20:00
Done.
| |
| 185 if (value == mChromeSyncEnabled || mAccount == null) return; | |
| 186 mChromeSyncEnabled = value; | |
| 368 | 187 |
| 369 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); | 188 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); |
| 189 mSyncContentResolverDelegate.setSyncAutomatically(mAccount, mContractAut hority, value); | |
| 190 StrictMode.setThreadPolicy(oldPolicy); | |
| 191 | |
| 192 notifyObservers(); | |
| 193 } | |
| 194 | |
| 195 /** | |
| 196 * Register Chrome with the Android Sync Manager. | |
| 197 * | |
| 198 * This is what causes the "Chrome" option to appear in Settings -> Accounts / Sync . | |
| 199 */ | |
| 200 private synchronized void makeSyncable() { | |
| 201 if (mIsSyncable || mAccount == null) return; | |
| 202 | |
| 203 mIsSyncable = true; | |
| 204 | |
| 205 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); | |
| 206 mSyncContentResolverDelegate.setIsSyncable(mAccount, mContractAuthority, 1); | |
| 207 | |
| 370 // Disable the syncability of Chrome for all other accounts. Don't use | 208 // Disable the syncability of Chrome for all other accounts. Don't use |
| 371 // our cache as we're touching many accounts that aren't signed in, so t his saves | 209 // our cache as we're touching many accounts that aren't signed in, so t his saves |
| 372 // extra calls to Android sync configuration. | 210 // extra calls to Android sync configuration. |
| 373 Account[] googleAccounts = AccountManagerHelper.get(mApplicationContext) | 211 Account[] googleAccounts = AccountManagerHelper.get(mApplicationContext) |
| 374 .getGoogleAccounts(); | 212 .getGoogleAccounts(); |
| 375 for (Account accountToSetNotSyncable : googleAccounts) { | 213 for (Account accountToSetNotSyncable : googleAccounts) { |
| 376 if (!accountToSetNotSyncable.equals(account) | 214 if (!accountToSetNotSyncable.equals(mAccount) |
| 377 && mSyncContentResolverDelegate.getIsSyncable( | 215 && mSyncContentResolverDelegate.getIsSyncable( |
| 378 accountToSetNotSyncable, mContractAuthority) > 0) { | 216 accountToSetNotSyncable, mContractAuthority) > 0) { |
| 379 mSyncContentResolverDelegate.setIsSyncable(accountToSetNotSyncab le, | 217 mSyncContentResolverDelegate.setIsSyncable(accountToSetNotSyncab le, |
| 380 mContractAuthority, 0); | 218 mContractAuthority, 0); |
| 381 } | 219 } |
| 382 } | 220 } |
| 383 StrictMode.setThreadPolicy(oldPolicy); | 221 StrictMode.setThreadPolicy(oldPolicy); |
| 384 } | 222 } |
| 385 | 223 |
| 386 /** | 224 /** |
| 387 * Helper class to be used by observers whenever sync settings change. | 225 * Helper class to be used by observers whenever sync settings change. |
| 388 * | 226 * |
| 389 * To register the observer, call AndroidSyncSettings.registerObserver(...). | 227 * To register the observer, call AndroidSyncSettings.registerObserver(...). |
| 390 */ | 228 */ |
| 391 private class AndroidSyncSettingsChangedObserver implements SyncStatusObserv er { | 229 private class AndroidSyncSettingsChangedObserver implements SyncStatusObserv er { |
| 392 @Override | 230 @Override |
| 393 public void onStatusChanged(int which) { | 231 public void onStatusChanged(int which) { |
| 394 if (ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS == which) { | 232 if (which == ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS) { |
| 395 // Sync settings have changed; update our in-memory caches | 233 // Sync settings have changed; update our cached values. |
| 396 synchronized (mCachedSettings) { | 234 if (updateCachedSettings()) { |
| 397 mCachedSettings.updateSyncSettingsForAccount( | 235 // If something actually changed, tell our observers. |
| 398 ChromeSigninController.get(mApplicationContext).getS ignedInUser()); | |
| 399 } | |
| 400 | |
| 401 boolean oldMasterSyncEnabled = isMasterSyncEnabled(); | |
| 402 updateMasterSyncAutomaticallySetting(); | |
| 403 boolean didMasterSyncChanged = oldMasterSyncEnabled != isMasterS yncEnabled(); | |
| 404 // Notify observers if MasterSync or account level settings chan ge. | |
| 405 if (didMasterSyncChanged || getAndClearDidUpdateStatus()) { | |
| 406 notifyObservers(); | 236 notifyObservers(); |
| 407 } | 237 } |
| 408 } | 238 } |
| 409 } | 239 } |
| 410 } | 240 } |
| 411 | 241 |
| 412 private boolean getAndClearDidUpdateStatus() { | 242 /** |
| 413 boolean didGetStatusUpdate; | 243 * Update the three cached settings from the content resolver. |
| 414 synchronized (mCachedSettings) { | 244 * |
| 415 didGetStatusUpdate = mCachedSettings.getDidUpdateStatus(); | 245 * @return Whether either chromeSyncEnabled or masterSyncEnabled changed. |
| 416 mCachedSettings.clearUpdateStatus(); | 246 */ |
| 247 private synchronized boolean updateCachedSettings() { | |
| 248 boolean oldChromeSyncEnabled = mChromeSyncEnabled; | |
| 249 boolean oldMasterSyncEnabled = mMasterSyncEnabled; | |
| 250 | |
| 251 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); | |
| 252 if (mAccount != null) { | |
| 253 mIsSyncable = mSyncContentResolverDelegate.getIsSyncable( | |
| 254 mAccount, mContractAuthority) == 1; | |
| 255 mChromeSyncEnabled = mSyncContentResolverDelegate.getSyncAutomatical ly( | |
| 256 mAccount, mContractAuthority); | |
| 257 } else { | |
| 258 mIsSyncable = false; | |
| 259 mChromeSyncEnabled = false; | |
| 417 } | 260 } |
| 418 return didGetStatusUpdate; | 261 mMasterSyncEnabled = mSyncContentResolverDelegate.getMasterSyncAutomatic ally(); |
| 419 } | 262 StrictMode.setThreadPolicy(oldPolicy); |
| 420 | 263 |
| 421 private void notifyObserversIfAccountSettingsChanged() { | 264 return oldChromeSyncEnabled != mChromeSyncEnabled |
| 422 if (getAndClearDidUpdateStatus()) { | 265 || oldMasterSyncEnabled != mMasterSyncEnabled; |
| 423 notifyObservers(); | |
| 424 } | |
| 425 } | 266 } |
| 426 | 267 |
| 427 private void notifyObservers() { | 268 private void notifyObservers() { |
| 428 for (AndroidSyncSettingsObserver observer : mObservers) { | 269 for (AndroidSyncSettingsObserver observer : mObservers) { |
|
nyquist
2015/02/06 03:03:56
I don't think it's thread safe to iterate over obs
maxbogue
2015/02/10 09:20:00
From ObserverList.java: This container can be modi
| |
| 429 observer.androidSyncSettingsChanged(); | 270 observer.androidSyncSettingsChanged(); |
| 430 } | 271 } |
| 431 } | 272 } |
| 273 | |
| 274 @Deprecated | |
| 275 @VisibleForTesting | |
| 276 public static void overrideAndroidSyncSettingsForTests(Context context, | |
| 277 SyncContentResolverDelegate contentResolver) { | |
| 278 overrideForTests(context, contentResolver); | |
| 279 } | |
| 280 | |
| 281 @Deprecated | |
| 282 public boolean isChromeSyncEnabled(Account account) { | |
| 283 return isChromeSyncEnabled(); | |
| 284 } | |
| 285 | |
| 286 @Deprecated | |
| 287 public boolean isSyncEnabled(Account account) { | |
| 288 return isSyncEnabled(); | |
| 289 } | |
| 432 } | 290 } |
| OLD | NEW |