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 |