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
19bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.Account;
20bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.AccountManager;
21bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.AccountManagerCallback;
22bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.AccountManagerFuture;
23bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.AuthenticatorException;
24bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.OnAccountsUpdateListener;
25bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.accounts.OperationCanceledException;
26b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport android.app.admin.DevicePolicyManager;
27bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikovimport android.content.ContentProvider;
28e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.content.ContentResolver;
29ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.content.ContentUris;
30ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.content.ContentValues;
31619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.Context;
329701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onukiimport android.content.ContextWrapper;
330bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onukiimport android.content.Intent;
3435997f3fdee2984b6d5373326110eda26929001aMakoto Onukiimport android.content.SharedPreferences;
35619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.ApplicationInfo;
36619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.pm.PackageManager;
3772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport android.content.pm.ProviderInfo;
38b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport android.content.pm.UserInfo;
395dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport android.content.res.Configuration;
40b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikovimport android.content.res.Resources;
41ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.database.Cursor;
4289b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.location.Country;
4389b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.location.CountryDetector;
4489b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.location.CountryListener;
45ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.net.Uri;
46b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport android.os.Bundle;
47bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.os.Handler;
48b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport android.os.IUserManager;
4989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.os.Looper;
50b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport android.os.UserHandle;
51b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport android.os.UserManager;
52ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.BaseColumns;
53619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.provider.ContactsContract;
5447fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions;
55ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.CommonDataKinds;
5689b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email;
5789b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone;
58e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
59ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.provider.ContactsContract.Data;
60e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
611d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkeyimport android.provider.ContactsContract.StatusUpdates;
62619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.test.IsolatedContext;
63619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.test.RenamingDelegatingContext;
64619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.test.mock.MockContentResolver;
65619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.test.mock.MockContext;
669701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onukiimport android.util.Log;
67619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
68400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onukiimport com.android.providers.contacts.util.ContactsPermissions;
6938210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.util.MockSharedPreferences;
703a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
7138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.google.android.collect.Sets;
7238210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki
73f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.File;
74bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport java.io.IOException;
75b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport java.util.ArrayList;
7624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoroimport java.util.Arrays;
77b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport java.util.List;
785dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport java.util.Locale;
7924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoroimport java.util.Set;
80619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
81619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey/**
82619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * Helper class that encapsulates an "actor" which is owned by a specific
83619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * package name. It correctly maintains a wrapped {@link Context} and an
84619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * attached {@link MockContentResolver}. Multiple actors can be used to test
85619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey * security scenarios between multiple packages.
86619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey */
87619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeypublic class ContactsActor {
88619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private static final String FILENAME_PREFIX = "test.";
89619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
90619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public static final String PACKAGE_GREY = "edu.example.grey";
91619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public static final String PACKAGE_RED = "net.example.red";
92619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public static final String PACKAGE_GREEN = "com.example.green";
93619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public static final String PACKAGE_BLUE = "org.example.blue";
94619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
95619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public Context context;
96619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public String packageName;
97619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public MockContentResolver resolver;
98bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov    public ContentProvider provider;
9989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    private Country mMockCountry = new Country("us", 0);
10089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
101bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    private Account[] mAccounts = new Account[0];
102bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
10324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    private Set<String> mGrantedPermissions = Sets.newHashSet();
104eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    private final Set<Uri> mGrantedUriPermissions = Sets.newHashSet();
10524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
10689b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    private CountryDetector mMockCountryDetector = new CountryDetector(null){
10789b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        @Override
10889b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        public Country detectCountry() {
10989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            return mMockCountry;
11089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        }
11189b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
11289b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        @Override
11389b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        public void addCountryListener(CountryListener listener, Looper looper) {
11489b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        }
11589b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    };
116619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
117bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    private AccountManager mMockAccountManager;
118bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
119bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    private class MockAccountManager extends AccountManager {
120bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public MockAccountManager(Context conteact) {
121bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            super(context, null, null);
122bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
123bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
124bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
125bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public void addOnAccountsUpdatedListener(OnAccountsUpdateListener listener,
126bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                Handler handler, boolean updateImmediately) {
127bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            // do nothing
128bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
129bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
130bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
131bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public Account[] getAccounts() {
132bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            return mAccounts;
133bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
134bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
135bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
136bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
137bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                final String type, final String[] features,
138bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                AccountManagerCallback<Account[]> callback, Handler handler) {
139bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            return null;
140bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
141bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
142bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
143bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public String blockingGetAuthToken(Account account, String authTokenType,
144bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                boolean notifyAuthFailure)
145bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                throws OperationCanceledException, IOException, AuthenticatorException {
146bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            return null;
147bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
148bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    }
149bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
150b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public MockUserManager mockUserManager;
151b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
152b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public static class MockUserManager extends UserManager {
153b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public static UserInfo createUserInfo(String name, int id, int groupId, int flags) {
154b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            final UserInfo ui = new UserInfo();
155b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            ui.name = name;
156b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            ui.id = id;
157b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            ui.profileGroupId = groupId;
158b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            ui.flags = flags | UserInfo.FLAG_INITIALIZED;
159b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            return ui;
160b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
161b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
162b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public static final UserInfo PRIMARY_USER = createUserInfo("primary", 0, 0,
163b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN);
164b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public static final UserInfo CORP_USER = createUserInfo("corp", 10, 0,
165b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                UserInfo.FLAG_MANAGED_PROFILE);
166b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public static final UserInfo SECONDARY_USER = createUserInfo("2nd", 11, 11, 0);
167b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
168b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        /** "My" user.  Set it to change the current user. */
169b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public int myUser = 0;
170b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
171b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        private ArrayList<UserInfo> mUsers = new ArrayList<>();
172b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
173b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public MockUserManager(Context context) {
174b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            super(context, /* IUserManager */ null);
175b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
176b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            mUsers.add(PRIMARY_USER); // Add the primary user.
177b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
178b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
179b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        /** Replaces users. */
180b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public void setUsers(UserInfo... users) {
181b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            mUsers.clear();
182b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            for (UserInfo ui : users) {
183b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                mUsers.add(ui);
184b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            }
185b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
186b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
187b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
188b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public int getUserHandle() {
189b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            return myUser;
190b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
191b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
192b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
193b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public UserInfo getUserInfo(int userHandle) {
194b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            for (UserInfo ui : mUsers) {
195b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                if (ui.id == userHandle) {
196b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    return ui;
197b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                }
198b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            }
199b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            return null;
200b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
201b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
202b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
203b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public UserInfo getProfileParent(int userHandle) {
204b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            final UserInfo child = getUserInfo(userHandle);
205b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            if (child == null) {
206b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                return null;
207b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            }
208b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            for (UserInfo ui : mUsers) {
209b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                if (ui.id != userHandle && ui.id == child.profileGroupId) {
210b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    return ui;
211b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                }
212b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            }
213b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            return null;
214b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
215b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
216b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
217b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public List<UserInfo> getUsers() {
218b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            return mUsers;
219b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
220b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
221b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
222b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public Bundle getUserRestrictions(UserHandle userHandle) {
223b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            return new Bundle();
224b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
2253a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
2263a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        @Override
2273a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        public boolean hasUserRestriction(String restrictionKey) {
2283a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            return false;
2293a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        }
2303a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
2313a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        @Override
2323a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
2333a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee            return false;
2343a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        }
235f2d3e8cb095348535e5ad3b9babccfa15bc31257Makoto Onuki
236f2d3e8cb095348535e5ad3b9babccfa15bc31257Makoto Onuki        @Override
237f2d3e8cb095348535e5ad3b9babccfa15bc31257Makoto Onuki        public boolean isSameProfileGroup(int userId, int otherUserId) {
238f2d3e8cb095348535e5ad3b9babccfa15bc31257Makoto Onuki            return getUserInfo(userId).profileGroupId == getUserInfo(otherUserId).profileGroupId;
239f2d3e8cb095348535e5ad3b9babccfa15bc31257Makoto Onuki        }
240b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    }
241b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
2429701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    /**
2439701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     * A context wrapper that reports a different user id.
2449701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     *
2459701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     * TODO This should override getSystemService() and returns a UserManager that returns the
2469701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     * same, altered user ID too.
2479701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     */
2489701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public static class AlteringUserContext extends ContextWrapper {
2499701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        private final int mUserId;
2509701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
2519701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        public AlteringUserContext(Context base, int userId) {
2529701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            super(base);
2539701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            mUserId = userId;
2549701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        }
2559701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
2569701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        @Override
2579701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        public int getUserId() {
2589701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            return mUserId;
2599701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        }
2609701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    }
2619701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
262e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private IsolatedContext mProviderContext;
263e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
264619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
265619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Create an "actor" using the given parent {@link Context} and the specific
266619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * package name. Internally, all {@link Context} method calls are passed to
267619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * a new instance of {@link RestrictionMockContext}, which stubs out the
268619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * security infrastructure.
269619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
270b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public ContactsActor(final Context overallContext, String packageName,
271bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov            Class<? extends ContentProvider> providerClass, String authority) throws Exception {
272400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki
273400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki        // Force permission check even when called by self.
274400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki        ContactsPermissions.ALLOW_SELF_CALL = false;
275400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki
276619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        resolver = new MockContentResolver();
27724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        context = new RestrictionMockContext(overallContext, packageName, resolver,
278f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                mGrantedPermissions, mGrantedUriPermissions) {
279f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            @Override
280f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            public Object getSystemService(String name) {
281f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                if (Context.COUNTRY_DETECTOR.equals(name)) {
282f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    return mMockCountryDetector;
283f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                }
284f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                if (Context.ACCOUNT_SERVICE.equals(name)) {
285f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    return mMockAccountManager;
286f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                }
287f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                if (Context.USER_SERVICE.equals(name)) {
288f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                    return mockUserManager;
289f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                }
290f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                // Use overallContext here; super.getSystemService() somehow won't return
291f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                // DevicePolicyManager.
292f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                return overallContext.getSystemService(name);
293f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            }
294f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki
295f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            @Override
296f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            public String getSystemServiceName(Class<?> serviceClass) {
297f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki                return overallContext.getSystemServiceName(serviceClass);
298f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            }
299f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki        };
300e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        this.packageName = packageName;
301619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
302212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // Let the Secure class initialize the settings provider, which is done when we first
303212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // tries to get any setting.  Because our mock context/content resolver doesn't have the
304212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // settings provider, we need to do this with an actual context, before other classes
305212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // try to do this with a mock context.
306212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // (Otherwise ContactsProvider2.initialzie() will crash trying to get a setting with
307212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // a mock context.)
308212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        android.provider.Settings.Secure.getString(overallContext.getContentResolver(), "dummy");
309212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki
310bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov        RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(context,
311bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov                overallContext, FILENAME_PREFIX);
31235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki        mProviderContext = new IsolatedContext(resolver, targetContextWrapper) {
31335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki            private final MockSharedPreferences mPrefs = new MockSharedPreferences();
31489b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
31589b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            @Override
316f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            public File getFilesDir() {
317f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro                // TODO: Need to figure out something more graceful than this.
318f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro                return new File("/data/data/com.android.providers.contacts.tests/files");
319f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            }
320f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro
321f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            @Override
32289b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            public Object getSystemService(String name) {
32389b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                if (Context.COUNTRY_DETECTOR.equals(name)) {
32489b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                    return mMockCountryDetector;
32589b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                }
326bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                if (Context.ACCOUNT_SERVICE.equals(name)) {
327bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                    return mMockAccountManager;
328bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                }
329b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                if (Context.USER_SERVICE.equals(name)) {
330b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    return mockUserManager;
331b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                }
332b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                // Use overallContext here; super.getSystemService() somehow won't return
333b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                // DevicePolicyManager.
334b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                return overallContext.getSystemService(name);
33589b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            }
33635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki
33735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki            @Override
3386040ab71df843cbb9562ded8b819bfff1c0d9838Victor Chang            public String getSystemServiceName(Class<?> serviceClass) {
3396040ab71df843cbb9562ded8b819bfff1c0d9838Victor Chang                return overallContext.getSystemServiceName(serviceClass);
3406040ab71df843cbb9562ded8b819bfff1c0d9838Victor Chang            }
3416040ab71df843cbb9562ded8b819bfff1c0d9838Victor Chang
3426040ab71df843cbb9562ded8b819bfff1c0d9838Victor Chang            @Override
34335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki            public SharedPreferences getSharedPreferences(String name, int mode) {
34435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki                return mPrefs;
34535997f3fdee2984b6d5373326110eda26929001aMakoto Onuki            }
3469701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
3479701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            @Override
3489701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            public int getUserId() {
3499701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki                return mockUserManager.getUserHandle();
3509701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            }
351dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki
352dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki            @Override
353dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki            public void sendBroadcast(Intent intent, String receiverPermission) {
354dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki                // Ignore.
355dc653a5c1bed274512ce41e4a6129a65d2b0eeacMakoto Onuki            }
35689b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        };
357bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
358bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        mMockAccountManager = new MockAccountManager(mProviderContext);
359b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        mockUserManager = new MockUserManager(mProviderContext);
360e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        provider = addProvider(providerClass, authority);
361e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
362e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
363b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public Context getProviderContext() {
364b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        return mProviderContext;
365b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    }
366b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
3679701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public <T extends ContentProvider> T addProvider(Class<T> providerClass,
368e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            String authority) throws Exception {
3699701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        return addProvider(providerClass, authority, mProviderContext);
3709701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    }
3719701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
3729701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public <T extends ContentProvider> T addProvider(Class<T> providerClass,
3739701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            String authority, Context providerContext) throws Exception {
3749701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        T provider = providerClass.newInstance();
37572e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        ProviderInfo info = new ProviderInfo();
37671142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki
37771142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        // Here, authority can have "user-id@".  We want to use it for addProvider, but provider
37871142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        // info shouldn't have it.
37971142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        info.authority = stripOutUserIdFromAuthority(authority);
3809701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        provider.attachInfoForTesting(providerContext, info);
381c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki
382c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        // In case of LegacyTest, "authority" here is actually multiple authorities.
383c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        // Register all authority here.
384c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        for (String a : authority.split(";")) {
385c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki            resolver.addProvider(a, provider);
386f3bd980c0ec03db2538e86cadee2c1559f02c85bMakoto Onuki            resolver.addProvider("0@" + a, provider);
387c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        }
388e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        return provider;
389619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
390619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
39171142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki    /**
39271142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki     * Takes an provider authority. If it has "userid@", then remove it.
39371142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki     */
39471142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki    private String stripOutUserIdFromAuthority(String authority) {
39571142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        final int pos = authority.indexOf('@');
39671142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        return pos < 0 ? authority : authority.substring(pos + 1);
39771142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki    }
39871142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki
39924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    public void addPermissions(String... permissions) {
40024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        mGrantedPermissions.addAll(Arrays.asList(permissions));
40124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    }
40224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
40324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    public void removePermissions(String... permissions) {
40424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        mGrantedPermissions.removeAll(Arrays.asList(permissions));
40524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    }
40624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
407eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    public void addUriPermissions(Uri... uris) {
408eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        mGrantedUriPermissions.addAll(Arrays.asList(uris));
409eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    }
410eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
411eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    public void removeUriPermissions(Uri... uris) {
412eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        mGrantedUriPermissions.removeAll(Arrays.asList(uris));
413eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    }
414eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
415619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
416619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Mock {@link Context} that reports specific well-known values for testing
417619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * data protection. The creator can override the owner package name, and
418619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * force the {@link PackageManager} to always return a well-known package
419619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * list for any call to {@link PackageManager#getPackagesForUid(int)}.
420619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * <p>
421619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * For example, the creator could request that the {@link Context} lives in
422619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * package name "com.example.red", and also cause the {@link PackageManager}
423619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * to report that no UID contains that package name.
424619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
425619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private static class RestrictionMockContext extends MockContext {
426b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        private final Context mOverallContext;
427b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        private final String mReportedPackageName;
42872e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        private final ContactsMockPackageManager mPackageManager;
429e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        private final ContentResolver mResolver;
4301d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        private final Resources mRes;
43124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        private final Set<String> mGrantedPermissions;
432eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        private final Set<Uri> mGrantedUriPermissions;
433619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
434619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        /**
435619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey         * Create a {@link Context} under the given package name.
436619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey         */
437e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        public RestrictionMockContext(Context overallContext, String reportedPackageName,
438eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                ContentResolver resolver, Set<String> grantedPermissions,
439eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                Set<Uri> grantedUriPermissions) {
440b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            mOverallContext = overallContext;
441619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mReportedPackageName = reportedPackageName;
442e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            mResolver = resolver;
44324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            mGrantedPermissions = grantedPermissions;
444eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            mGrantedUriPermissions = grantedUriPermissions;
4451d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
44672e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            mPackageManager = new ContactsMockPackageManager();
447619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(1000, PACKAGE_GREY);
448619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(2000, PACKAGE_RED);
449619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(3000, PACKAGE_GREEN);
450619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(4000, PACKAGE_BLUE);
4511d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
4525dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            Resources resources = overallContext.getResources();
4535dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            Configuration configuration = new Configuration(resources.getConfiguration());
4545dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            configuration.locale = Locale.US;
4555dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            resources.updateConfiguration(configuration, resources.getDisplayMetrics());
456ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann            mRes = resources;
457619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
458619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
459619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        @Override
460619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public String getPackageName() {
461619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            return mReportedPackageName;
462619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
463619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
464619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        @Override
465619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public PackageManager getPackageManager() {
466619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            return mPackageManager;
467619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
468b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
469b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        @Override
470b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public Resources getResources() {
4711d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey            return mRes;
472b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        }
473e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
474e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        @Override
475e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        public ContentResolver getContentResolver() {
476e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            return mResolver;
477e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
478d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
479d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        @Override
480d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        public ApplicationInfo getApplicationInfo() {
481d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            ApplicationInfo ai = new ApplicationInfo();
482d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            ai.packageName = "contactsTestPackage";
483d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            return ai;
484d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        }
48524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
48624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        // All permission checks are implemented to simply check against the granted permission set.
48724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
48824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
48924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int checkPermission(String permission, int pid, int uid) {
49024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            return checkCallingPermission(permission);
49124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
49224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
49324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
49424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int checkCallingPermission(String permission) {
49524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            if (mGrantedPermissions.contains(permission)) {
49624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro                return PackageManager.PERMISSION_GRANTED;
49724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            } else {
49824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro                return PackageManager.PERMISSION_DENIED;
49924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            }
50024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
50124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
50224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
503eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
504eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            return checkCallingUriPermission(uri, modeFlags);
505eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        }
506eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
507eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        @Override
508eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        public int checkCallingUriPermission(Uri uri, int modeFlags) {
509eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            if (mGrantedUriPermissions.contains(uri)) {
510eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                return PackageManager.PERMISSION_GRANTED;
511eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            } else {
512eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                return PackageManager.PERMISSION_DENIED;
513eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            }
514eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        }
515eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
516eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        @Override
51724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int checkCallingOrSelfPermission(String permission) {
51824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            return checkCallingPermission(permission);
51924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
52024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
52124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
52224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public void enforcePermission(String permission, int pid, int uid, String message) {
52324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            enforceCallingPermission(permission, message);
52424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
52524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
52624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
52724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public void enforceCallingPermission(String permission, String message) {
52824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            if (!mGrantedPermissions.contains(permission)) {
52924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro                throw new SecurityException(message);
53024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            }
53124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
53224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
53324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
53424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public void enforceCallingOrSelfPermission(String permission, String message) {
53524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            enforceCallingPermission(permission, message);
53624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
5370bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki
5380bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        @Override
5390bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        public void sendBroadcast(Intent intent) {
5400bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki            mOverallContext.sendBroadcast(intent);
5410bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        }
5420bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki
5430bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        @Override
5440bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        public void sendBroadcast(Intent intent, String receiverPermission) {
5450bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki            mOverallContext.sendBroadcast(intent, receiverPermission);
5460bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        }
547619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
548619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
54972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    static String sCallingPackage = null;
5501d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
5511d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    void ensureCallingPackage() {
5521d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        sCallingPackage = this.packageName;
5531d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
5541d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
555ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann    public long createRawContact(String name) {
5561d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
557ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann        long rawContactId = createRawContact();
55847fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        createName(rawContactId, name);
55947fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        return rawContactId;
560ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
561ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
562ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann    public long createRawContact() {
5631d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
564ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
565ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
56647fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        Uri rawContactUri = resolver.insert(RawContacts.CONTENT_URI, values);
56747fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        return ContentUris.parseId(rawContactUri);
568ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
569ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
570ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann    public long createRawContactWithStatus(String name, String address,
5711d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey            String status) {
572ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann        final long rawContactId = createRawContact(name);
5731d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final long dataId = createEmail(rawContactId, address);
5741d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        createStatus(dataId, status);
5751d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return rawContactId;
5761d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
5771d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
578ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public long createName(long contactId, String name) {
5791d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
580ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
5815ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Data.RAW_CONTACT_ID, contactId);
582ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
583ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
584ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
585ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(CommonDataKinds.StructuredName.FAMILY_NAME, name);
5866cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
5876cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                contactId), RawContacts.Data.CONTENT_DIRECTORY);
588ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
589ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(dataUri);
590ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
591ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
592ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public long createPhone(long contactId, String phoneNumber) {
5931d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
594ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
5955ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Data.RAW_CONTACT_ID, contactId);
596ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
597ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
5986bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
5993cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        values.put(ContactsContract.CommonDataKinds.Phone.TYPE,
6003cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                ContactsContract.CommonDataKinds.Phone.TYPE_HOME);
601ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber);
6026cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
6036cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                contactId), RawContacts.Data.CONTENT_DIRECTORY);
604ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
605ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(dataUri);
606ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
607ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
6081d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    public long createEmail(long contactId, String address) {
6091d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
6101d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final ContentValues values = new ContentValues();
6111d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.RAW_CONTACT_ID, contactId);
6121d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
6131d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
6141d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
6151d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Email.TYPE, Email.TYPE_HOME);
6161d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Email.DATA, address);
6171d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
6181d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey                contactId), RawContacts.Data.CONTENT_DIRECTORY);
6191d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
6201d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return ContentUris.parseId(dataUri);
6211d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
6221d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
6231d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    public long createStatus(long dataId, String status) {
6241d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
6251d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final ContentValues values = new ContentValues();
6261d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(StatusUpdates.DATA_ID, dataId);
6271d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(StatusUpdates.STATUS, status);
6281d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri dataUri = resolver.insert(StatusUpdates.CONTENT_URI, values);
6291d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return ContentUris.parseId(dataUri);
6301d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
6311d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
632ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public void updateException(String packageProvider, String packageClient, boolean allowAccess) {
63367dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        throw new UnsupportedOperationException("RestrictionExceptions are hard-coded");
634ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
635ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
636d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public long getContactForRawContact(long rawContactId) {
6371d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
638d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Uri contactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
639d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        final Cursor cursor = resolver.query(contactUri, Projections.PROJ_RAW_CONTACTS, null,
640ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                null, null);
641ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        if (!cursor.moveToFirst()) {
642ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            cursor.close();
643ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            throw new RuntimeException("Contact didn't have an aggregate");
644ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
645d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        final long aggId = cursor.getLong(Projections.COL_CONTACTS_ID);
646ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        cursor.close();
647ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return aggId;
648ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
649ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
650d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public int getDataCountForContact(long contactId) {
6511d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
652d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Uri contactUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI,
653d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                contactId), Contacts.Data.CONTENT_DIRECTORY);
654ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final Cursor cursor = resolver.query(contactUri, Projections.PROJ_ID, null, null,
655ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                null);
656ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final int count = cursor.getCount();
657ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        cursor.close();
658ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return count;
659ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
660ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
6611d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    public int getDataCountForRawContact(long rawContactId) {
6621d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
6631d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri contactUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
6641d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey                rawContactId), Contacts.Data.CONTENT_DIRECTORY);
6651d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final Cursor cursor = resolver.query(contactUri, Projections.PROJ_ID, null, null,
6661d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey                null);
6671d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final int count = cursor.getCount();
6681d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        cursor.close();
6691d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return count;
6701d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
6711d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
672ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public void setSuperPrimaryPhone(long dataId) {
6731d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
674ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
675ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
676ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
677ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri updateUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId);
678ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        resolver.update(updateUri, values, null, null);
679ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
680ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
681ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public long createGroup(String groupName) {
6821d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
683ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
68467dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        values.put(ContactsContract.Groups.RES_PACKAGE, packageName);
685ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(ContactsContract.Groups.TITLE, groupName);
686ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri groupUri = resolver.insert(ContactsContract.Groups.CONTENT_URI, values);
687ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(groupUri);
688ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
689ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
6905ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public long createGroupMembership(long rawContactId, long groupId) {
6911d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
692ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
6935ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Data.RAW_CONTACT_ID, rawContactId);
694ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.MIMETYPE, CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE);
695ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId);
6966cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
6975ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId), RawContacts.Data.CONTENT_DIRECTORY);
698ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
699ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(dataUri);
700ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
701ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
70247fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov    protected void setAggregationException(int type, long rawContactId1, long rawContactId2) {
70347fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        ContentValues values = new ContentValues();
70447fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
70547fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        values.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
70647fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        values.put(AggregationExceptions.TYPE, type);
70747fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        resolver.update(AggregationExceptions.CONTENT_URI, values, null, null);
70847fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov    }
70947fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov
710bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    public void setAccounts(Account[] accounts) {
711bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        mAccounts = accounts;
712bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    }
713bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
714ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
715ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Various internal database projections.
716ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
717ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private interface Projections {
718ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        static final String[] PROJ_ID = new String[] {
719ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                BaseColumns._ID,
720ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
721ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
722ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        static final int COL_ID = 0;
723ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
724d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        static final String[] PROJ_RAW_CONTACTS = new String[] {
725d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                RawContacts.CONTACT_ID
726ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
727ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
728d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        static final int COL_CONTACTS_ID = 0;
729ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
730619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey}
731