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