ContactsActor.java revision c19d5519535bc05225eac5f7dfb830fda48497de
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        }
235b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    }
236b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
2379701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    /**
2389701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     * A context wrapper that reports a different user id.
2399701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     *
2409701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     * TODO This should override getSystemService() and returns a UserManager that returns the
2419701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     * same, altered user ID too.
2429701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki     */
2439701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public static class AlteringUserContext extends ContextWrapper {
2449701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        private final int mUserId;
2459701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
2469701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        public AlteringUserContext(Context base, int userId) {
2479701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            super(base);
2489701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            mUserId = userId;
2499701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        }
2509701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
2519701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        @Override
2529701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        public int getUserId() {
2539701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            return mUserId;
2549701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        }
2559701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    }
2569701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
257e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    private IsolatedContext mProviderContext;
258e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
259619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
260619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Create an "actor" using the given parent {@link Context} and the specific
261619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * package name. Internally, all {@link Context} method calls are passed to
262619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * a new instance of {@link RestrictionMockContext}, which stubs out the
263619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * security infrastructure.
264619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
265b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public ContactsActor(final Context overallContext, String packageName,
266bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov            Class<? extends ContentProvider> providerClass, String authority) throws Exception {
267400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki
268400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki        // Force permission check even when called by self.
269400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki        ContactsPermissions.ALLOW_SELF_CALL = false;
270400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki
271619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        resolver = new MockContentResolver();
27224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        context = new RestrictionMockContext(overallContext, packageName, resolver,
273eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                mGrantedPermissions, mGrantedUriPermissions);
274e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        this.packageName = packageName;
275619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
276212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // Let the Secure class initialize the settings provider, which is done when we first
277212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // tries to get any setting.  Because our mock context/content resolver doesn't have the
278212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // settings provider, we need to do this with an actual context, before other classes
279212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // try to do this with a mock context.
280212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // (Otherwise ContactsProvider2.initialzie() will crash trying to get a setting with
281212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        // a mock context.)
282212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        android.provider.Settings.Secure.getString(overallContext.getContentResolver(), "dummy");
283212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki
284bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov        RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(context,
285bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov                overallContext, FILENAME_PREFIX);
28635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki        mProviderContext = new IsolatedContext(resolver, targetContextWrapper) {
28735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki            private final MockSharedPreferences mPrefs = new MockSharedPreferences();
28889b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
28989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            @Override
290f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            public File getFilesDir() {
291f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro                // TODO: Need to figure out something more graceful than this.
292f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro                return new File("/data/data/com.android.providers.contacts.tests/files");
293f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            }
294f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro
295f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            @Override
29689b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            public Object getSystemService(String name) {
29789b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                if (Context.COUNTRY_DETECTOR.equals(name)) {
29889b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                    return mMockCountryDetector;
29989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                }
300bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                if (Context.ACCOUNT_SERVICE.equals(name)) {
301bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                    return mMockAccountManager;
302bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                }
303b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                if (Context.USER_SERVICE.equals(name)) {
304b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    return mockUserManager;
305b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                }
306b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                // Use overallContext here; super.getSystemService() somehow won't return
307b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                // DevicePolicyManager.
308b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                return overallContext.getSystemService(name);
30989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov            }
31035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki
31135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki            @Override
31235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki            public SharedPreferences getSharedPreferences(String name, int mode) {
31335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki                return mPrefs;
31435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki            }
3159701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
3169701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            @Override
3179701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            public int getUserId() {
3189701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki                return mockUserManager.getUserHandle();
3199701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            }
32089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        };
321bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
322bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        mMockAccountManager = new MockAccountManager(mProviderContext);
323b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        mockUserManager = new MockUserManager(mProviderContext);
324e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        provider = addProvider(providerClass, authority);
325e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    }
326e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
327b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public Context getProviderContext() {
328b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        return mProviderContext;
329b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    }
330b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
3319701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public <T extends ContentProvider> T addProvider(Class<T> providerClass,
332e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            String authority) throws Exception {
3339701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        return addProvider(providerClass, authority, mProviderContext);
3349701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    }
3359701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
3369701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public <T extends ContentProvider> T addProvider(Class<T> providerClass,
3379701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            String authority, Context providerContext) throws Exception {
3389701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        T provider = providerClass.newInstance();
33972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        ProviderInfo info = new ProviderInfo();
34071142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki
34171142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        // Here, authority can have "user-id@".  We want to use it for addProvider, but provider
34271142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        // info shouldn't have it.
34371142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        info.authority = stripOutUserIdFromAuthority(authority);
3449701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        provider.attachInfoForTesting(providerContext, info);
345bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov        resolver.addProvider(authority, provider);
346c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki
347c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        // In case of LegacyTest, "authority" here is actually multiple authorities.
348c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        // Register all authority here.
349c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        for (String a : authority.split(";")) {
350c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki            resolver.addProvider(a, provider);
351c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        }
352e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        return provider;
353619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
354619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
35571142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki    /**
35671142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki     * Takes an provider authority. If it has "userid@", then remove it.
35771142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki     */
35871142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki    private String stripOutUserIdFromAuthority(String authority) {
35971142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        final int pos = authority.indexOf('@');
36071142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        return pos < 0 ? authority : authority.substring(pos + 1);
36171142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki    }
36271142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki
36324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    public void addPermissions(String... permissions) {
36424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        mGrantedPermissions.addAll(Arrays.asList(permissions));
36524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    }
36624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
36724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    public void removePermissions(String... permissions) {
36824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        mGrantedPermissions.removeAll(Arrays.asList(permissions));
36924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    }
37024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
371eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    public void addUriPermissions(Uri... uris) {
372eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        mGrantedUriPermissions.addAll(Arrays.asList(uris));
373eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    }
374eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
375eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    public void removeUriPermissions(Uri... uris) {
376eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        mGrantedUriPermissions.removeAll(Arrays.asList(uris));
377eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee    }
378eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
379619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    /**
380619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * Mock {@link Context} that reports specific well-known values for testing
381619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * data protection. The creator can override the owner package name, and
382619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * force the {@link PackageManager} to always return a well-known package
383619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * list for any call to {@link PackageManager#getPackagesForUid(int)}.
384619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * <p>
385619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * For example, the creator could request that the {@link Context} lives in
386619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * package name "com.example.red", and also cause the {@link PackageManager}
387619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     * to report that no UID contains that package name.
388619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey     */
389619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private static class RestrictionMockContext extends MockContext {
390b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        private final Context mOverallContext;
391b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        private final String mReportedPackageName;
39272e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov        private final ContactsMockPackageManager mPackageManager;
393e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        private final ContentResolver mResolver;
3941d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        private final Resources mRes;
39524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        private final Set<String> mGrantedPermissions;
396eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        private final Set<Uri> mGrantedUriPermissions;
397619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
398619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        /**
399619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey         * Create a {@link Context} under the given package name.
400619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey         */
401e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        public RestrictionMockContext(Context overallContext, String reportedPackageName,
402eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                ContentResolver resolver, Set<String> grantedPermissions,
403eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                Set<Uri> grantedUriPermissions) {
404b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov            mOverallContext = overallContext;
405619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mReportedPackageName = reportedPackageName;
406e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            mResolver = resolver;
40724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            mGrantedPermissions = grantedPermissions;
408eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            mGrantedUriPermissions = grantedUriPermissions;
4091d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
41072e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov            mPackageManager = new ContactsMockPackageManager();
411619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(1000, PACKAGE_GREY);
412619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(2000, PACKAGE_RED);
413619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(3000, PACKAGE_GREEN);
414619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            mPackageManager.addPackage(4000, PACKAGE_BLUE);
4151d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
4165dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            Resources resources = overallContext.getResources();
4175dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            Configuration configuration = new Configuration(resources.getConfiguration());
4185dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            configuration.locale = Locale.US;
4195dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov            resources.updateConfiguration(configuration, resources.getDisplayMetrics());
420ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann            mRes = resources;
421619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
422619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
423619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        @Override
424619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public String getPackageName() {
425619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            return mReportedPackageName;
426619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
427619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
428619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        @Override
429619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        public PackageManager getPackageManager() {
430619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            return mPackageManager;
431619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        }
432b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov
433b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        @Override
434b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        public Resources getResources() {
4351d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey            return mRes;
436b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov        }
437e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
438e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        @Override
439e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        public ContentResolver getContentResolver() {
440e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            return mResolver;
441e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        }
442d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov
443d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        @Override
444d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        public ApplicationInfo getApplicationInfo() {
445d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            ApplicationInfo ai = new ApplicationInfo();
446d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            ai.packageName = "contactsTestPackage";
447d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov            return ai;
448d3d812af96f7d77e13dc60652626b39f25907147Dmitri Plotnikov        }
44924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
45024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        // All permission checks are implemented to simply check against the granted permission set.
45124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
45224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
45324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int checkPermission(String permission, int pid, int uid) {
45424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            return checkCallingPermission(permission);
45524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
45624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
45724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
45824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int checkCallingPermission(String permission) {
45924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            if (mGrantedPermissions.contains(permission)) {
46024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro                return PackageManager.PERMISSION_GRANTED;
46124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            } else {
46224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro                return PackageManager.PERMISSION_DENIED;
46324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            }
46424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
46524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
46624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
467eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
468eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            return checkCallingUriPermission(uri, modeFlags);
469eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        }
470eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
471eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        @Override
472eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        public int checkCallingUriPermission(Uri uri, int modeFlags) {
473eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            if (mGrantedUriPermissions.contains(uri)) {
474eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                return PackageManager.PERMISSION_GRANTED;
475eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            } else {
476eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                return PackageManager.PERMISSION_DENIED;
477eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee            }
478eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        }
479eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
480eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        @Override
48124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int checkCallingOrSelfPermission(String permission) {
48224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            return checkCallingPermission(permission);
48324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
48424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
48524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
48624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public void enforcePermission(String permission, int pid, int uid, String message) {
48724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            enforceCallingPermission(permission, message);
48824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
48924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
49024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
49124c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public void enforceCallingPermission(String permission, String message) {
49224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            if (!mGrantedPermissions.contains(permission)) {
49324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro                throw new SecurityException(message);
49424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            }
49524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
49624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
49724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        @Override
49824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public void enforceCallingOrSelfPermission(String permission, String message) {
49924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro            enforceCallingPermission(permission, message);
50024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        }
5010bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki
5020bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        @Override
5030bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        public void sendBroadcast(Intent intent) {
5040bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki            mOverallContext.sendBroadcast(intent);
5050bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        }
5060bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki
5070bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        @Override
5080bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        public void sendBroadcast(Intent intent, String receiverPermission) {
5090bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki            mOverallContext.sendBroadcast(intent, receiverPermission);
5100bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onuki        }
511619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
512619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
51372e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    static String sCallingPackage = null;
5141d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
5151d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    void ensureCallingPackage() {
5161d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        sCallingPackage = this.packageName;
5171d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
5181d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
519ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann    public long createRawContact(String name) {
5201d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
521ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann        long rawContactId = createRawContact();
52247fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        createName(rawContactId, name);
52347fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        return rawContactId;
524ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
525ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
526ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann    public long createRawContact() {
5271d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
528ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
529ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
53047fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        Uri rawContactUri = resolver.insert(RawContacts.CONTENT_URI, values);
53147fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        return ContentUris.parseId(rawContactUri);
532ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
533ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
534ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann    public long createRawContactWithStatus(String name, String address,
5351d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey            String status) {
536ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann        final long rawContactId = createRawContact(name);
5371d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final long dataId = createEmail(rawContactId, address);
5381d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        createStatus(dataId, status);
5391d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return rawContactId;
5401d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
5411d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
542ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public long createName(long contactId, String name) {
5431d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
544ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
5455ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Data.RAW_CONTACT_ID, contactId);
546ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
547ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
548ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
549ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(CommonDataKinds.StructuredName.FAMILY_NAME, name);
5506cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
5516cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                contactId), RawContacts.Data.CONTENT_DIRECTORY);
552ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
553ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(dataUri);
554ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
555ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
556ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public long createPhone(long contactId, String phoneNumber) {
5571d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
558ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
5595ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Data.RAW_CONTACT_ID, contactId);
560ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
561ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
5626bc46c9f22aaa9e68f344b171426fc686d3b536aDmitri Plotnikov        values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
5633cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov        values.put(ContactsContract.CommonDataKinds.Phone.TYPE,
5643cebbf7141252768d3e272e049e9c5b0cb9d710eDmitri Plotnikov                ContactsContract.CommonDataKinds.Phone.TYPE_HOME);
565ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber);
5666cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
5676cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov                contactId), RawContacts.Data.CONTENT_DIRECTORY);
568ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
569ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(dataUri);
570ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
571ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
5721d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    public long createEmail(long contactId, String address) {
5731d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
5741d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final ContentValues values = new ContentValues();
5751d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.RAW_CONTACT_ID, contactId);
5761d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
5771d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
5781d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
5791d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Email.TYPE, Email.TYPE_HOME);
5801d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(Email.DATA, address);
5811d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
5821d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey                contactId), RawContacts.Data.CONTENT_DIRECTORY);
5831d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
5841d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return ContentUris.parseId(dataUri);
5851d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
5861d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
5871d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    public long createStatus(long dataId, String status) {
5881d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
5891d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final ContentValues values = new ContentValues();
5901d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(StatusUpdates.DATA_ID, dataId);
5911d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        values.put(StatusUpdates.STATUS, status);
5921d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri dataUri = resolver.insert(StatusUpdates.CONTENT_URI, values);
5931d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return ContentUris.parseId(dataUri);
5941d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
5951d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
596ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public void updateException(String packageProvider, String packageClient, boolean allowAccess) {
59767dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        throw new UnsupportedOperationException("RestrictionExceptions are hard-coded");
598ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
599ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
600d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public long getContactForRawContact(long rawContactId) {
6011d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
602d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Uri contactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
603d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        final Cursor cursor = resolver.query(contactUri, Projections.PROJ_RAW_CONTACTS, null,
604ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                null, null);
605ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        if (!cursor.moveToFirst()) {
606ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            cursor.close();
607ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey            throw new RuntimeException("Contact didn't have an aggregate");
608ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        }
609d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        final long aggId = cursor.getLong(Projections.COL_CONTACTS_ID);
610ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        cursor.close();
611ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return aggId;
612ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
613ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
614d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov    public int getDataCountForContact(long contactId) {
6151d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
616d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        Uri contactUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI,
617d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                contactId), Contacts.Data.CONTENT_DIRECTORY);
618ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final Cursor cursor = resolver.query(contactUri, Projections.PROJ_ID, null, null,
619ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                null);
620ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final int count = cursor.getCount();
621ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        cursor.close();
622ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return count;
623ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
624ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
6251d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    public int getDataCountForRawContact(long rawContactId) {
6261d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
6271d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        Uri contactUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
6281d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey                rawContactId), Contacts.Data.CONTENT_DIRECTORY);
6291d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final Cursor cursor = resolver.query(contactUri, Projections.PROJ_ID, null, null,
6301d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey                null);
6311d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        final int count = cursor.getCount();
6321d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        cursor.close();
6331d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        return count;
6341d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey    }
6351d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
636ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public void setSuperPrimaryPhone(long dataId) {
6371d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
638ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
639ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_PRIMARY, 1);
640ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.IS_SUPER_PRIMARY, 1);
641ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri updateUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId);
642ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        resolver.update(updateUri, values, null, null);
643ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
644ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
645ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public long createGroup(String groupName) {
6461d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
647ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
64867dde51ab932dc84d95a203b113989b13437f13dJeff Sharkey        values.put(ContactsContract.Groups.RES_PACKAGE, packageName);
649ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(ContactsContract.Groups.TITLE, groupName);
650ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri groupUri = resolver.insert(ContactsContract.Groups.CONTENT_URI, values);
651ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(groupUri);
652ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
653ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
6545ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov    public long createGroupMembership(long rawContactId, long groupId) {
6551d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey        ensureCallingPackage();
656ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        final ContentValues values = new ContentValues();
6575ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov        values.put(Data.RAW_CONTACT_ID, rawContactId);
658ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(Data.MIMETYPE, CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE);
659ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        values.put(CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId);
6606cffee46a1334d2b3ed19f436b27638451541044Dmitri Plotnikov        Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI,
6615ef0401c311c62e53bde415b99cbb0ff83b0a9a2Dmitri Plotnikov                rawContactId), RawContacts.Data.CONTENT_DIRECTORY);
662ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        Uri dataUri = resolver.insert(insertUri, values);
663ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        return ContentUris.parseId(dataUri);
664ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
665ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
66647fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov    protected void setAggregationException(int type, long rawContactId1, long rawContactId2) {
66747fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        ContentValues values = new ContentValues();
66847fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
66947fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        values.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
67047fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        values.put(AggregationExceptions.TYPE, type);
67147fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov        resolver.update(AggregationExceptions.CONTENT_URI, values, null, null);
67247fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov    }
67347fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov
674bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    public void setAccounts(Account[] accounts) {
675bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        mAccounts = accounts;
676bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    }
677bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
678ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    /**
679ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     * Various internal database projections.
680ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey     */
681ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private interface Projections {
682ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        static final String[] PROJ_ID = new String[] {
683ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey                BaseColumns._ID,
684ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
685ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
686ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        static final int COL_ID = 0;
687ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
688d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        static final String[] PROJ_RAW_CONTACTS = new String[] {
689d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov                RawContacts.CONTACT_ID
690ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey        };
691ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
692d3fde755e73cd3912a488e7cb7d412d3c5f6ca94Dmitri Plotnikov        static final int COL_CONTACTS_ID = 0;
693ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    }
694619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey}
695