ContactsActor.java revision 212975b9dbb3c164e11732b98266eb7361e27ac5
1619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey/*
2619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Copyright (C) 2009 The Android Open Source Project
3619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey *
4619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * you may not use this file except in compliance with the License.
6619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * You may obtain a copy of the License at
7619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey *
8619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey *
10619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Unless required by applicable law or agreed to in writing, software
11619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * See the License for the specific language governing permissions and
14619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * limitations under the License.
15619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */
16619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
1728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarpackage com.android.providers.contacts;
18619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
1924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoroimport com.google.android.collect.Sets;
2024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
21bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.Account;
22bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.AccountManager;
23bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.AccountManagerCallback;
24bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.AccountManagerFuture;
25bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.AuthenticatorException;
26bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.OnAccountsUpdateListener;
27bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.OperationCanceledException;
28bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikovimport android.content.ContentProvider;
29e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.ContentResolver;
30ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.content.ContentUris;
31ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.content.ContentValues;
32619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.Context;
33619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.ApplicationInfo;
34619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.PackageManager;
3572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.content.pm.ProviderInfo;
365dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport android.content.res.Configuration;
37b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikovimport android.content.res.Resources;
38ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.Cursor;
3989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.location.Country;
4089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.location.CountryDetector;
4189b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.location.CountryListener;
42ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.net.Uri;
43bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Handler;
4489b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.os.Looper;
45ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.BaseColumns;
46619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.provider.ContactsContract;
4747fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions;
48ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds;
4989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email;
5089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone;
51e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
52ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.Data;
53e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
541d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkeyimport android.provider.ContactsContract.StatusUpdates;
55619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.test.IsolatedContext;
56619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.test.RenamingDelegatingContext;
57619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.test.mock.MockContentResolver;
58619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.test.mock.MockContext;
59619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
60f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.File;
61bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport java.io.IOException;
6224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoroimport java.util.Arrays;
635dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport java.util.Locale;
6424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoroimport java.util.Set;
65619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
66619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey/**
67619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Helper class that encapsulates an "actor" which is owned by a specific
68619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * package name. It correctly maintains a wrapped {@link Context} and an
69619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * attached {@link MockContentResolver}. Multiple actors can be used to test
70619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * security scenarios between multiple packages.
71619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */
72619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeypublic class ContactsActor {
73619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private static final String FILENAME_PREFIX = "test.";
74619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
75619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public static final String PACKAGE_GREY = "edu.example.grey";
76619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public static final String PACKAGE_RED = "net.example.red";
77619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public static final String PACKAGE_GREEN = "com.example.green";
78619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public static final String PACKAGE_BLUE = "org.example.blue";
79619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
80619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public Context context;
81619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public String packageName;
82619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public MockContentResolver resolver;
83bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov    public ContentProvider provider;
8489b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    private Country mMockCountry = new Country("us", 0);
8589b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
86bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    private Account[] mAccounts = new Account[0];
87bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
8824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    private Set<String> mGrantedPermissions = Sets.newHashSet();
89eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    private final Set<Uri> mGrantedUriPermissions = Sets.newHashSet();
9024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
9189b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    private CountryDetector mMockCountryDetector = new CountryDetector(null){
9289b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        @Override
9389b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        public Country detectCountry() {
9489b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            return mMockCountry;
9589b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        }
9689b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
9789b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        @Override
9889b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        public void addCountryListener(CountryListener listener, Looper looper) {
9989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        }
10089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    };
101619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
102bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    private AccountManager mMockAccountManager;
103bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
104bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    private class MockAccountManager extends AccountManager {
105bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public MockAccountManager(Context conteact) {
106bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            super(context, null, null);
107bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
108bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
109bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
110bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public void addOnAccountsUpdatedListener(OnAccountsUpdateListener listener,
111bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                Handler handler, boolean updateImmediately) {
112bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            // do nothing
113bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
114bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
115bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
116bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public Account[] getAccounts() {
117bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            return mAccounts;
118bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
119bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
120bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
121bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
122bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                final String type, final String[] features,
123bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                AccountManagerCallback<Account[]> callback, Handler handler) {
124bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            return null;
125bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
126bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
127bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
128bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public String blockingGetAuthToken(Account account, String authTokenType,
129bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                boolean notifyAuthFailure)
130bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                throws OperationCanceledException, IOException, AuthenticatorException {
131bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            return null;
132bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
133bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    }
134bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
135e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private IsolatedContext mProviderContext;
136e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
137619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
138619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Create an "actor" using the given parent {@link Context} and the specific
139619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * package name. Internally, all {@link Context} method calls are passed to
140619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * a new instance of {@link RestrictionMockContext}, which stubs out the
141619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * security infrastructure.
142619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
143bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov    public ContactsActor(Context overallContext, String packageName,
144bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov            Class<? extends ContentProvider> providerClass, String authority) throws Exception {
145619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        resolver = new MockContentResolver();
14624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        context = new RestrictionMockContext(overallContext, packageName, resolver,
147eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                mGrantedPermissions, mGrantedUriPermissions);
148e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        this.packageName = packageName;
149619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
150212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // Let the Secure class initialize the settings provider, which is done when we first
151212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // tries to get any setting.  Because our mock context/content resolver doesn't have the
152212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // settings provider, we need to do this with an actual context, before other classes
153212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // try to do this with a mock context.
154212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // (Otherwise ContactsProvider2.initialzie() will crash trying to get a setting with
155212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // a mock context.)
156212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        android.provider.Settings.Secure.getString(overallContext.getContentResolver(), "dummy");
157212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki
158bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov        RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(context,
159bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov                overallContext, FILENAME_PREFIX);
16089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        mProviderContext = new IsolatedContext(resolver, targetContextWrapper){
16189b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
16289b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            @Override
163f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            public File getFilesDir() {
164f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro                // TODO: Need to figure out something more graceful than this.
165f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro                return new File("/data/data/com.android.providers.contacts.tests/files");
166f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            }
167f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro
168f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            @Override
16989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            public Object getSystemService(String name) {
17089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                if (Context.COUNTRY_DETECTOR.equals(name)) {
17189b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                    return mMockCountryDetector;
17289b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                }
173bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                if (Context.ACCOUNT_SERVICE.equals(name)) {
174bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                    return mMockAccountManager;
175bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                }
17689b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                return super.getSystemService(name);
17789b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            }
17889b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        };
179bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
180bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        mMockAccountManager = new MockAccountManager(mProviderContext);
181e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        provider = addProvider(providerClass, authority);
182e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
183e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
184e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public void addAuthority(String authority) {
185e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        resolver.addProvider(authority, provider);
186e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
187619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
188e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public ContentProvider addProvider(Class<? extends ContentProvider> providerClass,
189e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            String authority) throws Exception {
190e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        ContentProvider provider = providerClass.newInstance();
19172e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        ProviderInfo info = new ProviderInfo();
19272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        info.authority = authority;
19372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        provider.attachInfo(mProviderContext, info);
194bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov        resolver.addProvider(authority, provider);
195e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        return provider;
196619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
197619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
19824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    public void addPermissions(String... permissions) {
19924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        mGrantedPermissions.addAll(Arrays.asList(permissions));
20024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    }
20124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
20224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    public void removePermissions(String... permissions) {
20324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        mGrantedPermissions.removeAll(Arrays.asList(permissions));
20424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    }
20524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
206eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    public void addUriPermissions(Uri... uris) {
207eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        mGrantedUriPermissions.addAll(Arrays.asList(uris));
208eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    }
209eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
210eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    public void removeUriPermissions(Uri... uris) {
211eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        mGrantedUriPermissions.removeAll(Arrays.asList(uris));
212eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    }
213eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
214619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
215619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Mock {@link Context} that reports specific well-known values for testing
216619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * data protection. The creator can override the owner package name, and
217619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * force the {@link PackageManager} to always return a well-known package
218619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * list for any call to {@link PackageManager#getPackagesForUid(int)}.
219619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * <p>
220619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * For example, the creator could request that the {@link Context} lives in
221619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * package name "com.example.red", and also cause the {@link PackageManager}
222619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * to report that no UID contains that package name.
223619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
224619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private static class RestrictionMockContext extends MockContext {
225b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        private final Context mOverallContext;
226b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        private final String mReportedPackageName;
22772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        private final ContactsMockPackageManager mPackageManager;
228e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        private final ContentResolver mResolver;
2291d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        private final Resources mRes;
23024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        private final Set<String> mGrantedPermissions;
231eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        private final Set<Uri> mGrantedUriPermissions;
232619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
233619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        /**
234619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey         * Create a {@link Context} under the given package name.
235619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey         */
236e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        public RestrictionMockContext(Context overallContext, String reportedPackageName,
237eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                ContentResolver resolver, Set<String> grantedPermissions,
238eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                Set<Uri> grantedUriPermissions) {
239b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            mOverallContext = overallContext;
240619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mReportedPackageName = reportedPackageName;
241e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            mResolver = resolver;
24224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            mGrantedPermissions = grantedPermissions;
243eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            mGrantedUriPermissions = grantedUriPermissions;
2441d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
24572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            mPackageManager = new ContactsMockPackageManager();
246619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(1000, PACKAGE_GREY);
247619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(2000, PACKAGE_RED);
248619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(3000, PACKAGE_GREEN);
249619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(4000, PACKAGE_BLUE);
2501d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
2515dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            Resources resources = overallContext.getResources();
2525dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            Configuration configuration = new Configuration(resources.getConfiguration());
2535dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            configuration.locale = Locale.US;
2545dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            resources.updateConfiguration(configuration, resources.getDisplayMetrics());
255ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann            mRes = resources;
256619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
257619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
258619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        @Override
259619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public String getPackageName() {
260619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            return mReportedPackageName;
261619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
262619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
263619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        @Override
264619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public PackageManager getPackageManager() {
265619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            return mPackageManager;
266619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
267b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
268b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        @Override
269b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public Resources getResources() {
2701d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey            return mRes;
271b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        }
272e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
273e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        @Override
274e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        public ContentResolver getContentResolver() {
275e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            return mResolver;
276e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
277d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
278d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        @Override
279d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        public ApplicationInfo getApplicationInfo() {
280d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            ApplicationInfo ai = new ApplicationInfo();
281d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            ai.packageName = "contactsTestPackage";
282d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            return ai;
283d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        }
28424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
28524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        // All permission checks are implemented to simply check against the granted permission set.
28624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
28724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
28824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int checkPermission(String permission, int pid, int uid) {
28924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            return checkCallingPermission(permission);
29024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
29124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
29224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
29324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int checkCallingPermission(String permission) {
29424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            if (mGrantedPermissions.contains(permission)) {
29524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro                return PackageManager.PERMISSION_GRANTED;
29624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            } else {
29724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro                return PackageManager.PERMISSION_DENIED;
29824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            }
29924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
30024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
30124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
302eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
303eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            return checkCallingUriPermission(uri, modeFlags);
304eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        }
305eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
306eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        @Override
307eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        public int checkCallingUriPermission(Uri uri, int modeFlags) {
308eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            if (mGrantedUriPermissions.contains(uri)) {
309eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                return PackageManager.PERMISSION_GRANTED;
310eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            } else {
311eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                return PackageManager.PERMISSION_DENIED;
312eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            }
313eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        }
314eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
315eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        @Override
31624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int checkCallingOrSelfPermission(String permission) {
31724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            return checkCallingPermission(permission);
31824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
31924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
32024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
32124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public void enforcePermission(String permission, int pid, int uid, String message) {
32224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            enforceCallingPermission(permission, message);
32324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
32424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
32524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
32624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public void enforceCallingPermission(String permission, String message) {
32724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            if (!mGrantedPermissions.contains(permission)) {
32824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro                throw new SecurityException(message);
32924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            }
33024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
33124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
33224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
33324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public void enforceCallingOrSelfPermission(String permission, String message) {
33424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            enforceCallingPermission(permission, message);
33524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
336619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
337619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
33872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    static String sCallingPackage = null;
3391d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
3401d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    void ensureCallingPackage() {
3411d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        sCallingPackage = this.packageName;
3421d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
3431d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
344ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann    public long createRawContact(String name) {
3451d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
346ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann        long rawContactId = createRawContact();
34747fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        createName(rawContactId, name);
34847fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        return rawContactId;
349ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
350ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
351ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann    public long createRawContact() {
3521d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
353ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
354ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
35547fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        Uri rawContactUri = resolver.insert(RawContacts.CONTENT_URI, values);
35647fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        return ContentUris.parseId(rawContactUri);
357ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
358ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
359ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann    public long createRawContactWithStatus(String name, String address,
3601d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey            String status) {
361ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann        final long rawContactId = createRawContact(name);
3621d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final long dataId = createEmail(rawContactId, address);
3631d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        createStatus(dataId, status);
3641d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return rawContactId;
3651d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
3661d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
367ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public long createName(long contactId, String name) {
3681d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
369ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
3705ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Data.RAW_CONTACT_ID, contactId);
371ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
372ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
373ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
374ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(CommonDataKinds.StructuredName.FAMILY_NAME, name);
3756cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
3766cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                contactId), RawContacts.Data.CONTENT_DIRECTORY);
377ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
378ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(dataUri);
379ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
380ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
381ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public long createPhone(long contactId, String phoneNumber) {
3821d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
383ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
3845ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Data.RAW_CONTACT_ID, contactId);
385ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
386ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
3876bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
3883cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        values.put(ContactsContract.CommonDataKinds.Phone.TYPE,
3893cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                ContactsContract.CommonDataKinds.Phone.TYPE_HOME);
390ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber);
3916cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
3926cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                contactId), RawContacts.Data.CONTENT_DIRECTORY);
393ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
394ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(dataUri);
395ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
396ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
3971d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    public long createEmail(long contactId, String address) {
3981d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
3991d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final ContentValues values = new ContentValues();
4001d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.RAW_CONTACT_ID, contactId);
4011d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
4021d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
4031d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
4041d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Email.TYPE, Email.TYPE_HOME);
4051d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Email.DATA, address);
4061d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
4071d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey                contactId), RawContacts.Data.CONTENT_DIRECTORY);
4081d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
4091d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return ContentUris.parseId(dataUri);
4101d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
4111d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
4121d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    public long createStatus(long dataId, String status) {
4131d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
4141d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final ContentValues values = new ContentValues();
4151d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(StatusUpdates.DATA_ID, dataId);
4161d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(StatusUpdates.STATUS, status);
4171d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri dataUri = resolver.insert(StatusUpdates.CONTENT_URI, values);
4181d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return ContentUris.parseId(dataUri);
4191d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
4201d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
421ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public void updateException(String packageProvider, String packageClient, boolean allowAccess) {
42267dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        throw new UnsupportedOperationException("RestrictionExceptions are hard-coded");
423ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
424ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
425d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public long getContactForRawContact(long rawContactId) {
4261d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
427d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Uri contactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
428d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        final Cursor cursor = resolver.query(contactUri, Projections.PROJ_RAW_CONTACTS, null,
429ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                null, null);
430ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        if (!cursor.moveToFirst()) {
431ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            cursor.close();
432ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            throw new RuntimeException("Contact didn't have an aggregate");
433ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
434d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        final long aggId = cursor.getLong(Projections.COL_CONTACTS_ID);
435ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        cursor.close();
436ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return aggId;
437ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
438ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
439d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public int getDataCountForContact(long contactId) {
4401d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
441d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Uri contactUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI,
442d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                contactId), Contacts.Data.CONTENT_DIRECTORY);
443ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final Cursor cursor = resolver.query(contactUri, Projections.PROJ_ID, null, null,
444ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                null);
445ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final int count = cursor.getCount();
446ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        cursor.close();
447ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return count;
448ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
449ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4501d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    public int getDataCountForRawContact(long rawContactId) {
4511d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
4521d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri contactUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
4531d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey                rawContactId), Contacts.Data.CONTENT_DIRECTORY);
4541d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final Cursor cursor = resolver.query(contactUri, Projections.PROJ_ID, null, null,
4551d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey                null);
4561d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final int count = cursor.getCount();
4571d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        cursor.close();
4581d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return count;
4591d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
4601d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
461ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public void setSuperPrimaryPhone(long dataId) {
4621d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
463ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
464ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
465ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
466ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri updateUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId);
467ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        resolver.update(updateUri, values, null, null);
468ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
469ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
470ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public long createGroup(String groupName) {
4711d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
472ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
47367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        values.put(ContactsContract.Groups.RES_PACKAGE, packageName);
474ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(ContactsContract.Groups.TITLE, groupName);
475ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri groupUri = resolver.insert(ContactsContract.Groups.CONTENT_URI, values);
476ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(groupUri);
477ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
478ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4795ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public long createGroupMembership(long rawContactId, long groupId) {
4801d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
481ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
4825ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Data.RAW_CONTACT_ID, rawContactId);
483ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.MIMETYPE, CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE);
484ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId);
4856cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
4865ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId), RawContacts.Data.CONTENT_DIRECTORY);
487ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
488ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(dataUri);
489ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
490ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
49147fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov    protected void setAggregationException(int type, long rawContactId1, long rawContactId2) {
49247fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        ContentValues values = new ContentValues();
49347fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
49447fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        values.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
49547fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        values.put(AggregationExceptions.TYPE, type);
49647fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        resolver.update(AggregationExceptions.CONTENT_URI, values, null, null);
49747fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov    }
49847fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov
499bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    public void setAccounts(Account[] accounts) {
500bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        mAccounts = accounts;
501bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    }
502bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
503ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
504ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Various internal database projections.
505ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
506ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private interface Projections {
507ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        static final String[] PROJ_ID = new String[] {
508ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                BaseColumns._ID,
509ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
510ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
511ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        static final int COL_ID = 0;
512ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
513d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        static final String[] PROJ_RAW_CONTACTS = new String[] {
514d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                RawContacts.CONTACT_ID
515ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
516ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
517d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        static final int COL_CONTACTS_ID = 0;
518ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
519619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey}
520