Home | History | Annotate | Download | only in interactions
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.contacts.interactions;
     18 
     19 import android.app.LoaderManager;
     20 import android.content.AsyncTaskLoader;
     21 import android.content.Loader;
     22 import android.os.Bundle;
     23 import android.util.Log;
     24 
     25 import com.google.common.annotations.VisibleForTesting;
     26 
     27 import junit.framework.Assert;
     28 
     29 import java.io.FileDescriptor;
     30 import java.io.PrintWriter;
     31 import java.util.ArrayList;
     32 import java.util.HashSet;
     33 import java.util.List;
     34 
     35 /**
     36  * This implementation of TestLoaderManagerBase uses hidden APIs and must therefore
     37  * be kept outside of the main Contacts apk.
     38  */
     39 public class TestLoaderManager extends TestLoaderManagerBase {
     40     private static final String TAG = "TestLoaderManager";
     41 
     42     private final HashSet<Integer> mFinishedLoaders;
     43 
     44     private LoaderManager mDelegate;
     45 
     46     @VisibleForTesting
     47     public TestLoaderManager() {
     48         mFinishedLoaders = new HashSet<Integer>();
     49     }
     50 
     51     /**
     52      * Sets the object to which we delegate the actual work.
     53      * <p>
     54      * It can not be set to null. Once set, it cannot be changed (but it allows setting it to the
     55      * same value again).
     56      */
     57     public void setDelegate(LoaderManager delegate) {
     58         if (delegate == null || (mDelegate != null && mDelegate != delegate)) {
     59             throw new IllegalArgumentException("TestLoaderManager cannot be shared");
     60         }
     61 
     62         mDelegate = delegate;
     63     }
     64 
     65     public LoaderManager getDelegate() {
     66         return mDelegate;
     67     }
     68 
     69     public void reset() {
     70         mFinishedLoaders.clear();
     71     }
     72 
     73     /**
     74      * Waits for the specified loaders to complete loading.
     75      * <p>
     76      * If one of the loaders has already completed since the last call to {@link #reset()}, it will
     77      * not wait for it to complete again.
     78      */
     79     @VisibleForTesting
     80     public synchronized void waitForLoaders(int... loaderIds) {
     81         List<Loader<?>> loaders = new ArrayList<Loader<?>>(loaderIds.length);
     82         for (int loaderId : loaderIds) {
     83             if (mFinishedLoaders.contains(loaderId)) {
     84                 // This loader has already completed since the last reset, do not wait for it.
     85                 continue;
     86             }
     87 
     88             final AsyncTaskLoader<?> loader =
     89                     (AsyncTaskLoader<?>) mDelegate.getLoader(loaderId);
     90             if (loader == null) {
     91                 Assert.fail("Loader does not exist: " + loaderId);
     92                 return;
     93             }
     94 
     95             loaders.add(loader);
     96         }
     97 
     98         waitForLoaders(loaders.toArray(new Loader<?>[0]));
     99     }
    100 
    101     /**
    102      * Waits for the specified loaders to complete loading.
    103      */
    104     public static void waitForLoaders(Loader<?>... loaders) {
    105         // We want to wait for each loader using a separate thread, so that we can
    106         // simulate race conditions.
    107         Thread[] waitThreads = new Thread[loaders.length];
    108         for (int i = 0; i < loaders.length; i++) {
    109             final AsyncTaskLoader<?> loader = (AsyncTaskLoader<?>) loaders[i];
    110             waitThreads[i] = new Thread("LoaderWaitingThread" + i) {
    111                 @Override
    112                 public void run() {
    113                     try {
    114                         AsyncTaskLoader.class.getMethod("waitForLoader").invoke(loader, null);
    115                     } catch (Throwable e) {
    116                         Log.e(TAG, "Exception while waiting for loader: " + loader.getId(), e);
    117                         Assert.fail("Exception while waiting for loader: " + loader.getId());
    118                     }
    119                 }
    120             };
    121             waitThreads[i].start();
    122         }
    123 
    124         // Now we wait for all these threads to finish
    125         for (Thread thread : waitThreads) {
    126             try {
    127                 thread.join();
    128             } catch (InterruptedException e) {
    129                 // Ignore
    130             }
    131         }
    132     }
    133 
    134     @Override
    135     public <D> Loader<D> initLoader(final int id, Bundle args, final LoaderCallbacks<D> callback) {
    136         return mDelegate.initLoader(id, args, new LoaderManager.LoaderCallbacks<D>() {
    137             @Override
    138             public Loader<D> onCreateLoader(int id, Bundle args) {
    139                 return callback.onCreateLoader(id, args);
    140             }
    141 
    142             @Override
    143             public void onLoadFinished(Loader<D> loader, D data) {
    144                 callback.onLoadFinished(loader, data);
    145                 synchronized (this) {
    146                     mFinishedLoaders.add(id);
    147                 }
    148             }
    149 
    150             @Override
    151             public void onLoaderReset(Loader<D> loader) {
    152                 callback.onLoaderReset(loader);
    153             }
    154         });
    155     }
    156 
    157     @Override
    158     public <D> Loader<D> restartLoader(int id, Bundle args, LoaderCallbacks<D> callback) {
    159         return mDelegate.restartLoader(id, args, callback);
    160     }
    161 
    162     @Override
    163     public void destroyLoader(int id) {
    164         mDelegate.destroyLoader(id);
    165     }
    166 
    167     @Override
    168     public <D> Loader<D> getLoader(int id) {
    169         return mDelegate.getLoader(id);
    170     }
    171 
    172     @Override
    173     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
    174         mDelegate.dump(prefix, fd, writer, args);
    175     }
    176 }
    177