| OLD | NEW |
| (Empty) |
| 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 | |
| 5 package org.chromium.sync.test.util; | |
| 6 | |
| 7 | |
| 8 import android.accounts.Account; | |
| 9 import android.content.ContentResolver; | |
| 10 import android.content.SyncStatusObserver; | |
| 11 import android.os.AsyncTask; | |
| 12 import android.os.Bundle; | |
| 13 | |
| 14 import junit.framework.Assert; | |
| 15 | |
| 16 import org.chromium.base.ThreadUtils; | |
| 17 import org.chromium.base.VisibleForTesting; | |
| 18 import org.chromium.sync.SyncContentResolverDelegate; | |
| 19 | |
| 20 import java.util.HashMap; | |
| 21 import java.util.HashSet; | |
| 22 import java.util.Map; | |
| 23 import java.util.Set; | |
| 24 import java.util.concurrent.Semaphore; | |
| 25 import java.util.concurrent.TimeUnit; | |
| 26 | |
| 27 | |
| 28 /** | |
| 29 * Mock implementation of the {@link SyncContentResolverDelegate}. | |
| 30 * | |
| 31 * This implementation only supports status change listeners for the type | |
| 32 * SYNC_OBSERVER_TYPE_SETTINGS. | |
| 33 */ | |
| 34 public class MockSyncContentResolverDelegate implements SyncContentResolverDeleg
ate { | |
| 35 | |
| 36 private final Set<String> mSyncAutomaticallySet; | |
| 37 private final Map<String, Boolean> mIsSyncableMap; | |
| 38 private final Object mSyncableMapLock = new Object(); | |
| 39 | |
| 40 private final Set<AsyncSyncStatusObserver> mObservers; | |
| 41 | |
| 42 private boolean mMasterSyncAutomatically; | |
| 43 private boolean mDisableObserverNotifications; | |
| 44 | |
| 45 private Semaphore mPendingObserverCount; | |
| 46 | |
| 47 public MockSyncContentResolverDelegate() { | |
| 48 mSyncAutomaticallySet = new HashSet<String>(); | |
| 49 mIsSyncableMap = new HashMap<String, Boolean>(); | |
| 50 mObservers = new HashSet<AsyncSyncStatusObserver>(); | |
| 51 } | |
| 52 | |
| 53 @Override | |
| 54 public Object addStatusChangeListener(int mask, SyncStatusObserver callback)
{ | |
| 55 if (mask != ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS) { | |
| 56 throw new IllegalArgumentException("This implementation only support
s " | |
| 57 + "ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS as the mask")
; | |
| 58 } | |
| 59 AsyncSyncStatusObserver asyncSyncStatusObserver = new AsyncSyncStatusObs
erver(callback); | |
| 60 synchronized (mObservers) { | |
| 61 mObservers.add(asyncSyncStatusObserver); | |
| 62 } | |
| 63 return asyncSyncStatusObserver; | |
| 64 } | |
| 65 | |
| 66 @Override | |
| 67 public void removeStatusChangeListener(Object handle) { | |
| 68 synchronized (mObservers) { | |
| 69 mObservers.remove(handle); | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 @Override | |
| 74 @VisibleForTesting | |
| 75 public void setMasterSyncAutomatically(boolean sync) { | |
| 76 if (mMasterSyncAutomatically == sync) return; | |
| 77 | |
| 78 mMasterSyncAutomatically = sync; | |
| 79 notifyObservers(); | |
| 80 } | |
| 81 | |
| 82 @Override | |
| 83 public boolean getMasterSyncAutomatically() { | |
| 84 return mMasterSyncAutomatically; | |
| 85 } | |
| 86 | |
| 87 @Override | |
| 88 public boolean getSyncAutomatically(Account account, String authority) { | |
| 89 String key = createKey(account, authority); | |
| 90 synchronized (mSyncableMapLock) { | |
| 91 return mSyncAutomaticallySet.contains(key); | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 @Override | |
| 96 public void setSyncAutomatically(Account account, String authority, boolean
sync) { | |
| 97 String key = createKey(account, authority); | |
| 98 synchronized (mSyncableMapLock) { | |
| 99 if (!mIsSyncableMap.containsKey(key) || !mIsSyncableMap.get(key)) { | |
| 100 throw new IllegalArgumentException("Account " + account | |
| 101 + " is not syncable for authority " + authority | |
| 102 + ". Can not set sync state to " + sync); | |
| 103 } | |
| 104 if (sync) { | |
| 105 mSyncAutomaticallySet.add(key); | |
| 106 } else if (mSyncAutomaticallySet.contains(key)) { | |
| 107 mSyncAutomaticallySet.remove(key); | |
| 108 } | |
| 109 } | |
| 110 notifyObservers(); | |
| 111 } | |
| 112 | |
| 113 @Override | |
| 114 public void setIsSyncable(Account account, String authority, int syncable) { | |
| 115 String key = createKey(account, authority); | |
| 116 | |
| 117 synchronized (mSyncableMapLock) { | |
| 118 switch (syncable) { | |
| 119 case 0: | |
| 120 mIsSyncableMap.put(key, false); | |
| 121 break; | |
| 122 case 1: | |
| 123 mIsSyncableMap.put(key, true); | |
| 124 break; | |
| 125 case -1: | |
| 126 if (mIsSyncableMap.containsKey(key)) { | |
| 127 mIsSyncableMap.remove(key); | |
| 128 } | |
| 129 break; | |
| 130 default: | |
| 131 throw new IllegalArgumentException("Unable to understand syn
cable argument: " | |
| 132 + syncable); | |
| 133 } | |
| 134 } | |
| 135 notifyObservers(); | |
| 136 } | |
| 137 | |
| 138 @Override | |
| 139 public int getIsSyncable(Account account, String authority) { | |
| 140 String key = createKey(account, authority); | |
| 141 synchronized (mSyncableMapLock) { | |
| 142 if (mIsSyncableMap.containsKey(key)) { | |
| 143 return mIsSyncableMap.get(key) ? 1 : 0; | |
| 144 } else { | |
| 145 return -1; | |
| 146 } | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 @Override | |
| 151 public void removePeriodicSync(Account account, String authority, Bundle ext
ras) { | |
| 152 } | |
| 153 | |
| 154 private static String createKey(Account account, String authority) { | |
| 155 return account.name + "@@@" + account.type + "@@@" + authority; | |
| 156 } | |
| 157 | |
| 158 private void notifyObservers() { | |
| 159 if (mDisableObserverNotifications) return; | |
| 160 synchronized (mObservers) { | |
| 161 mPendingObserverCount = new Semaphore(1 - mObservers.size()); | |
| 162 for (AsyncSyncStatusObserver observer : mObservers) { | |
| 163 observer.notifyObserverAsync(mPendingObserverCount); | |
| 164 } | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 /** | |
| 169 * Blocks until the last notification has been issued to all registered obse
rvers. | |
| 170 * Note that if an observer is removed while a notification is being handled
this can | |
| 171 * fail to return correctly. | |
| 172 * | |
| 173 * @throws InterruptedException | |
| 174 */ | |
| 175 @VisibleForTesting | |
| 176 public void waitForLastNotificationCompleted() throws InterruptedException { | |
| 177 Assert.assertTrue("Timed out waiting for notifications to complete.", | |
| 178 mPendingObserverCount.tryAcquire(5, TimeUnit.SECONDS)); | |
| 179 } | |
| 180 | |
| 181 public void disableObserverNotifications() { | |
| 182 mDisableObserverNotifications = true; | |
| 183 } | |
| 184 | |
| 185 /** | |
| 186 * Simulate an account rename, which copies settings to the new account. | |
| 187 */ | |
| 188 public void renameAccounts(Account oldAccount, Account newAccount, String au
thority) { | |
| 189 int oldIsSyncable = getIsSyncable(oldAccount, authority); | |
| 190 setIsSyncable(newAccount, authority, oldIsSyncable); | |
| 191 if (oldIsSyncable == 1) { | |
| 192 setSyncAutomatically( | |
| 193 newAccount, authority, getSyncAutomatically(oldAccount, auth
ority)); | |
| 194 } | |
| 195 } | |
| 196 | |
| 197 private static class AsyncSyncStatusObserver { | |
| 198 | |
| 199 private final SyncStatusObserver mSyncStatusObserver; | |
| 200 | |
| 201 private AsyncSyncStatusObserver(SyncStatusObserver syncStatusObserver) { | |
| 202 mSyncStatusObserver = syncStatusObserver; | |
| 203 } | |
| 204 | |
| 205 private void notifyObserverAsync(final Semaphore pendingObserverCount) { | |
| 206 if (ThreadUtils.runningOnUiThread()) { | |
| 207 new AsyncTask<Void, Void, Void>() { | |
| 208 @Override | |
| 209 protected Void doInBackground(Void... params) { | |
| 210 mSyncStatusObserver.onStatusChanged( | |
| 211 ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); | |
| 212 return null; | |
| 213 } | |
| 214 | |
| 215 @Override | |
| 216 protected void onPostExecute(Void result) { | |
| 217 pendingObserverCount.release(); | |
| 218 } | |
| 219 }.execute(); | |
| 220 } else { | |
| 221 mSyncStatusObserver.onStatusChanged( | |
| 222 ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); | |
| 223 pendingObserverCount.release(); | |
| 224 } | |
| 225 } | |
| 226 } | |
| 227 } | |
| OLD | NEW |