1e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk/* 2340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * Copyright (C) 2017 The Android Open Source Project 3e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * 4e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * except in compliance with the License. You may obtain a copy of the License at 6e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * 7e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * http://www.apache.org/licenses/LICENSE-2.0 8e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * 9e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * Unless required by applicable law or agreed to in writing, software distributed under the 10e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * KIND, either express or implied. See the License for the specific language governing 12e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * permissions and limitations under the License. 13e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk */ 14e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 15340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkpackage android.testing; 16e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 17e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monkimport android.content.ContentProvider; 18e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monkimport android.content.ContentResolver; 19e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monkimport android.content.Context; 20e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monkimport android.content.IContentProvider; 21e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monkimport android.database.ContentObserver; 22e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monkimport android.net.Uri; 23e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monkimport android.util.ArraySet; 24e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 25e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monkimport com.google.android.collect.Maps; 26e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 27e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monkimport java.util.Map; 28e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 29e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk/** 30e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * Alternative to a MockContentResolver that falls back to real providers. 31e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk */ 32340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkpublic class TestableContentResolver extends ContentResolver { 33e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 34e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk private final Map<String, ContentProvider> mProviders = Maps.newHashMap(); 35e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk private final ContentResolver mParent; 36e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk private final ArraySet<ContentProvider> mInUse = new ArraySet<>(); 37e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk private boolean mFallbackToExisting; 38e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 39340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk public TestableContentResolver(Context context) { 40e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk super(context); 41e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk mParent = context.getContentResolver(); 42e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk mFallbackToExisting = true; 43e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 44e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 45e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk /** 46e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * Sets whether existing providers should be returned when a mock does not exist. 47e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * The default is true. 48e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk */ 49e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk public void setFallbackToExisting(boolean fallbackToExisting) { 50e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk mFallbackToExisting = fallbackToExisting; 51e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 52e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 53e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk /** 54e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * Adds access to a provider based on its authority 55e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * 56e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * @param name The authority name associated with the provider. 57e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * @param provider An instance of {@link android.content.ContentProvider} or one of its 58e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk * subclasses, or null. 59e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk */ 60e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk public void addProvider(String name, ContentProvider provider) { 61e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk mProviders.put(name, provider); 62e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 63e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 64e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk @Override 65e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk protected IContentProvider acquireProvider(Context context, String name) { 66e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk final ContentProvider provider = mProviders.get(name); 67e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (provider != null) { 68e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return provider.getIContentProvider(); 69e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } else { 70e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return mFallbackToExisting ? mParent.acquireProvider(name) : null; 71e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 72e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 73e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 74e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk @Override 75e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk protected IContentProvider acquireExistingProvider(Context context, String name) { 76e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk final ContentProvider provider = mProviders.get(name); 77e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (provider != null) { 78e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return provider.getIContentProvider(); 79e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } else { 80e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return mFallbackToExisting ? mParent.acquireExistingProvider( 81e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk new Uri.Builder().authority(name).build()) : null; 82e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 83e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 84e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 85e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk @Override 86e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk public boolean releaseProvider(IContentProvider provider) { 87e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (!mFallbackToExisting) return true; 88e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (mInUse.contains(provider)) { 89e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk mInUse.remove(provider); 90e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return true; 91e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 92e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return mParent.releaseProvider(provider); 93e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 94e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 95e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk @Override 96e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk protected IContentProvider acquireUnstableProvider(Context c, String name) { 97e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk final ContentProvider provider = mProviders.get(name); 98e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (provider != null) { 99e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return provider.getIContentProvider(); 100e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } else { 101e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return mFallbackToExisting ? mParent.acquireUnstableProvider(name) : null; 102e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 103e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 104e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 105e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk @Override 106e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk public boolean releaseUnstableProvider(IContentProvider icp) { 107e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (!mFallbackToExisting) return true; 108e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (mInUse.contains(icp)) { 109e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk mInUse.remove(icp); 110e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return true; 111e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 112e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return mParent.releaseUnstableProvider(icp); 113e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 114e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 115e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk @Override 116e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk public void unstableProviderDied(IContentProvider icp) { 117e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (!mFallbackToExisting) return; 118e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (mInUse.contains(icp)) { 119e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk return; 120e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 121e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk mParent.unstableProviderDied(icp); 122e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 123e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk 124e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk @Override 125e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { 126e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (!mFallbackToExisting) return; 127e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk if (!mProviders.containsKey(uri.getAuthority())) { 128e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk super.notifyChange(uri, observer, syncToNetwork); 129e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 130e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk } 131e97892844a5c21c91c7f82b96f82202b18a1a24dJason Monk} 132