• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TestableContentResolver(Context context)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      */
setFallbackToExisting(boolean fallbackToExisting)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      */
addProvider(String name, ContentProvider provider)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      */
addProvider(String name, ContentProvider provider, int flags)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
acquireProvider(Context context, String name)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
acquireExistingProvider(Context context, String name)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
releaseProvider(IContentProvider provider)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
acquireUnstableProvider(Context c, String name)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
releaseUnstableProvider(IContentProvider icp)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
unstableProviderDied(IContentProvider icp)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
notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork)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