diff options
Diffstat (limited to 'tests/src')
10 files changed, 792 insertions, 144 deletions
diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java index 54984d29..e8920530 100644 --- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java +++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java @@ -70,6 +70,8 @@ import com.android.providers.contacts.util.Hex; import com.android.providers.contacts.util.MockClock; import com.google.android.collect.Sets; +import java.io.FileInputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; @@ -1381,6 +1383,25 @@ public abstract class BaseContactsProvider2Test extends PhotoLoadingTestCase { assertEquals(timeStamp, time); } + /** + * Asserts the equality of two Uri objects, ignoring the order of the query parameters. + */ + protected static void assertUriEquals(Uri expected, Uri actual) { + assertEquals(expected.getScheme(), actual.getScheme()); + assertEquals(expected.getAuthority(), actual.getAuthority()); + assertEquals(expected.getPath(), actual.getPath()); + assertEquals(expected.getFragment(), actual.getFragment()); + Set<String> expectedParameterNames = expected.getQueryParameterNames(); + Set<String> actualParameterNames = actual.getQueryParameterNames(); + assertEquals(expectedParameterNames.size(), actualParameterNames.size()); + assertTrue(expectedParameterNames.containsAll(actualParameterNames)); + for (String parameterName : expectedParameterNames) { + assertEquals(expected.getQueryParameter(parameterName), + actual.getQueryParameter(parameterName)); + } + + } + protected void setTimeForTest(Long time) { Uri uri = Calls.CONTENT_URI.buildUpon() .appendQueryParameter(CallLogProvider.PARAM_KEY_QUERY_FOR_TESTING, "1") @@ -1400,6 +1421,71 @@ public abstract class BaseContactsProvider2Test extends PhotoLoadingTestCase { getContactsProvider().getProfileProviderForTest().getDatabaseHelper(), values); } + protected class VCardTestUriCreator { + private String mLookup1; + private String mLookup2; + + public VCardTestUriCreator(String lookup1, String lookup2) { + super(); + mLookup1 = lookup1; + mLookup2 = lookup2; + } + + public Uri getUri1() { + return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup1); + } + + public Uri getUri2() { + return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup2); + } + + public Uri getCombinedUri() { + return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, + Uri.encode(mLookup1 + ":" + mLookup2)); + } + } + + protected VCardTestUriCreator createVCardTestContacts() { + final long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount, + RawContacts.SOURCE_ID, "4:12"); + DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Doe"); + + final long rawContactId2 = RawContactUtil.createRawContact(mResolver, mAccount, + RawContacts.SOURCE_ID, "3:4%121"); + DataUtil.insertStructuredName(mResolver, rawContactId2, "Jane", "Doh"); + + final long contactId1 = queryContactId(rawContactId1); + final long contactId2 = queryContactId(rawContactId2); + final Uri contact1Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1); + final Uri contact2Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2); + final String lookup1 = + Uri.encode(Contacts.getLookupUri(mResolver, contact1Uri).getPathSegments().get(2)); + final String lookup2 = + Uri.encode(Contacts.getLookupUri(mResolver, contact2Uri).getPathSegments().get(2)); + return new VCardTestUriCreator(lookup1, lookup2); + } + + protected String readToEnd(FileInputStream inputStream) { + try { + System.out.println("DECLARED INPUT STREAM LENGTH: " + inputStream.available()); + int ch; + StringBuilder stringBuilder = new StringBuilder(); + int index = 0; + while (true) { + ch = inputStream.read(); + System.out.println("READ CHARACTER: " + index + " " + ch); + if (ch == -1) { + break; + } + stringBuilder.append((char)ch); + index++; + } + return stringBuilder.toString(); + } catch (IOException e) { + return null; + } + } + /** * A contact in the database, and the attributes used to create it. Construct using * {@link GoldenContactBuilder#build()}. diff --git a/tests/src/com/android/providers/contacts/CallLogMigrationTest.java b/tests/src/com/android/providers/contacts/CallLogMigrationTest.java index d1e80035..74e5d0a5 100644 --- a/tests/src/com/android/providers/contacts/CallLogMigrationTest.java +++ b/tests/src/com/android/providers/contacts/CallLogMigrationTest.java @@ -93,51 +93,6 @@ public class CallLogMigrationTest extends FixedAndroidTestCase { + " = 1", null)); } - public void testMigration() throws IOException { - final File sourceDbFile = new File(getTestContext().getCacheDir(), "contacts2src.db"); - writeAssetFileToDisk("calllogmigration/contacts2.db", sourceDbFile); - - try (final SQLiteDatabase sourceDb = SQLiteDatabase.openDatabase( - sourceDbFile.getAbsolutePath(), /* cursorFactory=*/ null, - SQLiteDatabase.OPEN_READWRITE)) { - - // Make sure the source tables exist initially. - assertTrue(CallLogDatabaseHelper.tableExists(sourceDb, "calls")); - assertTrue(CallLogDatabaseHelper.tableExists(sourceDb, "voicemail_status")); - // Create the calllog DB to perform the migration. - final CallLogDatabaseHelperTestable dbh = - new CallLogDatabaseHelperTestable(getTestContext(), sourceDb); - - final SQLiteDatabase db = dbh.getReadableDatabase(); - - // Check the content: - // Note what we worry here is basically insertion error due to additional constraints, - // renames, etc. So here, we just check the number of rows and don't check the content. - assertEquals(3, DatabaseUtils.longForQuery(db, "select count(*) from " + - CallLogDatabaseHelper.Tables.CALLS, null)); - - assertEquals(2, DatabaseUtils.longForQuery(db, "select count(*) from " + - CallLogDatabaseHelper.Tables.VOICEMAIL_STATUS, null)); - - assertEquals("123456", - dbh.getProperty(CallLogDatabaseHelper.DbProperties.CALL_LOG_LAST_SYNCED, "")); - - // Test onCreate() step, check each entry with TelephonyComponent in the CALLS has - // a new coloumn of Calls.IS_PHONE_ACCOUNT_MIGRATION_PENDING. - assertEquals(3, - DatabaseUtils.longForQuery(db, "select count(*) from " - + CallLogDatabaseHelper.Tables.CALLS + " where " - + Calls.IS_PHONE_ACCOUNT_MIGRATION_PENDING + " = 0", null)); - - // Also, the source table should have been removed. - assertFalse(CallLogDatabaseHelper.tableExists(sourceDb, "calls")); - assertFalse(CallLogDatabaseHelper.tableExists(sourceDb, "voicemail_status")); - - assertEquals("1", - dbh.getProperty(CallLogDatabaseHelper.DbProperties.DATA_MIGRATED, "")); - } - } - public static final class InMemoryCallLogProviderDbHelperV1 extends SQLiteOpenHelper { public InMemoryCallLogProviderDbHelperV1(Context context, int databaseVersion) { super(context, diff --git a/tests/src/com/android/providers/contacts/CloneContactsProvider2Test.java b/tests/src/com/android/providers/contacts/CloneContactsProvider2Test.java new file mode 100644 index 00000000..26a78143 --- /dev/null +++ b/tests/src/com/android/providers/contacts/CloneContactsProvider2Test.java @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2022 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 com.android.providers.contacts.ContactsActor.MockUserManager.CLONE_PROFILE_USER; +import static com.android.providers.contacts.ContactsActor.MockUserManager.PRIMARY_USER; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.spy; + +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.OperationApplicationException; +import android.content.res.AssetFileDescriptor; +import android.database.Cursor; +import android.net.Uri; +import android.os.Binder; +import android.os.Build; +import android.os.Bundle; +import android.os.RemoteException; +import android.provider.CallLog; +import android.provider.ContactsContract; +import android.util.SparseArray; + +import androidx.test.filters.MediumTest; +import androidx.test.filters.SdkSuppress; + +import org.junit.Assert; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Set; + +@MediumTest +@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake") +public class CloneContactsProvider2Test extends BaseContactsProvider2Test { + + private ContactsActor mCloneContactsActor; + private SynchronousContactsProvider2 mCloneContactsProvider; + + private SynchronousContactsProvider2 getCloneContactsProvider() { + return (SynchronousContactsProvider2) mCloneContactsActor.provider; + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mCloneContactsActor = new ContactsActor( + new ContactsActor.AlteringUserContext(getContext(), CLONE_PROFILE_USER.id), + getContextPackageName(), SynchronousContactsProvider2.class, getAuthority()); + mActor.mockUserManager.setUsers(ContactsActor.MockUserManager.PRIMARY_USER, + CLONE_PROFILE_USER); + mCloneContactsActor.mockUserManager.setUsers(ContactsActor.MockUserManager.PRIMARY_USER, + CLONE_PROFILE_USER); + mCloneContactsActor.mockUserManager.myUser = CLONE_PROFILE_USER.id; + mCloneContactsProvider = spy(getCloneContactsProvider()); + mCloneContactsProvider.wipeData(); + } + + private ContentValues getSampleContentValues() { + ContentValues values = new ContentValues(); + values.put(ContactsContract.RawContacts.ACCOUNT_NAME, "test@test.com"); + values.put(ContactsContract.RawContacts.ACCOUNT_TYPE, "test.com"); + values.put(ContactsContract.RawContacts.CUSTOM_RINGTONE, "custom"); + values.put(ContactsContract.RawContacts.STARRED, "1"); + return values; + } + + private void getCloneContactsProviderWithMockedCallToParent(Uri uri) { + Cursor primaryProfileCursor = mActor.provider.query(uri, + null /* projection */, null /* queryArgs */, null /* cancellationSignal */); + assertNotNull(primaryProfileCursor); + doReturn(primaryProfileCursor).when(mCloneContactsProvider) + .queryContactsProviderForUser(eq(uri), any(), any(), any(), any(), + any(), eq(PRIMARY_USER)); + } + + private void getCloneContactsProviderWithMockedOpenAssetFileCall(Uri uri) + throws FileNotFoundException { + AssetFileDescriptor fileDescriptor = mActor.provider.openAssetFile(uri, "r"); + doReturn(fileDescriptor).when(mCloneContactsProvider) + .openAssetFileThroughParentProvider(eq(uri), eq("r")); + } + + private String getCursorValue(Cursor c, String columnName) { + return c.getString(c.getColumnIndex(columnName)); + } + + private void assertEqualContentValues(ContentValues contentValues, Cursor cursor) { + for (String key: contentValues.getValues().keySet()) { + assertEquals(contentValues.get(key), getCursorValue(cursor, key)); + } + } + + private void assertRawContactsCursorEquals(Cursor expectedCursor, Cursor actualCursor, + Set<String> columnNames) { + assertNotNull(actualCursor); + assertEquals(expectedCursor.getCount(), actualCursor.getCount()); + while (actualCursor.moveToNext()) { + expectedCursor.moveToNext(); + for (String key: columnNames) { + assertEquals(getCursorValue(expectedCursor, key), + getCursorValue(actualCursor, key)); + } + } + } + + private void assertRejectedApplyBatchResults(ContentProviderResult[] res, + ArrayList<ContentProviderOperation> ops) { + assertEquals(ops.size(), res.length); + for (int i = 0;i < ops.size();i++) { + Uri expectedUri = ops.get(i).getUri() + .buildUpon() + .appendPath("0") + .build(); + assertUriEquals(expectedUri, res[i].uri); + } + } + + /** + * Asserts that no contacts are returned when queried by the given contacts provider + */ + private void assertContactsProviderEmpty(ContactsProvider2 contactsProvider2) { + Cursor cursor = contactsProvider2.query(ContactsContract.RawContacts.CONTENT_URI, + new String[]{ContactsContract.RawContactsEntity._ID}, + null /* queryArgs */, null /* cancellationSignal */); + assertNotNull(cursor); + assertEquals(cursor.getCount(), 0); + } + + private long insertRawContactsThroughPrimaryProvider(ContentValues values) { + Uri resultUri = mActor.resolver.insert(ContactsContract.RawContacts.CONTENT_URI, + values); + assertNotNull(resultUri); + return ContentUris.parseId(resultUri); + } + + public void testAreContactWritesEnabled() { + // Check that writes are disabled for clone CP2 + ContactsProvider2 cloneContactsProvider = + (ContactsProvider2) mCloneContactsActor.provider; + assertFalse(cloneContactsProvider.areContactWritesEnabled()); + + // Check that writes are enabled for primary CP2 + ContactsProvider2 primaryContactsProvider = (ContactsProvider2) getProvider(); + assertTrue(primaryContactsProvider.areContactWritesEnabled()); + } + + public void testCloneContactsProviderInsert() { + Uri resultUri = + mCloneContactsActor.resolver.insert(ContactsContract.RawContacts.CONTENT_URI, + getSampleContentValues()); + + // Here we expect a fakeUri returned to fail silently + Uri expectedUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon() + .appendPath("0") + .build(); + assertUriEquals(expectedUri, resultUri); + // No contacts should be present in both clone and primary providers + assertContactsProviderEmpty(getContactsProvider()); + doReturn(false) + .when(mCloneContactsProvider).isAppAllowedToUseParentUsersContacts(any()); + assertContactsProviderEmpty(mCloneContactsProvider); + + } + + public void testPrimaryContactsProviderInsert() { + ContentValues inputContentValues = getSampleContentValues(); + long rawContactId = insertRawContactsThroughPrimaryProvider(inputContentValues); + Cursor cursor = mActor.resolver.query(ContentUris.withAppendedId( + ContactsContract.RawContacts.CONTENT_URI, rawContactId), + null /* projection */, null /* queryArgs */, null /* cancellationSignal */); + assertNotNull(cursor); + assertEquals(1, cursor.getCount()); + assertTrue(cursor.moveToFirst()); + assertEquals(rawContactId, + cursor.getLong(cursor.getColumnIndex(ContactsContract.RawContacts._ID))); + assertEqualContentValues(inputContentValues, cursor); + } + + public void testCloneContactsProviderUpdate() { + // Insert contact through the primary clone provider + ContentValues inputContentValues = getSampleContentValues(); + long rawContactId = insertRawContactsThroughPrimaryProvider(inputContentValues); + + // Update display name in the input content values + ContentValues updatedContentValues = getSampleContentValues(); + updatedContentValues.put(ContactsContract.RawContacts.STARRED, + "0"); + updatedContentValues.put(ContactsContract.RawContacts.CUSTOM_RINGTONE, + "beethoven5"); + + // Call clone contacts provider update method to update the raw contact inserted earlier + int updateResult = mCloneContactsActor.resolver.update( + ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId), + updatedContentValues, null /* extras */); + + // Check results, no rows should have been affected + assertEquals(0, updateResult); + + // Check values associated with rawContactId by querying the database + Cursor cursor = mActor.resolver.query(ContentUris.withAppendedId( + ContactsContract.RawContacts.CONTENT_URI, rawContactId), + null /* projection */, null /* queryArgs */, null /* cancellationSignal */); + assertNotNull(cursor); + assertEquals(1, cursor.getCount()); + assertTrue(cursor.moveToFirst()); + assertEqualContentValues(inputContentValues, cursor); + } + + public void testCloneContactsProviderDelete() { + // Insert contact through the primary clone provider + ContentValues inputContentValues = getSampleContentValues(); + long rawContactId = insertRawContactsThroughPrimaryProvider(inputContentValues); + + // Delete the inserted row through clone provider + int deleteResult = mCloneContactsActor.resolver.delete( + ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId), + null); + + // Check results, no rows should have been affected + assertEquals(0, deleteResult); + + // Check that contact is present in the primary CP2 database + Cursor cursor = mActor.resolver.query(ContentUris.withAppendedId( + ContactsContract.RawContacts.CONTENT_URI, rawContactId), + null /* projection */, null /* queryArgs */, null /* cancellationSignal */); + assertNotNull(cursor); + assertEquals(1, cursor.getCount()); + assertTrue(cursor.moveToFirst()); + assertEqualContentValues(inputContentValues, cursor); + } + + public void testCloneContactsProviderBulkInsert() { + int bulkInsertResult = + mCloneContactsActor.resolver.bulkInsert(ContactsContract.RawContacts.CONTENT_URI, + new ContentValues[]{ getSampleContentValues() }); + + // Check results, no rows should have been affected + assertEquals(0, bulkInsertResult); + // No contacts should be present in both clone and primary providers + assertContactsProviderEmpty(getContactsProvider()); + doReturn(false) + .when(mCloneContactsProvider).isAppAllowedToUseParentUsersContacts(any()); + assertContactsProviderEmpty(mCloneContactsProvider); + } + + public void testCloneContactsApplyBatch() + throws RemoteException, OperationApplicationException { + ArrayList<ContentProviderOperation> ops = new ArrayList<>(); + + ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) + .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null /* value */) + .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null /* value */).build()); + + // Phone Number + ops.add(ContentProviderOperation + .newInsert(ContactsContract.Data.CONTENT_URI) + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "7XXXXXXXXXX") + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, "1").build()); + + // Display name/Contact name + ops.add(ContentProviderOperation + .newInsert(ContactsContract.Data.CONTENT_URI) + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + .withValue(ContactsContract.Data.MIMETYPE, + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "Name") + .build()); + + // Check results, fake uris should be returned for each of the insert operation + ContentProviderResult[] res = mCloneContactsActor.resolver.applyBatch( + ContactsContract.AUTHORITY, ops); + assertRejectedApplyBatchResults(res, ops); + + // No contacts should be present in both clone and primary providers + assertContactsProviderEmpty(getContactsProvider()); + doReturn(false) + .when(mCloneContactsProvider).isAppAllowedToUseParentUsersContacts(any()); + assertContactsProviderEmpty(mCloneContactsProvider); + } + + public void testCloneContactsCallOperation() { + // Query Account Operation + Bundle response = mCloneContactsActor.resolver.call(ContactsContract.AUTHORITY_URI, + ContactsContract.Settings.QUERY_DEFAULT_ACCOUNT_METHOD, null /* arg */, + null /* extras */); + assertNotNull(response); + assertEquals(Bundle.EMPTY, response); + + // Set account operation + Bundle bundle = new Bundle(); + bundle.putString(ContactsContract.Settings.ACCOUNT_NAME, "test@test.com"); + bundle.putString(ContactsContract.Settings.ACCOUNT_TYPE, "test.com"); + Bundle setAccountResponse = + mCloneContactsActor.resolver.call(ContactsContract.AUTHORITY_URI, + ContactsContract.Settings.SET_DEFAULT_ACCOUNT_METHOD, null /* arg */, bundle); + assertNotNull(setAccountResponse); + assertEquals(Bundle.EMPTY, response); + + // Authorization URI + Uri testUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, 1); + final Bundle uriBundle = new Bundle(); + uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, testUri); + final Bundle authResponse = mCloneContactsActor.resolver.call( + ContactsContract.AUTHORITY_URI, + ContactsContract.Authorization.AUTHORIZATION_METHOD, + null /* arg */, + uriBundle); + assertNotNull(authResponse); + assertEquals(Bundle.EMPTY, authResponse); + } + + public void testCloneContactsProviderReads_callerNotInAllowlist() { + // Insert raw contact through the primary clone provider + ContentValues inputContentValues = getSampleContentValues(); + long rawContactId = insertRawContactsThroughPrimaryProvider(inputContentValues); + Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, + rawContactId); + + // Mock call to parent profile contacts provider to return the correct result containing all + // contacts in the parent profile. + getCloneContactsProviderWithMockedCallToParent(uri); + + // Mock call to ensure the caller package is not in the app-cloning allowlist + doReturn(false) + .when(mCloneContactsProvider).isAppAllowedToUseParentUsersContacts(any()); + + // Test clone contacts provider read with the uri of the contact added above + mCloneContactsProvider.query(uri, + null /* projection */, null /* queryArgs */, null /* cancellationSignal */); + + // Check that the call passed through to the local query instead of redirecting to the + // parent provider + verify(mCloneContactsProvider, times(1)) + .queryDirectoryIfNecessary(any(), any(), any(), any(), any(), any()); + } + + public void testContactsProviderReads_callerInAllowlist() { + // Insert raw contact through the primary clone provider + ContentValues inputContentValues = getSampleContentValues(); + long rawContactId = insertRawContactsThroughPrimaryProvider(inputContentValues); + Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, + rawContactId); + + // Mock call to parent profile contacts provider to return the correct result containing all + // contacts in the parent profile. + getCloneContactsProviderWithMockedCallToParent(uri); + + // Mock call to ensure the caller package is in the app-cloning allowlist + doReturn(true) + .when(mCloneContactsProvider).isAppAllowedToUseParentUsersContacts(any()); + + // Test clone contacts provider read with the uri of the contact added above + Cursor cursor = mCloneContactsProvider.query(uri, + null /* projection */, null /* queryArgs */, null /* cancellationSignal */); + + // Check that the call did not pass through to the local query and instead redirected to the + // parent provider + verify(mCloneContactsProvider, times(0)) + .queryDirectoryIfNecessary(any(), any(), any(), any(), any(), any()); + assertNotNull(cursor); + Cursor primaryProfileCursor = mActor.provider.query(uri, + null /* projection */, null /* queryArgs */, null /* cancellationSignal */); + assertNotNull(primaryProfileCursor); + assertRawContactsCursorEquals(primaryProfileCursor, cursor, + inputContentValues.getValues().keySet()); + } + + public void testQueryPrimaryProfileProvider_callingFromParentUser() { + ContentValues inputContentValues = getSampleContentValues(); + long rawContactId = insertRawContactsThroughPrimaryProvider(inputContentValues); + Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, + rawContactId); + + // Fetch primary contacts provider and call method to redirect to parent provider + final ContactsProvider2 primaryCP2 = (ContactsProvider2) getProvider(); + Cursor cursor = primaryCP2.queryParentProfileContactsProvider(uri, + null /* projection */, null /* selection */, null /* selectionArgs */, + null /* sortOrder */, null /* cancellationSignal */); + + // Assert that empty cursor is returned + assertNotNull(cursor); + assertEquals(0, cursor.getCount()); + } + + public void testQueryPrimaryProfileProvider_incorrectAuthority() { + ContentValues inputContentValues = getSampleContentValues(); + insertRawContactsThroughPrimaryProvider(inputContentValues); + + Assert.assertThrows(IllegalArgumentException.class, () -> + mCloneContactsProvider.queryParentProfileContactsProvider(CallLog.CONTENT_URI, + null /* projection */, null /* selection */, null /* selectionArgs */, + null /* sortOrder */, null /* cancellationSignal */)); + } + + public void testOpenAssetFileMultiVCard() throws IOException { + final VCardTestUriCreator contacts = createVCardTestContacts(); + + // Mock call to parent profile contacts provider to return the correct asset file + getCloneContactsProviderWithMockedOpenAssetFileCall(contacts.getCombinedUri()); + + // Mock call to ensure the caller package is in the app-cloning allowlist + doReturn(true) + .when(mCloneContactsProvider).isAppAllowedToUseParentUsersContacts(any()); + + final AssetFileDescriptor descriptor = + mCloneContactsProvider.openAssetFile(contacts.getCombinedUri(), "r"); + final FileInputStream inputStream = descriptor.createInputStream(); + String data = readToEnd(inputStream); + inputStream.close(); + descriptor.close(); + + // Ensure that the resulting VCard has both contacts + assertTrue(data.contains("N:Doe;John;;;")); + assertTrue(data.contains("N:Doh;Jane;;;")); + } + + public void testOpenAssetFileMultiVCard_callerNotInAllowlist() throws IOException { + final VCardTestUriCreator contacts = createVCardTestContacts(); + + // Mock call to parent profile contacts provider to return the correct asset file + getCloneContactsProviderWithMockedOpenAssetFileCall(contacts.getCombinedUri()); + + // Mock call to ensure the caller package is not in the app-cloning allowlist + doReturn(false) + .when(mCloneContactsProvider).isAppAllowedToUseParentUsersContacts(any()); + + final AssetFileDescriptor descriptor = + mCloneContactsProvider.openAssetFile(contacts.getCombinedUri(), "r"); + + // Check that the call passed through to the local call instead of redirecting to the + // parent provider + verify(mCloneContactsProvider, times(1)) + .openAssetFile(eq(contacts.getCombinedUri()), any()); + } + + public void testIsAppAllowedToUseParentUsersContacts_AppInAllowlistCacheEmpty() + throws InterruptedException { + String testPackageName = mCloneContactsActor.packageName; + int processUid = Binder.getCallingUid(); + doReturn(true) + .when(mCloneContactsProvider) + .doesPackageHaveALauncherActivity(eq(testPackageName), any()); + + SparseArray<ContactsProvider2.LaunchableCloneAppsCacheEntry> launchableCloneAppsCache = + mCloneContactsProvider.getLaunchableCloneAppsCacheForTesting(); + launchableCloneAppsCache.clear(); + boolean appAllowedToUseParentUsersContacts = + mCloneContactsProvider.isAppAllowedToUseParentUsersContacts(testPackageName); + assertTrue(appAllowedToUseParentUsersContacts); + + // Check that the cache has been updated with an entry corresponding to current app uid + ContactsProvider2.LaunchableCloneAppsCacheEntry cacheEntry = + launchableCloneAppsCache.get(processUid); + assertNotNull(cacheEntry); + assertEquals(1, launchableCloneAppsCache.size()); + assertTrue(cacheEntry.doesAppHaveLaunchableActivity); + } + + public void testIsAppAllowedToUseParentUsersContacts_AppNotInAllowlistCacheEmtpy() { + String testPackageName = mCloneContactsActor.packageName; + int processUid = Binder.getCallingUid(); + + SparseArray<ContactsProvider2.LaunchableCloneAppsCacheEntry> launchableCloneAppsCache = + mCloneContactsProvider.getLaunchableCloneAppsCacheForTesting(); + launchableCloneAppsCache.clear(); + assertFalse(mCloneContactsProvider.isAppAllowedToUseParentUsersContacts(testPackageName)); + + // Check that the cache has been updated with an entry corresponding to current app uid + ContactsProvider2.LaunchableCloneAppsCacheEntry cacheEntry = + launchableCloneAppsCache.get(processUid); + assertNotNull(cacheEntry); + assertEquals(1, launchableCloneAppsCache.size()); + assertFalse(cacheEntry.doesAppHaveLaunchableActivity); + } +} diff --git a/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java b/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java index fca00afc..a4165ce5 100644 --- a/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java +++ b/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java @@ -16,8 +16,6 @@ package com.android.providers.contacts; -import static com.android.providers.contacts.ContactsActor.PACKAGE_GREY; - import android.accounts.Account; import android.content.ContentValues; import android.content.Context; @@ -38,10 +36,15 @@ import android.test.mock.MockContentProvider; import android.test.suitebuilder.annotation.MediumTest; import android.util.Log; +import androidx.test.platform.app.InstrumentationRegistry; + import com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; import com.google.android.collect.Lists; +import java.util.Arrays; +import java.util.Set; + /** * Unit tests for {@link ContactDirectoryManager}. Run the test like this: * @@ -634,8 +637,17 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { return; } + try { + InstrumentationRegistry.getInstrumentation().getUiAutomation() + .executeShellCommand("am wait-for-broadcast-idle"); + Thread.sleep(1000); // wait for the system + } catch (Exception ignored) { } + // If installed, getDirectoryProviderPackages() should return it. - assertTrue(ContactDirectoryManager.getDirectoryProviderPackages(pm).contains(googleSync)); + Set<String> dirProviderPackages = ContactDirectoryManager.getDirectoryProviderPackages(pm); + assertTrue(googleSync + " package not found in the list of directory provider packages: " + + Arrays.toString(dirProviderPackages.toArray()), + dirProviderPackages.contains(googleSync)); } protected PackageInfo createProviderPackage(String packageName, String authority) { diff --git a/tests/src/com/android/providers/contacts/ContactsActor.java b/tests/src/com/android/providers/contacts/ContactsActor.java index e3c606e2..0d7d9b3b 100644 --- a/tests/src/com/android/providers/contacts/ContactsActor.java +++ b/tests/src/com/android/providers/contacts/ContactsActor.java @@ -16,6 +16,10 @@ package com.android.providers.contacts; +import static android.content.pm.UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT; +import static com.android.providers.contacts.ContactsActor.MockUserManager.CLONE_PROFILE_USER; +import static com.android.providers.contacts.ContactsActor.MockUserManager.PRIMARY_USER; + import static org.mockito.Mockito.when; import android.accounts.Account; @@ -25,6 +29,7 @@ import android.accounts.AccountManagerFuture; import android.accounts.AuthenticatorException; import android.accounts.OnAccountsUpdateListener; import android.accounts.OperationCanceledException; +import android.annotation.NonNull; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentUris; @@ -37,6 +42,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.pm.UserInfo; +import android.content.pm.UserProperties; import android.content.res.Configuration; import android.content.res.Resources; import android.database.Cursor; @@ -170,6 +176,8 @@ public class ContactsActor { 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); + public static final UserInfo CLONE_PROFILE_USER = createUserInfo("clone", 12, 0, + UserInfo.FLAG_PROFILE); /** "My" user. Set it to change the current user. */ public int myUser = DEFAULT_USER_ID; @@ -253,6 +261,18 @@ public class ContactsActor { public boolean isUserRunning(int userId) { return true; } + + @Override + public UserProperties getUserProperties(@NonNull UserHandle userHandle) { + if (CLONE_PROFILE_USER.getUserHandle().equals(userHandle)) { + return new UserProperties.Builder() + .setUseParentsContacts(true) + .setShowInLauncher(SHOW_IN_LAUNCHER_WITH_PARENT) + .setStartWithParent(true) + .build(); + } + return new UserProperties.Builder().build(); + } } private MockTelephonyManager mMockTelephonyManager; @@ -411,6 +431,15 @@ public class ContactsActor { } @Override + public UserHandle getUser() { + if (mockUserManager != null && + mockUserManager.getProcessUserId() == CLONE_PROFILE_USER.id) { + return CLONE_PROFILE_USER.getUserHandle(); + } + return PRIMARY_USER.getUserHandle(); + } + + @Override public void sendBroadcast(Intent intent, String receiverPermission) { // Ignore. } diff --git a/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java b/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java index a9420dda..62f17eab 100644 --- a/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java +++ b/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java @@ -24,6 +24,7 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.os.Binder; +import android.os.UserHandle; import android.test.mock.MockPackageManager; import java.util.ArrayList; @@ -149,4 +150,15 @@ public class ContactsMockPackageManager extends MockPackageManager { } return ret; } + + @Override + public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, ResolveInfoFlags flags, + UserHandle user) { + return new ArrayList<>(); + } + + @Override + public int getPackageUid(String packageName, int flags) throws NameNotFoundException { + return 123; + } } diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java index 09ea19fc..69ae0fb2 100644 --- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java +++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java @@ -8163,50 +8163,6 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test { assertEquals("default", helper.getProperty("existent1", "default")); } - private class VCardTestUriCreator { - private String mLookup1; - private String mLookup2; - - public VCardTestUriCreator(String lookup1, String lookup2) { - super(); - mLookup1 = lookup1; - mLookup2 = lookup2; - } - - public Uri getUri1() { - return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup1); - } - - public Uri getUri2() { - return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup2); - } - - public Uri getCombinedUri() { - return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, - Uri.encode(mLookup1 + ":" + mLookup2)); - } - } - - private VCardTestUriCreator createVCardTestContacts() { - final long rawContactId1 = RawContactUtil.createRawContact(mResolver, mAccount, - RawContacts.SOURCE_ID, "4:12"); - DataUtil.insertStructuredName(mResolver, rawContactId1, "John", "Doe"); - - final long rawContactId2 = RawContactUtil.createRawContact(mResolver, mAccount, - RawContacts.SOURCE_ID, "3:4%121"); - DataUtil.insertStructuredName(mResolver, rawContactId2, "Jane", "Doh"); - - final long contactId1 = queryContactId(rawContactId1); - final long contactId2 = queryContactId(rawContactId2); - final Uri contact1Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1); - final Uri contact2Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2); - final String lookup1 = - Uri.encode(Contacts.getLookupUri(mResolver, contact1Uri).getPathSegments().get(2)); - final String lookup2 = - Uri.encode(Contacts.getLookupUri(mResolver, contact2Uri).getPathSegments().get(2)); - return new VCardTestUriCreator(lookup1, lookup2); - } - public void testQueryMultiVCard() { // No need to create any contacts here, because the query for multiple vcards // does not go into the database at all @@ -9688,27 +9644,6 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test { return c; } - private String readToEnd(FileInputStream inputStream) { - try { - System.out.println("DECLARED INPUT STREAM LENGTH: " + inputStream.available()); - int ch; - StringBuilder stringBuilder = new StringBuilder(); - int index = 0; - while (true) { - ch = inputStream.read(); - System.out.println("READ CHARACTER: " + index + " " + ch); - if (ch == -1) { - break; - } - stringBuilder.append((char)ch); - index++; - } - return stringBuilder.toString(); - } catch (IOException e) { - return null; - } - } - private void assertQueryParameter(String uriString, String parameter, String expectedValue) { assertEquals(expectedValue, ContactsProvider2.getQueryParameter( Uri.parse(uriString), parameter)); @@ -9908,24 +9843,4 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test { } return false; } - - - /** - * Asserts the equality of two Uri objects, ignoring the order of the query parameters. - */ - public static void assertUriEquals(Uri expected, Uri actual) { - assertEquals(expected.getScheme(), actual.getScheme()); - assertEquals(expected.getAuthority(), actual.getAuthority()); - assertEquals(expected.getPath(), actual.getPath()); - assertEquals(expected.getFragment(), actual.getFragment()); - Set<String> expectedParameterNames = expected.getQueryParameterNames(); - Set<String> actualParameterNames = actual.getQueryParameterNames(); - assertEquals(expectedParameterNames.size(), actualParameterNames.size()); - assertTrue(expectedParameterNames.containsAll(actualParameterNames)); - for (String parameterName : expectedParameterNames) { - assertEquals(expected.getQueryParameter(parameterName), - actual.getQueryParameter(parameterName)); - } - - } } diff --git a/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java b/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java index c2ab74fc..ca8cb669 100644 --- a/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java +++ b/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java @@ -32,7 +32,8 @@ import java.util.Locale; public class SynchronousContactsProvider2 extends ContactsProvider2 { public static final String READ_ONLY_ACCOUNT_TYPE = "ro"; - private static Boolean sDataWiped = false; + private static final Object sDataWipedLock = new Object(); + private static boolean sDataWiped = false; private static ContactsDatabaseHelper sDbHelper; private Account mAccount; private boolean mNetworkNotified; @@ -93,7 +94,7 @@ public class SynchronousContactsProvider2 extends ContactsProvider2 { @Override public boolean onCreate() { boolean created = super.onCreate(); - synchronized (sDataWiped) { + synchronized (sDataWipedLock) { if (!sDataWiped) { sDataWiped = true; wipeData(); @@ -178,6 +179,11 @@ public class SynchronousContactsProvider2 extends ContactsProvider2 { } @Override + protected boolean isContactSharingEnabledForCloneProfile() { + return true; + } + + @Override public boolean isWritableAccountWithDataSet(String accountType) { return !READ_ONLY_ACCOUNT_TYPE.equals(accountType); } diff --git a/tests/src/com/android/providers/contacts/enterprise/EnterprisePolicyGuardTest.java b/tests/src/com/android/providers/contacts/enterprise/EnterprisePolicyGuardTest.java index 2e5241fb..5aedd8d0 100644 --- a/tests/src/com/android/providers/contacts/enterprise/EnterprisePolicyGuardTest.java +++ b/tests/src/com/android/providers/contacts/enterprise/EnterprisePolicyGuardTest.java @@ -17,6 +17,7 @@ package com.android.providers.contacts.enterprise; import android.app.admin.DevicePolicyManager; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.net.Uri; import android.os.UserHandle; @@ -31,6 +32,9 @@ import org.mockito.Matchers; import java.util.Arrays; import java.util.List; +import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -49,6 +53,7 @@ public class EnterprisePolicyGuardTest extends FixedAndroidTestCase { private static final String CONTACT_EMAIL = "david.green@android.com"; private static final String CONTACT_PHONE = "+1234567890"; private static final long DIRECTORY_ID = Directory.ENTERPRISE_DEFAULT; + private static final String CALLING_PACKAGE = "package"; private static final Uri URI_CONTACTS_ID_PHOTO = Uri.parse("content://com.android.contacts/contacts/" + CONTACT_ID + "/photo"); @@ -179,6 +184,32 @@ public class EnterprisePolicyGuardTest extends FixedAndroidTestCase { checkCrossProfile(guard, URI_CONTACTS_ID_PHOTO, false); checkCrossProfile(guard, URI_CONTACTS_ID_DISPLAY_PHOTO, false); checkCrossProfile(guard, URI_OTHER, false); + + // ManagedProfile is paused + context = getMockContext(true, true, false); + guard = new EnterprisePolicyGuardTestable(context, true); + checkCrossProfile(guard, appendRemoteDirectoryId(URI_PHONE_LOOKUP), false); + checkCrossProfile(guard, appendRemoteDirectoryId(URI_EMAILS_LOOKUP), false); + checkCrossProfile(guard, appendRemoteDirectoryId(URI_CONTACTS_FILTER), false); + checkCrossProfile(guard, appendRemoteDirectoryId(URI_PHONES_FILTER), false); + checkCrossProfile(guard, appendRemoteDirectoryId(URI_CALLABLES_FILTER), false); + checkCrossProfile(guard, appendRemoteDirectoryId(URI_EMAILS_FILTER), false); + checkCrossProfile(guard, URI_DIRECTORY_FILE, false); + + // Always allow uri with no directory support. + checkCrossProfile(guard, URI_DIRECTORIES, true); + checkCrossProfile(guard, URI_DIRECTORIES_ID, true); + checkCrossProfile(guard, URI_CONTACTS_ID_PHOTO, true); + checkCrossProfile(guard, URI_CONTACTS_ID_DISPLAY_PHOTO, true); + checkCrossProfile(guard, URI_OTHER, false); + + // Always allow uri with no remote directory id. + checkCrossProfile(guard, URI_PHONE_LOOKUP, true); + checkCrossProfile(guard, URI_EMAILS_LOOKUP, true); + checkCrossProfile(guard, URI_CONTACTS_FILTER, true); + checkCrossProfile(guard, URI_PHONES_FILTER, true); + checkCrossProfile(guard, URI_CALLABLES_FILTER, true); + checkCrossProfile(guard, URI_EMAILS_FILTER, true); } public void testCrossProfile_userSettingOff() { @@ -210,6 +241,7 @@ public class EnterprisePolicyGuardTest extends FixedAndroidTestCase { checkCrossProfile(guard, URI_EMAILS_FILTER, true); } + private static Uri appendRemoteDirectoryId(Uri uri) { return appendDirectoryId(uri, REMOTE_DIRECTORY_ID); } @@ -231,13 +263,13 @@ public class EnterprisePolicyGuardTest extends FixedAndroidTestCase { } } - private static void checkCrossProfile(EnterprisePolicyGuard guard, Uri uri, boolean expected) { + private void checkCrossProfile(EnterprisePolicyGuard guard, Uri uri, boolean expected) { if (expected) { assertTrue("Expected true but got false for uri: " + uri, - guard.isCrossProfileAllowed(uri)); + guard.isCrossProfileAllowed(uri, CALLING_PACKAGE)); } else { assertFalse("Expected false but got true for uri: " + uri, - guard.isCrossProfileAllowed(uri)); + guard.isCrossProfileAllowed(uri, CALLING_PACKAGE)); } } @@ -256,11 +288,16 @@ public class EnterprisePolicyGuardTest extends FixedAndroidTestCase { private Context getMockContext(boolean isCallerIdEnabled, boolean isContactsSearchEnabled) { + return getMockContext(isCallerIdEnabled, isContactsSearchEnabled, true); + } + + private Context getMockContext(boolean isCallerIdEnabled, boolean isContactsSearchEnabled, + boolean isManagedProfileEnabled) { DevicePolicyManager mockDpm = mock(DevicePolicyManager.class); - when(mockDpm.getCrossProfileCallerIdDisabled(Matchers.<UserHandle>any())) - .thenReturn(!isCallerIdEnabled); - when(mockDpm.getCrossProfileContactsSearchDisabled(Matchers.<UserHandle>any())) - .thenReturn(!isContactsSearchEnabled); + when(mockDpm.hasManagedProfileCallerIdAccess(Matchers.any(),Matchers.any())) + .thenReturn(isCallerIdEnabled); + when(mockDpm.hasManagedProfileContactsAccess(Matchers.any(),Matchers.any())) + .thenReturn(isContactsSearchEnabled); List<UserInfo> userInfos = MANAGED_USERINFO_LIST; UserManager mockUm = mock(UserManager.class); @@ -268,8 +305,14 @@ public class EnterprisePolicyGuardTest extends FixedAndroidTestCase { when(mockUm.getUsers()).thenReturn(userInfos); when(mockUm.getProfiles(Matchers.anyInt())).thenReturn(userInfos); when(mockUm.getProfileParent(WORK_USER_ID)).thenReturn(CURRENT_USER_INFO); + when(mockUm.isQuietModeEnabled(UserHandle.of(WORK_USER_ID))) + .thenReturn(!isManagedProfileEnabled); - Context mockContext = new TestMockContext(getContext(), mockDpm, mockUm); + PackageManager mockPm = mock(PackageManager.class); + when(mockPm.checkPermission(INTERACT_ACROSS_USERS, CALLING_PACKAGE)) + .thenReturn(PERMISSION_GRANTED); + + Context mockContext = new TestMockContext(getContext(), mockDpm, mockUm, mockPm); return mockContext; } @@ -278,11 +321,19 @@ public class EnterprisePolicyGuardTest extends FixedAndroidTestCase { private Context mRealContext; private DevicePolicyManager mDpm; private UserManager mUm; + private PackageManager mPm; - public TestMockContext(Context realContext, DevicePolicyManager dpm, UserManager um) { + public TestMockContext( + Context realContext, DevicePolicyManager dpm, UserManager um, PackageManager pm) { mRealContext = realContext; mDpm = dpm; mUm = um; + mPm = pm; + } + + @Override + public PackageManager getPackageManager() { + return mPm; } public Object getSystemService(String name) { diff --git a/tests/src/com/android/providers/contacts/util/UserUtilsTest.java b/tests/src/com/android/providers/contacts/util/UserUtilsTest.java index 93613cf5..c672697a 100644 --- a/tests/src/com/android/providers/contacts/util/UserUtilsTest.java +++ b/tests/src/com/android/providers/contacts/util/UserUtilsTest.java @@ -18,6 +18,7 @@ package com.android.providers.contacts.util; import static com.android.providers.contacts.ContactsActor.PACKAGE_GREY; import android.content.Context; +import android.os.UserHandle; import android.provider.ContactsContract; import android.test.suitebuilder.annotation.SmallTest; @@ -77,5 +78,82 @@ public class UserUtilsTest extends FixedAndroidTestCase { um.myUser = MockUserManager.SECONDARY_USER.id; assertEquals(-1, UserUtils.getCorpUserId(c)); + + // Primary + clone + corp + um.setUsers(MockUserManager.PRIMARY_USER, MockUserManager.CLONE_PROFILE_USER, + MockUserManager.CORP_USER); + + um.myUser = MockUserManager.PRIMARY_USER.id; + assertEquals(MockUserManager.CORP_USER.id, UserUtils.getCorpUserId(c)); + + um.myUser = MockUserManager.CLONE_PROFILE_USER.id; + assertEquals(-1, UserUtils.getCorpUserId(c)); + + um.myUser = MockUserManager.CORP_USER.id; + assertEquals(-1, UserUtils.getCorpUserId(c)); + } + + public void testShouldUseParentsContacts() { + final Context c = mActor.getProviderContext(); + final MockUserManager um = mActor.mockUserManager; + + um.setUsers(MockUserManager.PRIMARY_USER, MockUserManager.SECONDARY_USER, + MockUserManager.CLONE_PROFILE_USER, MockUserManager.CORP_USER); + + um.myUser = MockUserManager.PRIMARY_USER.id; + assertFalse(UserUtils.shouldUseParentsContacts(c)); + assertFalse(UserUtils.shouldUseParentsContacts(c, + MockUserManager.PRIMARY_USER.getUserHandle())); + + um.myUser = MockUserManager.SECONDARY_USER.id; + assertFalse(UserUtils.shouldUseParentsContacts(c)); + assertFalse(UserUtils.shouldUseParentsContacts(c, + MockUserManager.SECONDARY_USER.getUserHandle())); + + um.myUser = MockUserManager.CORP_USER.id; + assertFalse(UserUtils.shouldUseParentsContacts(c)); + assertFalse(UserUtils.shouldUseParentsContacts(c, + MockUserManager.CORP_USER.getUserHandle())); + + um.myUser = MockUserManager.CLONE_PROFILE_USER.id; + assertTrue(UserUtils.shouldUseParentsContacts(c)); + assertTrue(UserUtils.shouldUseParentsContacts(c, + MockUserManager.CLONE_PROFILE_USER.getUserHandle())); + + } + + public void testIsParentUser() { + final Context c = mActor.getProviderContext(); + final MockUserManager um = mActor.mockUserManager; + um.setUsers(MockUserManager.PRIMARY_USER, MockUserManager.SECONDARY_USER, + MockUserManager.CLONE_PROFILE_USER, MockUserManager.CORP_USER); + + UserHandle primaryProfileUserHandle = MockUserManager.PRIMARY_USER.getUserHandle(); + UserHandle cloneUserHandle = MockUserManager.CLONE_PROFILE_USER.getUserHandle(); + UserHandle corpUserHandle = MockUserManager.CORP_USER.getUserHandle(); + + assertTrue(UserUtils.isParentUser(c, primaryProfileUserHandle, cloneUserHandle)); + assertTrue(UserUtils.isParentUser(c, primaryProfileUserHandle, corpUserHandle)); + assertFalse(UserUtils.isParentUser(c, primaryProfileUserHandle, primaryProfileUserHandle)); + assertFalse(UserUtils.isParentUser(c, cloneUserHandle, cloneUserHandle)); + assertFalse(UserUtils.isParentUser(c, cloneUserHandle, primaryProfileUserHandle)); + assertFalse(UserUtils.isParentUser(c, corpUserHandle, primaryProfileUserHandle)); + } + + public void testGetProfileParent() { + final Context c = mActor.getProviderContext(); + final MockUserManager um = mActor.mockUserManager; + + um.setUsers(MockUserManager.PRIMARY_USER, MockUserManager.SECONDARY_USER, + MockUserManager.CLONE_PROFILE_USER, MockUserManager.CORP_USER); + + um.myUser = MockUserManager.PRIMARY_USER.id; + assertNull(UserUtils.getProfileParentUser(c)); + + um.myUser = MockUserManager.CLONE_PROFILE_USER.id; + assertEquals(MockUserManager.PRIMARY_USER, UserUtils.getProfileParentUser(c)); + + um.myUser = MockUserManager.CORP_USER.id; + assertEquals(MockUserManager.PRIMARY_USER, UserUtils.getProfileParentUser(c)); } } |