1 /*
2  * Copyright (C) 2015 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 com.android.messaging;
18 
19 import android.content.ContentProvider;
20 import android.content.ContentProviderClient;
21 import android.content.ContentValues;
22 import android.content.Context;
23 import android.content.pm.ProviderInfo;
24 import android.database.Cursor;
25 import android.net.Uri;
26 import android.os.Bundle;
27 import android.os.RemoteException;
28 import androidx.collection.SimpleArrayMap;
29 import android.text.TextUtils;
30 
31 import com.android.messaging.datamodel.FakeCursor;
32 import com.android.messaging.util.LogUtil;
33 
34 import java.util.ArrayList;
35 
36 public class FakeContentProvider extends ContentProvider {
37 
38     private static class ContentOverride {
39         private final String uri;
40         private final String where;
41         private final String args;
42         private final String[] columns;
43         private final Object[][] data;
44 
ContentOverride(final String uri, final String where, final String args, final String[] columns, final Object[][] data)45         ContentOverride(final String uri, final String where, final String args,
46                 final String[] columns, final Object[][] data) {
47             this.uri = uri;
48             this.where = where;
49             this.args = args;
50             this.columns = columns;
51             this.data = data;
52         }
53 
match(final String uri, final String where, final String[] args)54         boolean match(final String uri, final String where, final String[] args) {
55             if (!this.uri.equals(uri) || !TextUtils.equals(this.where, where)) {
56                 return false;
57             }
58 
59             if (this.args == null || args == null) {
60                 return this.args == null && args == null;
61             }
62 
63             return this.args.equals(TextUtils.join(";", args));
64         }
65     }
66 
67     private final Context mGlobalContext;
68     private final ArrayList<ContentOverride> mOverrides = new ArrayList<ContentOverride>();
69     private final SimpleArrayMap<String, String> mTypes = new SimpleArrayMap<String, String>();
70     private final ContentProviderClient mProvider;
71     private final Uri mUri;
72 
FakeContentProvider(final Context context, final Uri uri, final boolean canDelegate)73     public FakeContentProvider(final Context context, final Uri uri, final boolean canDelegate) {
74         mGlobalContext = context;
75         mUri = uri;
76         if (canDelegate) {
77             mProvider = mGlobalContext.getContentResolver().acquireContentProviderClient(mUri);
78         } else {
79             mProvider = null;
80         }
81 
82         ProviderInfo providerInfo = new ProviderInfo();
83         providerInfo.authority = uri.getAuthority();
84 
85         this.attachInfo(mGlobalContext, providerInfo);
86     }
87 
addOverrideData(final Uri uri, final String where, final String args, final String[] columns, final Object[][] data)88     public void addOverrideData(final Uri uri, final String where, final String args,
89             final String[] columns, final Object[][] data) {
90         mOverrides.add(new ContentOverride(uri.toString(), where, args, columns, data));
91     }
92 
addOverrideType(final Uri uri, final String type)93     public void addOverrideType(final Uri uri, final String type) {
94         mTypes.put(uri.toString(), type);
95     }
96 
97     @Override
onCreate()98     public boolean onCreate() {
99         return false;
100     }
101 
102     @Override
shutdown()103     public void shutdown() {
104         if (mProvider != null) {
105             mProvider.release();
106         }
107     }
108 
109     @Override
query(final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder)110     public Cursor query(final Uri uri, final String[] projection, final String selection,
111             final String[] selectionArgs, final String sortOrder) {
112         LogUtil.w(LogUtil.BUGLE_TAG, "FakeContentProvider: query " + uri.toString()
113                 + " for " + (projection == null ? null : TextUtils.join(",", projection))
114                 + " where " + selection
115                 + " with " + (selectionArgs == null ? null : TextUtils.join(";", selectionArgs)));
116 
117         for(final ContentOverride content : mOverrides) {
118             if (content.match(uri.toString(), selection, selectionArgs)) {
119                 return new FakeCursor(projection, content.columns, content.data);
120             }
121         }
122         if (mProvider != null) {
123             try {
124                 LogUtil.w(LogUtil.BUGLE_TAG, "FakeContentProvider: delgating");
125 
126                 final Cursor cursor = mProvider.query(uri, projection, selection, selectionArgs,
127                         sortOrder);
128 
129                 LogUtil.w(LogUtil.BUGLE_TAG, "FakeContentProvider: response size "
130                         + cursor.getCount() + " contains " + TextUtils.join(",",
131                                 cursor.getColumnNames()) + " type(0) " + cursor.getType(0));
132 
133                 return cursor;
134             } catch (final RemoteException e) {
135                 e.printStackTrace();
136             }
137         }
138         return null;
139     }
140 
141     @Override
getType(final Uri uri)142     public String getType(final Uri uri) {
143         String type = mTypes.get(uri.toString());
144         if (type == null) {
145             try {
146                 type = mProvider.getType(uri);
147             } catch (final RemoteException e) {
148                 e.printStackTrace();
149             }
150         }
151         return type;
152     }
153 
154     @Override
insert(final Uri uri, final ContentValues values)155     public Uri insert(final Uri uri, final ContentValues values) {
156         // TODO: Add code to track insert operations and return correct status
157         throw new UnsupportedOperationException();
158     }
159 
160     @Override
delete(final Uri uri, final String selection, final String[] selectionArgs)161     public int delete(final Uri uri, final String selection, final String[] selectionArgs) {
162         // TODO: Add code to track delete operations and return correct status
163         throw new UnsupportedOperationException();
164     }
165 
166     @Override
update(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs)167     public int update(final Uri uri, final ContentValues values, final String selection,
168             final String[] selectionArgs) {
169         // TODO: Add code to track update operations and return correct status
170         throw new UnsupportedOperationException();
171     }
172 
call(final String callingPkg, final String method, final String arg, final Bundle extras)173     public Bundle call(final String callingPkg, final String method, final String arg,
174             final Bundle extras) {
175         return null;
176     }
177 }
178