| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.providers.contacts; |
| |
| import static org.mockito.Mockito.when; |
| |
| import android.accounts.Account; |
| import android.accounts.AccountManager; |
| import android.accounts.AccountManagerCallback; |
| import android.accounts.AccountManagerFuture; |
| import android.accounts.AuthenticatorException; |
| import android.accounts.OnAccountsUpdateListener; |
| import android.accounts.OperationCanceledException; |
| import android.content.ContentProvider; |
| import android.content.ContentResolver; |
| import android.content.ContentUris; |
| import android.content.ContentValues; |
| import android.content.Context; |
| import android.content.ContextWrapper; |
| import android.content.Intent; |
| import android.content.SharedPreferences; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ProviderInfo; |
| import android.content.pm.UserInfo; |
| import android.content.res.Configuration; |
| import android.content.res.Resources; |
| import android.database.Cursor; |
| import android.location.Country; |
| import android.location.CountryDetector; |
| import android.location.CountryListener; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.provider.BaseColumns; |
| import android.provider.ContactsContract; |
| import android.provider.ContactsContract.AggregationExceptions; |
| import android.provider.ContactsContract.CommonDataKinds; |
| import android.provider.ContactsContract.CommonDataKinds.Email; |
| import android.provider.ContactsContract.CommonDataKinds.Phone; |
| import android.provider.ContactsContract.Contacts; |
| import android.provider.ContactsContract.Data; |
| import android.provider.ContactsContract.RawContacts; |
| import android.provider.ContactsContract.StatusUpdates; |
| import android.telecom.TelecomManager; |
| import android.telephony.TelephonyManager; |
| import android.test.IsolatedContext; |
| import android.test.mock.MockContentResolver; |
| import android.test.mock.MockContext; |
| import android.text.TextUtils; |
| |
| import com.android.providers.contacts.util.ContactsPermissions; |
| import com.android.providers.contacts.util.MockSharedPreferences; |
| |
| import com.google.android.collect.Sets; |
| |
| import org.mockito.Mockito; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Set; |
| |
| /** |
| * Helper class that encapsulates an "actor" which is owned by a specific |
| * package name. It correctly maintains a wrapped {@link Context} and an |
| * attached {@link MockContentResolver}. Multiple actors can be used to test |
| * security scenarios between multiple packages. |
| */ |
| public class ContactsActor { |
| private static final String FILENAME_PREFIX = "test."; |
| |
| public static final String PACKAGE_GREY = "edu.example.grey"; |
| public static final String PACKAGE_RED = "net.example.red"; |
| public static final String PACKAGE_GREEN = "com.example.green"; |
| public static final String PACKAGE_BLUE = "org.example.blue"; |
| |
| private static final int DEFAULT_USER_ID = 0; |
| |
| public Context context; |
| public String packageName; |
| public MockContentResolver resolver; |
| public ContentProvider provider; |
| private Country mMockCountry = new Country("us", 0); |
| |
| private Account[] mAccounts = new Account[0]; |
| |
| private Set<String> mGrantedPermissions = Sets.newHashSet(); |
| private final Set<Uri> mGrantedUriPermissions = Sets.newHashSet(); |
| private boolean mHasCarrierPrivileges; |
| |
| private List<ContentProvider> mAllProviders = new ArrayList<>(); |
| |
| private CountryDetector mMockCountryDetector = new CountryDetector(null){ |
| @Override |
| public Country detectCountry() { |
| return mMockCountry; |
| } |
| |
| @Override |
| public void addCountryListener(CountryListener listener, Looper looper) { |
| } |
| }; |
| |
| private AccountManager mMockAccountManager; |
| |
| private class MockAccountManager extends AccountManager { |
| public MockAccountManager(Context conteact) { |
| super(context, null, null); |
| } |
| |
| @Override |
| public void addOnAccountsUpdatedListener(OnAccountsUpdateListener listener, |
| Handler handler, boolean updateImmediately) { |
| // do nothing |
| } |
| |
| @Override |
| public Account[] getAccounts() { |
| return mAccounts; |
| } |
| |
| @Override |
| public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures( |
| final String type, final String[] features, |
| AccountManagerCallback<Account[]> callback, Handler handler) { |
| return null; |
| } |
| |
| @Override |
| public String blockingGetAuthToken(Account account, String authTokenType, |
| boolean notifyAuthFailure) |
| throws OperationCanceledException, IOException, AuthenticatorException { |
| return null; |
| } |
| } |
| |
| public MockUserManager mockUserManager; |
| |
| public static class MockUserManager extends UserManager { |
| public static UserInfo createUserInfo(String name, int id, int groupId, int flags) { |
| final UserInfo ui = new UserInfo(id, name, flags | UserInfo.FLAG_INITIALIZED); |
| ui.profileGroupId = groupId; |
| return ui; |
| } |
| |
| public static final UserInfo PRIMARY_USER = createUserInfo("primary", 0, 0, |
| UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN); |
| public static final UserInfo CORP_USER = createUserInfo("corp", 10, 0, |
| UserInfo.FLAG_MANAGED_PROFILE); |
| public static final UserInfo SECONDARY_USER = createUserInfo("2nd", 11, 11, 0); |
| |
| /** "My" user. Set it to change the current user. */ |
| public int myUser = DEFAULT_USER_ID; |
| |
| private ArrayList<UserInfo> mUsers = new ArrayList<>(); |
| |
| public MockUserManager(Context context) { |
| super(context, /* IUserManager */ null); |
| |
| mUsers.add(PRIMARY_USER); // Add the primary user. |
| } |
| |
| /** Replaces users. */ |
| public void setUsers(UserInfo... users) { |
| mUsers.clear(); |
| for (UserInfo ui : users) { |
| mUsers.add(ui); |
| } |
| } |
| |
| @Override |
| public int getUserHandle() { |
| return myUser; |
| } |
| |
| @Override |
| public UserInfo getUserInfo(int userHandle) { |
| for (UserInfo ui : mUsers) { |
| if (ui.id == userHandle) { |
| return ui; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public UserInfo getProfileParent(int userHandle) { |
| final UserInfo child = getUserInfo(userHandle); |
| if (child == null) { |
| return null; |
| } |
| for (UserInfo ui : mUsers) { |
| if (ui.id != userHandle && ui.id == child.profileGroupId) { |
| return ui; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public List<UserInfo> getUsers() { |
| return mUsers; |
| } |
| |
| @Override |
| public Bundle getUserRestrictions(UserHandle userHandle) { |
| return new Bundle(); |
| } |
| |
| @Override |
| public boolean hasUserRestriction(String restrictionKey) { |
| return false; |
| } |
| |
| @Override |
| public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) { |
| return false; |
| } |
| |
| @Override |
| public boolean isSameProfileGroup(int userId, int otherUserId) { |
| return getUserInfo(userId).profileGroupId == getUserInfo(otherUserId).profileGroupId; |
| } |
| |
| @Override |
| public boolean isUserUnlocked(int userId) { |
| return true; // Just make it always unlocked for now. |
| } |
| } |
| |
| private MockTelephonyManager mMockTelephonyManager; |
| |
| private class MockTelephonyManager extends TelephonyManager { |
| public MockTelephonyManager(Context context) { |
| super(context); |
| } |
| |
| @Override |
| public int checkCarrierPrivilegesForPackageAnyPhone(String packageName) { |
| if (TextUtils.equals(packageName, ContactsActor.this.packageName) |
| && mHasCarrierPrivileges) { |
| return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; |
| } |
| return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; |
| } |
| |
| @Override |
| public List<String> getPackagesWithCarrierPrivileges() { |
| if (!mHasCarrierPrivileges) { |
| return Collections.emptyList(); |
| } |
| return Collections.singletonList(packageName); |
| } |
| } |
| |
| private TelecomManager mMockTelecomManager; |
| |
| /** |
| * A context wrapper that reports a different user id. |
| * |
| * TODO This should override getSystemService() and returns a UserManager that returns the |
| * same, altered user ID too. |
| */ |
| public static class AlteringUserContext extends ContextWrapper { |
| private final int mUserId; |
| |
| public AlteringUserContext(Context base, int userId) { |
| super(base); |
| mUserId = userId; |
| } |
| |
| @Override |
| public int getUserId() { |
| return mUserId; |
| } |
| } |
| |
| private IsolatedContext mProviderContext; |
| |
| /** |
| * Create an "actor" using the given parent {@link Context} and the specific |
| * package name. Internally, all {@link Context} method calls are passed to |
| * a new instance of {@link RestrictionMockContext}, which stubs out the |
| * security infrastructure. |
| */ |
| public ContactsActor(final Context overallContext, String packageName, |
| Class<? extends ContentProvider> providerClass, String authority) throws Exception { |
| |
| // Force permission check even when called by self. |
| ContactsPermissions.ALLOW_SELF_CALL = false; |
| |
| resolver = new MockContentResolver(); |
| context = new RestrictionMockContext(overallContext, packageName, resolver, |
| mGrantedPermissions, mGrantedUriPermissions) { |
| @Override |
| public Object getSystemService(String name) { |
| if (Context.COUNTRY_DETECTOR.equals(name)) { |
| return mMockCountryDetector; |
| } |
| if (Context.ACCOUNT_SERVICE.equals(name)) { |
| return mMockAccountManager; |
| } |
| if (Context.USER_SERVICE.equals(name)) { |
| return mockUserManager; |
| } |
| if (Context.TELEPHONY_SERVICE.equals(name)) { |
| return mMockTelephonyManager; |
| } |
| if (Context.TELECOM_SERVICE.equals(name)) { |
| return mMockTelecomManager; |
| } |
| // Use overallContext here; super.getSystemService() somehow won't return |
| // DevicePolicyManager. |
| return overallContext.getSystemService(name); |
| } |
| |
| |
| |
| @Override |
| public String getSystemServiceName(Class<?> serviceClass) { |
| return overallContext.getSystemServiceName(serviceClass); |
| } |
| }; |
| this.packageName = packageName; |
| |
| // Let the Secure class initialize the settings provider, which is done when we first |
| // tries to get any setting. Because our mock context/content resolver doesn't have the |
| // settings provider, we need to do this with an actual context, before other classes |
| // try to do this with a mock context. |
| // (Otherwise ContactsProvider2.initialzie() will crash trying to get a setting with |
| // a mock context.) |
| android.provider.Settings.Secure.getString(overallContext.getContentResolver(), "dummy"); |
| |
| RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(context, |
| overallContext, FILENAME_PREFIX); |
| mProviderContext = new IsolatedContext(resolver, targetContextWrapper) { |
| private final MockSharedPreferences mPrefs = new MockSharedPreferences(); |
| |
| @Override |
| public File getFilesDir() { |
| // TODO: Need to figure out something more graceful than this. |
| return new File("/data/data/com.android.providers.contacts.tests/files"); |
| } |
| |
| @Override |
| public Object getSystemService(String name) { |
| if (Context.COUNTRY_DETECTOR.equals(name)) { |
| return mMockCountryDetector; |
| } |
| if (Context.ACCOUNT_SERVICE.equals(name)) { |
| return mMockAccountManager; |
| } |
| if (Context.USER_SERVICE.equals(name)) { |
| return mockUserManager; |
| } |
| if (Context.TELEPHONY_SERVICE.equals(name)) { |
| return mMockTelephonyManager; |
| } |
| if (Context.TELECOM_SERVICE.equals(name)) { |
| return mMockTelecomManager; |
| } |
| // Use overallContext here; super.getSystemService() somehow won't return |
| // DevicePolicyManager. |
| return overallContext.getSystemService(name); |
| } |
| |
| @Override |
| public String getSystemServiceName(Class<?> serviceClass) { |
| return overallContext.getSystemServiceName(serviceClass); |
| } |
| |
| @Override |
| public SharedPreferences getSharedPreferences(String name, int mode) { |
| return mPrefs; |
| } |
| |
| @Override |
| public int getUserId() { |
| if (mockUserManager != null) { |
| return mockUserManager.getUserHandle(); |
| } else { |
| return DEFAULT_USER_ID; |
| } |
| } |
| |
| @Override |
| public void sendBroadcast(Intent intent, String receiverPermission) { |
| // Ignore. |
| } |
| |
| @Override |
| public Context getApplicationContext() { |
| return this; |
| } |
| }; |
| |
| mMockAccountManager = new MockAccountManager(mProviderContext); |
| mockUserManager = new MockUserManager(mProviderContext); |
| mMockTelephonyManager = new MockTelephonyManager(mProviderContext); |
| mMockTelecomManager = Mockito.mock(TelecomManager.class); |
| when(mMockTelecomManager.getDefaultDialerPackage()).thenReturn(""); |
| when(mMockTelecomManager.getSystemDialerPackage()).thenReturn(""); |
| provider = addProvider(providerClass, authority); |
| } |
| |
| public Context getProviderContext() { |
| return mProviderContext; |
| } |
| |
| public <T extends ContentProvider> T addProvider(Class<T> providerClass, |
| String authority) throws Exception { |
| return addProvider(providerClass, authority, mProviderContext); |
| } |
| |
| public <T extends ContentProvider> T addProvider(Class<T> providerClass, |
| String authority, Context providerContext) throws Exception { |
| return addProvider(providerClass.newInstance(), authority, providerContext); |
| } |
| |
| public <T extends ContentProvider> T addProvider(T provider, |
| String authority, Context providerContext) throws Exception { |
| ProviderInfo info = new ProviderInfo(); |
| |
| // Here, authority can have "user-id@". We want to use it for addProvider, but provider |
| // info shouldn't have it. |
| info.authority = stripOutUserIdFromAuthority(authority); |
| provider.attachInfoForTesting(providerContext, info); |
| |
| // In case of LegacyTest, "authority" here is actually multiple authorities. |
| // Register all authority here. |
| for (String a : authority.split(";")) { |
| resolver.addProvider(a, provider); |
| resolver.addProvider("0@" + a, provider); |
| } |
| mAllProviders.add(provider); |
| return provider; |
| } |
| |
| /** |
| * Takes an provider authority. If it has "userid@", then remove it. |
| */ |
| private String stripOutUserIdFromAuthority(String authority) { |
| final int pos = authority.indexOf('@'); |
| return pos < 0 ? authority : authority.substring(pos + 1); |
| } |
| |
| public void addPermissions(String... permissions) { |
| mGrantedPermissions.addAll(Arrays.asList(permissions)); |
| } |
| |
| public void removePermissions(String... permissions) { |
| mGrantedPermissions.removeAll(Arrays.asList(permissions)); |
| } |
| |
| public void addUriPermissions(Uri... uris) { |
| mGrantedUriPermissions.addAll(Arrays.asList(uris)); |
| } |
| |
| public void removeUriPermissions(Uri... uris) { |
| mGrantedUriPermissions.removeAll(Arrays.asList(uris)); |
| } |
| |
| public void grantCarrierPrivileges() { |
| mHasCarrierPrivileges = true; |
| } |
| |
| public void revokeCarrierPrivileges() { |
| mHasCarrierPrivileges = false; |
| } |
| |
| /** |
| * Mock {@link Context} that reports specific well-known values for testing |
| * data protection. The creator can override the owner package name, and |
| * force the {@link PackageManager} to always return a well-known package |
| * list for any call to {@link PackageManager#getPackagesForUid(int)}. |
| * <p> |
| * For example, the creator could request that the {@link Context} lives in |
| * package name "com.example.red", and also cause the {@link PackageManager} |
| * to report that no UID contains that package name. |
| */ |
| private static class RestrictionMockContext extends MockContext { |
| private final Context mOverallContext; |
| private final String mReportedPackageName; |
| private final ContactsMockPackageManager mPackageManager; |
| private final ContentResolver mResolver; |
| private final Resources mRes; |
| private final Set<String> mGrantedPermissions; |
| private final Set<Uri> mGrantedUriPermissions; |
| |
| /** |
| * Create a {@link Context} under the given package name. |
| */ |
| public RestrictionMockContext(Context overallContext, String reportedPackageName, |
| ContentResolver resolver, Set<String> grantedPermissions, |
| Set<Uri> grantedUriPermissions) { |
| mOverallContext = overallContext; |
| mReportedPackageName = reportedPackageName; |
| mResolver = resolver; |
| mGrantedPermissions = grantedPermissions; |
| mGrantedUriPermissions = grantedUriPermissions; |
| |
| mPackageManager = new ContactsMockPackageManager(overallContext); |
| mPackageManager.addPackage(1000, PACKAGE_GREY); |
| mPackageManager.addPackage(2000, PACKAGE_RED); |
| mPackageManager.addPackage(3000, PACKAGE_GREEN); |
| mPackageManager.addPackage(4000, PACKAGE_BLUE); |
| |
| Resources resources = overallContext.getResources(); |
| Configuration configuration = new Configuration(resources.getConfiguration()); |
| configuration.locale = Locale.US; |
| resources.updateConfiguration(configuration, resources.getDisplayMetrics()); |
| mRes = resources; |
| } |
| |
| @Override |
| public String getPackageName() { |
| return mReportedPackageName; |
| } |
| |
| @Override |
| public PackageManager getPackageManager() { |
| return mPackageManager; |
| } |
| |
| @Override |
| public Resources getResources() { |
| return mRes; |
| } |
| |
| @Override |
| public ContentResolver getContentResolver() { |
| return mResolver; |
| } |
| |
| @Override |
| public ApplicationInfo getApplicationInfo() { |
| ApplicationInfo ai = new ApplicationInfo(); |
| ai.packageName = "contactsTestPackage"; |
| return ai; |
| } |
| |
| // All permission checks are implemented to simply check against the granted permission set. |
| |
| @Override |
| public int checkPermission(String permission, int pid, int uid) { |
| return checkCallingPermission(permission); |
| } |
| |
| @Override |
| public int checkCallingPermission(String permission) { |
| if (mGrantedPermissions.contains(permission)) { |
| return PackageManager.PERMISSION_GRANTED; |
| } else { |
| return PackageManager.PERMISSION_DENIED; |
| } |
| } |
| |
| @Override |
| public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) { |
| return checkCallingUriPermission(uri, modeFlags); |
| } |
| |
| @Override |
| public int checkCallingUriPermission(Uri uri, int modeFlags) { |
| if (mGrantedUriPermissions.contains(uri)) { |
| return PackageManager.PERMISSION_GRANTED; |
| } else { |
| return PackageManager.PERMISSION_DENIED; |
| } |
| } |
| |
| @Override |
| public int checkCallingOrSelfPermission(String permission) { |
| return checkCallingPermission(permission); |
| } |
| |
| @Override |
| public void enforcePermission(String permission, int pid, int uid, String message) { |
| enforceCallingPermission(permission, message); |
| } |
| |
| @Override |
| public void enforceCallingPermission(String permission, String message) { |
| if (!mGrantedPermissions.contains(permission)) { |
| throw new SecurityException(message); |
| } |
| } |
| |
| @Override |
| public void enforceCallingOrSelfPermission(String permission, String message) { |
| enforceCallingPermission(permission, message); |
| } |
| |
| @Override |
| public void sendBroadcast(Intent intent) { |
| mOverallContext.sendBroadcast(intent); |
| } |
| |
| @Override |
| public void sendBroadcast(Intent intent, String receiverPermission) { |
| mOverallContext.sendBroadcast(intent, receiverPermission); |
| } |
| } |
| |
| static String sCallingPackage = null; |
| |
| void ensureCallingPackage() { |
| sCallingPackage = this.packageName; |
| } |
| |
| public long createRawContact(String name) { |
| ensureCallingPackage(); |
| long rawContactId = createRawContact(); |
| createName(rawContactId, name); |
| return rawContactId; |
| } |
| |
| public long createRawContact() { |
| ensureCallingPackage(); |
| final ContentValues values = new ContentValues(); |
| |
| Uri rawContactUri = resolver.insert(RawContacts.CONTENT_URI, values); |
| return ContentUris.parseId(rawContactUri); |
| } |
| |
| public long createRawContactWithStatus(String name, String address, |
| String status) { |
| final long rawContactId = createRawContact(name); |
| final long dataId = createEmail(rawContactId, address); |
| createStatus(dataId, status); |
| return rawContactId; |
| } |
| |
| public long createName(long contactId, String name) { |
| ensureCallingPackage(); |
| final ContentValues values = new ContentValues(); |
| values.put(Data.RAW_CONTACT_ID, contactId); |
| values.put(Data.IS_PRIMARY, 1); |
| values.put(Data.IS_SUPER_PRIMARY, 1); |
| values.put(Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE); |
| values.put(CommonDataKinds.StructuredName.FAMILY_NAME, name); |
| Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, |
| contactId), RawContacts.Data.CONTENT_DIRECTORY); |
| Uri dataUri = resolver.insert(insertUri, values); |
| return ContentUris.parseId(dataUri); |
| } |
| |
| public long createPhone(long contactId, String phoneNumber) { |
| ensureCallingPackage(); |
| final ContentValues values = new ContentValues(); |
| values.put(Data.RAW_CONTACT_ID, contactId); |
| values.put(Data.IS_PRIMARY, 1); |
| values.put(Data.IS_SUPER_PRIMARY, 1); |
| values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); |
| values.put(ContactsContract.CommonDataKinds.Phone.TYPE, |
| ContactsContract.CommonDataKinds.Phone.TYPE_HOME); |
| values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber); |
| Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, |
| contactId), RawContacts.Data.CONTENT_DIRECTORY); |
| Uri dataUri = resolver.insert(insertUri, values); |
| return ContentUris.parseId(dataUri); |
| } |
| |
| public long createEmail(long contactId, String address) { |
| ensureCallingPackage(); |
| final ContentValues values = new ContentValues(); |
| values.put(Data.RAW_CONTACT_ID, contactId); |
| values.put(Data.IS_PRIMARY, 1); |
| values.put(Data.IS_SUPER_PRIMARY, 1); |
| values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); |
| values.put(Email.TYPE, Email.TYPE_HOME); |
| values.put(Email.DATA, address); |
| Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, |
| contactId), RawContacts.Data.CONTENT_DIRECTORY); |
| Uri dataUri = resolver.insert(insertUri, values); |
| return ContentUris.parseId(dataUri); |
| } |
| |
| public long createStatus(long dataId, String status) { |
| ensureCallingPackage(); |
| final ContentValues values = new ContentValues(); |
| values.put(StatusUpdates.DATA_ID, dataId); |
| values.put(StatusUpdates.STATUS, status); |
| Uri dataUri = resolver.insert(StatusUpdates.CONTENT_URI, values); |
| return ContentUris.parseId(dataUri); |
| } |
| |
| public void updateException(String packageProvider, String packageClient, boolean allowAccess) { |
| throw new UnsupportedOperationException("RestrictionExceptions are hard-coded"); |
| } |
| |
| public long getContactForRawContact(long rawContactId) { |
| ensureCallingPackage(); |
| Uri contactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); |
| final Cursor cursor = resolver.query(contactUri, Projections.PROJ_RAW_CONTACTS, null, |
| null, null); |
| if (!cursor.moveToFirst()) { |
| cursor.close(); |
| throw new RuntimeException("Contact didn't have an aggregate"); |
| } |
| final long aggId = cursor.getLong(Projections.COL_CONTACTS_ID); |
| cursor.close(); |
| return aggId; |
| } |
| |
| public int getDataCountForContact(long contactId) { |
| ensureCallingPackage(); |
| Uri contactUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, |
| contactId), Contacts.Data.CONTENT_DIRECTORY); |
| final Cursor cursor = resolver.query(contactUri, Projections.PROJ_ID, null, null, |
| null); |
| final int count = cursor.getCount(); |
| cursor.close(); |
| return count; |
| } |
| |
| public int getDataCountForRawContact(long rawContactId) { |
| ensureCallingPackage(); |
| Uri contactUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, |
| rawContactId), Contacts.Data.CONTENT_DIRECTORY); |
| final Cursor cursor = resolver.query(contactUri, Projections.PROJ_ID, null, null, |
| null); |
| final int count = cursor.getCount(); |
| cursor.close(); |
| return count; |
| } |
| |
| public void setSuperPrimaryPhone(long dataId) { |
| ensureCallingPackage(); |
| final ContentValues values = new ContentValues(); |
| values.put(Data.IS_PRIMARY, 1); |
| values.put(Data.IS_SUPER_PRIMARY, 1); |
| Uri updateUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId); |
| resolver.update(updateUri, values, null, null); |
| } |
| |
| public long createGroup(String groupName) { |
| ensureCallingPackage(); |
| final ContentValues values = new ContentValues(); |
| values.put(ContactsContract.Groups.RES_PACKAGE, packageName); |
| values.put(ContactsContract.Groups.TITLE, groupName); |
| Uri groupUri = resolver.insert(ContactsContract.Groups.CONTENT_URI, values); |
| return ContentUris.parseId(groupUri); |
| } |
| |
| public long createGroupMembership(long rawContactId, long groupId) { |
| ensureCallingPackage(); |
| final ContentValues values = new ContentValues(); |
| values.put(Data.RAW_CONTACT_ID, rawContactId); |
| values.put(Data.MIMETYPE, CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE); |
| values.put(CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId); |
| Uri insertUri = Uri.withAppendedPath(ContentUris.withAppendedId(RawContacts.CONTENT_URI, |
| rawContactId), RawContacts.Data.CONTENT_DIRECTORY); |
| Uri dataUri = resolver.insert(insertUri, values); |
| return ContentUris.parseId(dataUri); |
| } |
| |
| protected void setAggregationException(int type, long rawContactId1, long rawContactId2) { |
| ContentValues values = new ContentValues(); |
| values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); |
| values.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); |
| values.put(AggregationExceptions.TYPE, type); |
| resolver.update(AggregationExceptions.CONTENT_URI, values, null, null); |
| } |
| |
| public void setAccounts(Account[] accounts) { |
| mAccounts = accounts; |
| } |
| |
| /** |
| * Various internal database projections. |
| */ |
| private interface Projections { |
| static final String[] PROJ_ID = new String[] { |
| BaseColumns._ID, |
| }; |
| |
| static final int COL_ID = 0; |
| |
| static final String[] PROJ_RAW_CONTACTS = new String[] { |
| RawContacts.CONTACT_ID |
| }; |
| |
| static final int COL_CONTACTS_ID = 0; |
| } |
| |
| public void shutdown() { |
| for (ContentProvider provider : mAllProviders) { |
| provider.shutdown(); |
| } |
| } |
| } |