blob: a0afef8fcda368783b00e9f1b73e30104bb94df7 [file] [log] [blame]
Jason Monke9789282016-11-09 08:59:56 -05001/*
Jason Monk340b0e52017-03-08 14:57:56 -05002 * Copyright (C) 2017 The Android Open Source Project
Jason Monke9789282016-11-09 08:59:56 -05003 *
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
Jason Monk340b0e52017-03-08 14:57:56 -050015package android.testing;
Jason Monke9789282016-11-09 08:59:56 -050016
17import android.content.ContentProvider;
18import android.content.ContentResolver;
19import android.content.Context;
20import android.content.IContentProvider;
21import android.database.ContentObserver;
22import android.net.Uri;
Jason Monke1c0c2c2018-07-03 11:08:32 -040023import android.util.ArrayMap;
Jason Monke9789282016-11-09 08:59:56 -050024import android.util.ArraySet;
25
26import com.google.android.collect.Maps;
27
28import java.util.Map;
29
30/**
Jason Monk0c408002017-05-03 15:43:52 -040031 * 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)
Jason Monke9789282016-11-09 08:59:56 -050036 */
Jason Monk340b0e52017-03-08 14:57:56 -050037public class TestableContentResolver extends ContentResolver {
Jason Monke9789282016-11-09 08:59:56 -050038
Jason Monke1c0c2c2018-07-03 11:08:32 -040039 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<>();
Jason Monke9789282016-11-09 08:59:56 -050044 private final ContentResolver mParent;
45 private final ArraySet<ContentProvider> mInUse = new ArraySet<>();
46 private boolean mFallbackToExisting;
47
Jason Monk340b0e52017-03-08 14:57:56 -050048 public TestableContentResolver(Context context) {
Jason Monke9789282016-11-09 08:59:56 -050049 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) {
Jason Monke1c0c2c2018-07-03 11:08:32 -040070 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 }
Jason Monke9789282016-11-09 08:59:56 -050087 }
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) {
Jason Monke1c0c2c2018-07-03 11:08:32 -0400122 final ContentProvider provider = mUnstableProviders.get(name);
Jason Monke9789282016-11-09 08:59:56 -0500123 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;
Jason Monke1c0c2c2018-07-03 11:08:32 -0400152 if (!mProviders.containsKey(uri.getAuthority())
153 && !mUnstableProviders.containsKey(uri.getAuthority())) {
Jason Monke9789282016-11-09 08:59:56 -0500154 super.notifyChange(uri, observer, syncToNetwork);
155 }
156 }
157}