1 /*
2  * Copyright (C) 2009 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 android.test.mock;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.AttributionSource;
22 import android.content.ContentProvider;
23 import android.content.ContentProviderOperation;
24 import android.content.ContentProviderResult;
25 import android.content.ContentResolver;
26 import android.content.ContentValues;
27 import android.content.Context;
28 import android.content.IContentProvider;
29 import android.content.Intent;
30 import android.content.OperationApplicationException;
31 import android.content.pm.PathPermission;
32 import android.content.pm.ProviderInfo;
33 import android.content.res.AssetFileDescriptor;
34 import android.database.Cursor;
35 import android.net.Uri;
36 import android.os.AsyncTask;
37 import android.os.Binder;
38 import android.os.Bundle;
39 import android.os.IBinder;
40 import android.os.ICancellationSignal;
41 import android.os.ParcelFileDescriptor;
42 import android.os.RemoteCallback;
43 import android.os.RemoteException;
44 
45 import java.io.FileNotFoundException;
46 import java.util.ArrayList;
47 
48 /**
49  * Mock implementation of ContentProvider.  All methods are non-functional and throw
50  * {@link java.lang.UnsupportedOperationException}.  Tests can extend this class to
51  * implement behavior needed for tests.
52  */
53 public class MockContentProvider extends ContentProvider {
54     /*
55      * Note: if you add methods to ContentProvider, you must add similar methods to
56      *       MockContentProvider.
57      */
58 
59     /**
60      * IContentProvider that directs all calls to this MockContentProvider.
61      */
62     private class InversionIContentProvider implements IContentProvider {
63         @Override
applyBatch(@onNull AttributionSource attributionSource, String authority, ArrayList<ContentProviderOperation> operations)64         public ContentProviderResult[] applyBatch(@NonNull AttributionSource attributionSource,
65                 String authority, ArrayList<ContentProviderOperation> operations)
66                 throws RemoteException, OperationApplicationException {
67             return MockContentProvider.this.applyBatch(authority, operations);
68         }
69 
70         @Override
bulkInsert(@onNull AttributionSource attributionSource, Uri url, ContentValues[] initialValues)71         public int bulkInsert(@NonNull AttributionSource attributionSource, Uri url,
72                 ContentValues[] initialValues) throws RemoteException {
73             return MockContentProvider.this.bulkInsert(url, initialValues);
74         }
75 
76         @Override
delete(@onNull AttributionSource attributionSource, Uri url, Bundle extras)77         public int delete(@NonNull AttributionSource attributionSource, Uri url,
78                 Bundle extras) throws RemoteException {
79             return MockContentProvider.this.delete(url, extras);
80         }
81 
82         @Override
getType(@onNull AttributionSource attributionSource, Uri url)83         public String getType(@NonNull AttributionSource attributionSource,
84                 Uri url) throws RemoteException {
85             return MockContentProvider.this.getType(url);
86         }
87 
88         @Override
getTypeAsync(@onNull AttributionSource attributionSource, Uri uri, RemoteCallback callback)89         public void getTypeAsync(@NonNull AttributionSource attributionSource,
90                 Uri uri, RemoteCallback callback) throws RemoteException {
91             MockContentProvider.this.getTypeAsync(uri, callback);
92         }
93 
94         @Override
getTypeAnonymousAsync(Uri uri, RemoteCallback callback)95         public void getTypeAnonymousAsync(Uri uri, RemoteCallback callback) throws RemoteException {
96             MockContentProvider.this.getTypeAnonymousAsync(uri, callback);
97         }
98         @Override
insert(@onNull AttributionSource attributionSource, Uri url, ContentValues initialValues, Bundle extras)99         public Uri insert(@NonNull AttributionSource attributionSource, Uri url,
100                 ContentValues initialValues, Bundle extras) throws RemoteException {
101             return MockContentProvider.this.insert(url, initialValues, extras);
102         }
103 
104         @Override
openAssetFile(@onNull AttributionSource attributionSource, Uri url, String mode, ICancellationSignal signal)105         public AssetFileDescriptor openAssetFile(@NonNull AttributionSource attributionSource,
106                 Uri url, String mode, ICancellationSignal signal)
107                 throws RemoteException, FileNotFoundException {
108             return MockContentProvider.this.openAssetFile(url, mode);
109         }
110 
111         @Override
openFile(@onNull AttributionSource attributionSource, Uri url, String mode, ICancellationSignal signal)112         public ParcelFileDescriptor openFile(@NonNull AttributionSource attributionSource,
113                 Uri url, String mode, ICancellationSignal signal)
114                 throws RemoteException, FileNotFoundException {
115             return MockContentProvider.this.openFile(url, mode);
116         }
117 
118         @Override
query(@onNull AttributionSource attributionSource, Uri url, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)119         public Cursor query(@NonNull AttributionSource attributionSource, Uri url,
120                 @Nullable String[] projection, @Nullable Bundle queryArgs,
121                 @Nullable ICancellationSignal cancellationSignal) throws RemoteException {
122             return MockContentProvider.this.query(url, projection, queryArgs, null);
123         }
124 
125         @Override
update(@onNull AttributionSource attributionSource, Uri url, ContentValues values, Bundle extras)126         public int update(@NonNull AttributionSource attributionSource, Uri url,
127                 ContentValues values, Bundle extras) throws RemoteException {
128             return MockContentProvider.this.update(url, values, extras);
129         }
130 
131         @Override
call(@onNull AttributionSource attributionSource, String authority, String method, String request, Bundle args)132         public Bundle call(@NonNull AttributionSource attributionSource, String authority,
133                 String method, String request, Bundle args) throws RemoteException {
134             return MockContentProvider.this.call(authority, method, request, args);
135         }
136 
137         @Override
asBinder()138         public IBinder asBinder() {
139             return MockContentProvider.this.getIContentProviderBinder();
140         }
141 
142         @Override
getStreamTypes(AttributionSource attributionSource, Uri url, String mimeTypeFilter)143         public String[] getStreamTypes(AttributionSource attributionSource,
144                 Uri url, String mimeTypeFilter) throws RemoteException {
145             return MockContentProvider.this.getStreamTypes(url, mimeTypeFilter);
146         }
147 
148         @Override
openTypedAssetFile( @onNull AttributionSource attributionSource, Uri url, String mimeType, Bundle opts, ICancellationSignal signal)149         public AssetFileDescriptor openTypedAssetFile(
150                 @NonNull AttributionSource attributionSource, Uri url, String mimeType,
151                 Bundle opts, ICancellationSignal signal)
152                 throws RemoteException, FileNotFoundException {
153             return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts);
154         }
155 
156         @Override
createCancellationSignal()157         public ICancellationSignal createCancellationSignal() throws RemoteException {
158             return null;
159         }
160 
161         @Override
canonicalize(@onNull AttributionSource attributionSource, Uri uri)162         public Uri canonicalize(@NonNull AttributionSource attributionSource, Uri uri)
163                 throws RemoteException {
164             return MockContentProvider.this.canonicalize(uri);
165         }
166 
167         @Override
canonicalizeAsync(@onNull AttributionSource attributionSource, Uri uri, RemoteCallback callback)168         public void canonicalizeAsync(@NonNull AttributionSource attributionSource, Uri uri,
169                 RemoteCallback callback) {
170             MockContentProvider.this.canonicalizeAsync(uri, callback);
171         }
172 
173         @Override
uncanonicalize(@onNull AttributionSource attributionSource, Uri uri)174         public Uri uncanonicalize(@NonNull AttributionSource attributionSource, Uri uri)
175                 throws RemoteException {
176             return MockContentProvider.this.uncanonicalize(uri);
177         }
178 
179         @Override
uncanonicalizeAsync(@onNull AttributionSource attributionSource, Uri uri, RemoteCallback callback)180         public void uncanonicalizeAsync(@NonNull AttributionSource attributionSource, Uri uri,
181                 RemoteCallback callback) {
182             MockContentProvider.this.uncanonicalizeAsync(uri, callback);
183         }
184 
185         @Override
refresh(@onNull AttributionSource attributionSource, Uri url, Bundle args, ICancellationSignal cancellationSignal)186         public boolean refresh(@NonNull AttributionSource attributionSource, Uri url,
187                 Bundle args, ICancellationSignal cancellationSignal) throws RemoteException {
188             return MockContentProvider.this.refresh(url, args);
189         }
190 
191         @Override
checkUriPermission(@onNull AttributionSource attributionSource, Uri uri, int uid, int modeFlags)192         public int checkUriPermission(@NonNull AttributionSource attributionSource, Uri uri,
193                 int uid, int modeFlags) {
194             return MockContentProvider.this.checkUriPermission(uri, uid, modeFlags);
195         }
196     }
197     private final InversionIContentProvider mIContentProvider = new InversionIContentProvider();
198 
199     /**
200      * A constructor using {@link MockContext} instance as a Context in it.
201      */
MockContentProvider()202     protected MockContentProvider() {
203         super(new MockContext(), "", "", null);
204     }
205 
206     /**
207      * A constructor accepting a Context instance, which is supposed to be the subclasss of
208      * {@link MockContext}.
209      */
MockContentProvider(Context context)210     public MockContentProvider(Context context) {
211         super(context, "", "", null);
212     }
213 
214     /**
215      * A constructor which initialize four member variables which
216      * {@link android.content.ContentProvider} have internally.
217      *
218      * @param context A Context object which should be some mock instance (like the
219      * instance of {@link android.test.mock.MockContext}).
220      * @param readPermission The read permision you want this instance should have in the
221      * test, which is available via {@link #getReadPermission()}.
222      * @param writePermission The write permission you want this instance should have
223      * in the test, which is available via {@link #getWritePermission()}.
224      * @param pathPermissions The PathPermissions you want this instance should have
225      * in the test, which is available via {@link #getPathPermissions()}.
226      */
MockContentProvider(Context context, String readPermission, String writePermission, PathPermission[] pathPermissions)227     public MockContentProvider(Context context,
228             String readPermission,
229             String writePermission,
230             PathPermission[] pathPermissions) {
231         super(context, readPermission, writePermission, pathPermissions);
232     }
233 
234     @Override
delete(Uri uri, String selection, String[] selectionArgs)235     public int delete(Uri uri, String selection, String[] selectionArgs) {
236         throw new UnsupportedOperationException("unimplemented mock method");
237     }
238 
239     @Override
getType(Uri uri)240     public String getType(Uri uri) {
241         throw new UnsupportedOperationException("unimplemented mock method");
242     }
243 
244     /**
245      * @hide
246      */
247     @SuppressWarnings("deprecation")
getTypeAsync(Uri uri, RemoteCallback remoteCallback)248     public void getTypeAsync(Uri uri, RemoteCallback remoteCallback) {
249         AsyncTask.SERIAL_EXECUTOR.execute(() -> {
250             final Bundle bundle = new Bundle();
251             bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
252             remoteCallback.sendResult(bundle);
253         });
254     }
255 
256     @Override
getTypeAnonymous(Uri uri)257     public String getTypeAnonymous(Uri uri) {
258         throw new UnsupportedOperationException("unimplemented mock method");
259     }
260 
261     /**
262      * @hide
263      */
264     @SuppressWarnings("deprecation")
getTypeAnonymousAsync(Uri uri, RemoteCallback remoteCallback)265     public void getTypeAnonymousAsync(Uri uri, RemoteCallback remoteCallback) {
266         AsyncTask.SERIAL_EXECUTOR.execute(() -> {
267             final Bundle bundle = new Bundle();
268             bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getTypeAnonymous(uri));
269             remoteCallback.sendResult(bundle);
270         });
271     }
272 
273     @Override
insert(Uri uri, ContentValues values)274     public Uri insert(Uri uri, ContentValues values) {
275         throw new UnsupportedOperationException("unimplemented mock method");
276     }
277 
278     @Override
onCreate()279     public boolean onCreate() {
280         throw new UnsupportedOperationException("unimplemented mock method");
281     }
282 
283     @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)284     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
285             String sortOrder) {
286         throw new UnsupportedOperationException("unimplemented mock method");
287     }
288 
289     @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)290     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
291         throw new UnsupportedOperationException("unimplemented mock method");
292     }
293 
294     /**
295      * If you're reluctant to implement this manually, please just call super.bulkInsert().
296      */
297     @Override
bulkInsert(Uri uri, ContentValues[] values)298     public int bulkInsert(Uri uri, ContentValues[] values) {
299         throw new UnsupportedOperationException("unimplemented mock method");
300     }
301 
302     @Override
attachInfo(Context context, ProviderInfo info)303     public void attachInfo(Context context, ProviderInfo info) {
304         throw new UnsupportedOperationException("unimplemented mock method");
305     }
306 
307     @Override
applyBatch(ArrayList<ContentProviderOperation> operations)308     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) {
309         throw new UnsupportedOperationException("unimplemented mock method");
310     }
311 
312     /**
313      * @hide
314      */
315     @Override
call(String method, String request, Bundle args)316     public Bundle call(String method, String request, Bundle args) {
317         throw new UnsupportedOperationException("unimplemented mock method call");
318     }
319 
320     @Override
getStreamTypes(Uri url, String mimeTypeFilter)321     public String[] getStreamTypes(Uri url, String mimeTypeFilter) {
322         throw new UnsupportedOperationException("unimplemented mock method call");
323     }
324 
325     @Override
openTypedAssetFile(Uri url, String mimeType, Bundle opts)326     public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts) {
327         throw new UnsupportedOperationException("unimplemented mock method call");
328     }
329 
330     /**
331      * @hide
332      */
333     @SuppressWarnings("deprecation")
canonicalizeAsync(Uri uri, RemoteCallback callback)334     public void canonicalizeAsync(Uri uri, RemoteCallback callback) {
335         AsyncTask.SERIAL_EXECUTOR.execute(() -> {
336             final Bundle bundle = new Bundle();
337             bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, canonicalize(uri));
338             callback.sendResult(bundle);
339         });
340     }
341 
342     /**
343      * @hide
344      */
345     @SuppressWarnings("deprecation")
uncanonicalizeAsync(Uri uri, RemoteCallback callback)346     public void uncanonicalizeAsync(Uri uri, RemoteCallback callback) {
347         AsyncTask.SERIAL_EXECUTOR.execute(() -> {
348             final Bundle bundle = new Bundle();
349             bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, uncanonicalize(uri));
350             callback.sendResult(bundle);
351         });
352     }
353 
354     /**
355      * @hide
356      */
refresh(Uri url, Bundle args)357     public boolean refresh(Uri url, Bundle args) {
358         throw new UnsupportedOperationException("unimplemented mock method call");
359     }
360 
361     /** {@hide} */
362     @Override
checkUriPermission(@onNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags)363     public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) {
364         throw new UnsupportedOperationException("unimplemented mock method call");
365     }
366 
367     /**
368      * Returns IContentProvider which calls back same methods in this class.
369      * By overriding this class, we avoid the mechanism hidden behind ContentProvider
370      * (IPC, etc.)
371      *
372      * @hide
373      */
374     @Override
getIContentProvider()375     public final IContentProvider getIContentProvider() {
376         return mIContentProvider;
377     }
378 
379     /**
380      * @hide
381      */
getIContentProviderBinder()382     public IBinder getIContentProviderBinder() {
383         return new Binder();
384     }
385 
386     /**
387      * Like {@link #attachInfo(Context, android.content.pm.ProviderInfo)}, but for use
388      * when directly instantiating the provider for testing.
389      *
390      * <p>Provided for use by {@code android.test.ProviderTestCase2} and
391      * {@code android.test.RenamingDelegatingContext}.
392      *
393      * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
394      * New tests should be written using the
395      * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
396      */
397     @Deprecated
attachInfoForTesting( ContentProvider provider, Context context, ProviderInfo providerInfo)398     public static void attachInfoForTesting(
399             ContentProvider provider, Context context, ProviderInfo providerInfo) {
400         provider.attachInfoForTesting(context, providerInfo);
401     }
402 }
403