Home | History | Annotate | Download | only in testing
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
      5  * except in compliance with the License. You may obtain a copy of the License at
      6  *
      7  *      http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the
     10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     11  * KIND, either express or implied. See the License for the specific language governing
     12  * permissions and limitations under the License.
     13  */
     14 
     15 package android.testing;
     16 
     17 import android.content.ContentProvider;
     18 import android.content.ContentResolver;
     19 import android.content.Context;
     20 import android.content.IContentProvider;
     21 import android.database.ContentObserver;
     22 import android.net.Uri;
     23 import android.util.ArrayMap;
     24 import android.util.ArraySet;
     25 
     26 import com.google.android.collect.Maps;
     27 
     28 import java.util.Map;
     29 
     30 /**
     31  * A version of ContentResolver that allows easy mocking of providers.
     32  * By default it acts as a normal ContentResolver and returns all the
     33  * same providers.
     34  * @see #addProvider(String, ContentProvider)
     35  * @see #setFallbackToExisting(boolean)
     36  */
     37 public class TestableContentResolver extends ContentResolver {
     38 
     39     public static final int STABLE = 1;
     40     public static final int UNSTABLE = 2;
     41 
     42     private final Map<String, ContentProvider> mProviders = new ArrayMap<>();
     43     private final Map<String, ContentProvider> mUnstableProviders = new ArrayMap<>();
     44     private final ContentResolver mParent;
     45     private final ArraySet<ContentProvider> mInUse = new ArraySet<>();
     46     private boolean mFallbackToExisting;
     47 
     48     public TestableContentResolver(Context context) {
     49         super(context);
     50         mParent = context.getContentResolver();
     51         mFallbackToExisting = true;
     52     }
     53 
     54     /**
     55      * Sets whether existing providers should be returned when a mock does not exist.
     56      * The default is true.
     57      */
     58     public void setFallbackToExisting(boolean fallbackToExisting) {
     59         mFallbackToExisting = fallbackToExisting;
     60     }
     61 
     62     /**
     63      * Adds access to a provider based on its authority
     64      *
     65      * @param name The authority name associated with the provider.
     66      * @param provider An instance of {@link android.content.ContentProvider} or one of its
     67      * subclasses, or null.
     68      */
     69     public void addProvider(String name, ContentProvider provider) {
     70         addProvider(name, provider, STABLE | UNSTABLE);
     71     }
     72 
     73     /**
     74      * Adds access to a provider based on its authority
     75      *
     76      * @param name The authority name associated with the provider.
     77      * @param provider An instance of {@link android.content.ContentProvider} or one of its
     78      * subclasses, or null.
     79      */
     80     public void addProvider(String name, ContentProvider provider, int flags) {
     81         if ((flags & STABLE) != 0) {
     82             mProviders.put(name, provider);
     83         }
     84         if ((flags & UNSTABLE) != 0) {
     85             mUnstableProviders.put(name, provider);
     86         }
     87     }
     88 
     89     @Override
     90     protected IContentProvider acquireProvider(Context context, String name) {
     91         final ContentProvider provider = mProviders.get(name);
     92         if (provider != null) {
     93             return provider.getIContentProvider();
     94         } else {
     95             return mFallbackToExisting ? mParent.acquireProvider(name) : null;
     96         }
     97     }
     98 
     99     @Override
    100     protected IContentProvider acquireExistingProvider(Context context, String name) {
    101         final ContentProvider provider = mProviders.get(name);
    102         if (provider != null) {
    103             return provider.getIContentProvider();
    104         } else {
    105             return mFallbackToExisting ? mParent.acquireExistingProvider(
    106                     new Uri.Builder().authority(name).build()) : null;
    107         }
    108     }
    109 
    110     @Override
    111     public boolean releaseProvider(IContentProvider provider) {
    112         if (!mFallbackToExisting) return true;
    113         if (mInUse.contains(provider)) {
    114             mInUse.remove(provider);
    115             return true;
    116         }
    117         return mParent.releaseProvider(provider);
    118     }
    119 
    120     @Override
    121     protected IContentProvider acquireUnstableProvider(Context c, String name) {
    122         final ContentProvider provider = mUnstableProviders.get(name);
    123         if (provider != null) {
    124             return provider.getIContentProvider();
    125         } else {
    126             return mFallbackToExisting ? mParent.acquireUnstableProvider(name) : null;
    127         }
    128     }
    129 
    130     @Override
    131     public boolean releaseUnstableProvider(IContentProvider icp) {
    132         if (!mFallbackToExisting) return true;
    133         if (mInUse.contains(icp)) {
    134             mInUse.remove(icp);
    135             return true;
    136         }
    137         return mParent.releaseUnstableProvider(icp);
    138     }
    139 
    140     @Override
    141     public void unstableProviderDied(IContentProvider icp) {
    142         if (!mFallbackToExisting) return;
    143         if (mInUse.contains(icp)) {
    144             return;
    145         }
    146         mParent.unstableProviderDied(icp);
    147     }
    148 
    149     @Override
    150     public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
    151         if (!mFallbackToExisting) return;
    152         if (!mProviders.containsKey(uri.getAuthority())
    153                 && !mUnstableProviders.containsKey(uri.getAuthority())) {
    154             super.notifyChange(uri, observer, syncToNetwork);
    155         }
    156     }
    157 }
    158