| 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 |