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