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.ArraySet; 24 25 import com.google.android.collect.Maps; 26 27 import java.util.Map; 28 29 /** 30 * A version of ContentResolver that allows easy mocking of providers. 31 * By default it acts as a normal ContentResolver and returns all the 32 * same providers. 33 * @see #addProvider(String, ContentProvider) 34 * @see #setFallbackToExisting(boolean) 35 */ 36 public class TestableContentResolver extends ContentResolver { 37 38 private final Map<String, ContentProvider> mProviders = Maps.newHashMap(); 39 private final ContentResolver mParent; 40 private final ArraySet<ContentProvider> mInUse = new ArraySet<>(); 41 private boolean mFallbackToExisting; 42 43 public TestableContentResolver(Context context) { 44 super(context); 45 mParent = context.getContentResolver(); 46 mFallbackToExisting = true; 47 } 48 49 /** 50 * Sets whether existing providers should be returned when a mock does not exist. 51 * The default is true. 52 */ 53 public void setFallbackToExisting(boolean fallbackToExisting) { 54 mFallbackToExisting = fallbackToExisting; 55 } 56 57 /** 58 * Adds access to a provider based on its authority 59 * 60 * @param name The authority name associated with the provider. 61 * @param provider An instance of {@link android.content.ContentProvider} or one of its 62 * subclasses, or null. 63 */ 64 public void addProvider(String name, ContentProvider provider) { 65 mProviders.put(name, provider); 66 } 67 68 @Override 69 protected IContentProvider acquireProvider(Context context, String name) { 70 final ContentProvider provider = mProviders.get(name); 71 if (provider != null) { 72 return provider.getIContentProvider(); 73 } else { 74 return mFallbackToExisting ? mParent.acquireProvider(name) : null; 75 } 76 } 77 78 @Override 79 protected IContentProvider acquireExistingProvider(Context context, String name) { 80 final ContentProvider provider = mProviders.get(name); 81 if (provider != null) { 82 return provider.getIContentProvider(); 83 } else { 84 return mFallbackToExisting ? mParent.acquireExistingProvider( 85 new Uri.Builder().authority(name).build()) : null; 86 } 87 } 88 89 @Override 90 public boolean releaseProvider(IContentProvider provider) { 91 if (!mFallbackToExisting) return true; 92 if (mInUse.contains(provider)) { 93 mInUse.remove(provider); 94 return true; 95 } 96 return mParent.releaseProvider(provider); 97 } 98 99 @Override 100 protected IContentProvider acquireUnstableProvider(Context c, String name) { 101 final ContentProvider provider = mProviders.get(name); 102 if (provider != null) { 103 return provider.getIContentProvider(); 104 } else { 105 return mFallbackToExisting ? mParent.acquireUnstableProvider(name) : null; 106 } 107 } 108 109 @Override 110 public boolean releaseUnstableProvider(IContentProvider icp) { 111 if (!mFallbackToExisting) return true; 112 if (mInUse.contains(icp)) { 113 mInUse.remove(icp); 114 return true; 115 } 116 return mParent.releaseUnstableProvider(icp); 117 } 118 119 @Override 120 public void unstableProviderDied(IContentProvider icp) { 121 if (!mFallbackToExisting) return; 122 if (mInUse.contains(icp)) { 123 return; 124 } 125 mParent.unstableProviderDied(icp); 126 } 127 128 @Override 129 public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { 130 if (!mFallbackToExisting) return; 131 if (!mProviders.containsKey(uri.getAuthority())) { 132 super.notifyChange(uri, observer, syncToNetwork); 133 } 134 } 135 } 136