Loading core/java/android/provider/ContactsContract.java +23 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; /** * <p> Loading Loading @@ -2210,6 +2211,28 @@ public final class ContactsContract { public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) { return openContactPhotoInputStream(cr, contactUri, false); } /** * Creates and returns a corp lookup URI from the given enterprise lookup URI by removing * {@link #ENTERPRISE_CONTACT_LOOKUP_PREFIX} from the key. Returns {@code null} if the given * URI is not an enterprise lookup URI. * * @hide */ @Nullable public static Uri createCorpLookupUriFromEnterpriseLookupUri( @NonNull Uri enterpriseLookupUri) { final List<String> pathSegments = enterpriseLookupUri.getPathSegments(); if (pathSegments == null || pathSegments.size() <= 2) { return null; } final String key = pathSegments.get(2); if (TextUtils.isEmpty(key) || !key.startsWith(ENTERPRISE_CONTACT_LOOKUP_PREFIX)) { return null; } final String actualKey = key.substring(ENTERPRISE_CONTACT_LOOKUP_PREFIX.length()); return Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, actualKey); } } /** Loading services/core/java/com/android/server/notification/ValidateNotificationPeople.java +45 −10 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.notification; import android.annotation.Nullable; import android.app.Notification; import android.app.Person; import android.content.ContentProvider; import android.content.Context; import android.content.pm.PackageManager; import android.database.ContentObserver; Loading @@ -28,6 +29,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import android.provider.Settings; Loading @@ -38,6 +40,8 @@ import android.util.Log; import android.util.LruCache; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import libcore.util.EmptyArray; import java.util.ArrayList; Loading Loading @@ -392,27 +396,58 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return searchContacts(context, numberUri); } private LookupResult searchContacts(Context context, Uri lookupUri) { @VisibleForTesting LookupResult searchContacts(Context context, Uri lookupUri) { LookupResult lookupResult = new LookupResult(); Cursor c = null; try { c = context.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null); final Uri corpLookupUri = ContactsContract.Contacts.createCorpLookupUriFromEnterpriseLookupUri(lookupUri); if (corpLookupUri == null) { addContacts(lookupResult, context, lookupUri); } else { addWorkContacts(lookupResult, context, corpLookupUri); } return lookupResult; } private void addWorkContacts(LookupResult lookupResult, Context context, Uri corpLookupUri) { final int workUserId = findWorkUserId(context); if (workUserId == -1) { Slog.w(TAG, "Work profile user ID not found for work contact: " + corpLookupUri); return; } final Uri corpLookupUriWithUserId = ContentProvider.maybeAddUserId(corpLookupUri, workUserId); addContacts(lookupResult, context, corpLookupUriWithUserId); } /** Returns the user ID of the managed profile or -1 if none is found. */ private int findWorkUserId(Context context) { final UserManager userManager = context.getSystemService(UserManager.class); final int[] profileIds = userManager.getProfileIds(context.getUserId(), /* enabledOnly= */ true); for (int profileId : profileIds) { if (userManager.isManagedProfile(profileId)) { return profileId; } } return -1; } /** Modifies the given lookup result to add contacts found at the given URI. */ private void addContacts(LookupResult lookupResult, Context context, Uri uri) { try (Cursor c = context.getContentResolver().query( uri, LOOKUP_PROJECTION, null, null, null)) { if (c == null) { Slog.w(TAG, "Null cursor from contacts query."); return lookupResult; return; } while (c.moveToNext()) { lookupResult.mergeContact(c); } } catch (Throwable t) { Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t); } finally { if (c != null) { c.close(); } } return lookupResult; } private static class LookupResult { private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr Loading services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java +71 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,23 @@ package com.android.server.notification; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; import android.app.Person; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.os.UserManager; import android.provider.ContactsContract; import android.test.suitebuilder.annotation.SmallTest; import android.text.SpannableString; Loading @@ -30,6 +42,7 @@ import com.android.server.UiServiceTestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -169,6 +182,64 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { assertStringArrayEquals("testPeopleArrayList", expected, result); } @Test public void testSearchContacts_workContact_queriesWorkContactProvider() throws Exception { final int personalUserId = 0; final int workUserId = 12; final int contactId = 12345; final Context mockContext = mock(Context.class); when(mockContext.getUserId()).thenReturn(personalUserId); final UserManager mockUserManager = mock(UserManager.class); when(mockContext.getSystemService(UserManager.class)).thenReturn(mockUserManager); when(mockUserManager.getProfileIds(personalUserId, /* enabledOnly= */ true)) .thenReturn(new int[] {personalUserId, workUserId}); when(mockUserManager.isManagedProfile(workUserId)).thenReturn(true); final ContentResolver mockContentResolver = mock(ContentResolver.class); when(mockContext.getContentResolver()).thenReturn(mockContentResolver); final Uri lookupUri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_LOOKUP_URI, ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX + contactId); new ValidateNotificationPeople().searchContacts(mockContext, lookupUri); ArgumentCaptor<Uri> queryUri = ArgumentCaptor.forClass(Uri.class); verify(mockContentResolver).query( queryUri.capture(), any(), /* selection= */ isNull(), /* selectionArgs= */ isNull(), /* sortOrder= */ isNull()); assertEquals(workUserId, ContentProvider.getUserIdFromUri(queryUri.getValue())); } @Test public void testSearchContacts_personalContact_queriesPersonalContactProvider() throws Exception { final int personalUserId = 0; final int workUserId = 12; final int contactId = 12345; final Context mockContext = mock(Context.class); when(mockContext.getUserId()).thenReturn(personalUserId); final UserManager mockUserManager = mock(UserManager.class); when(mockContext.getSystemService(UserManager.class)).thenReturn(mockUserManager); final ContentResolver mockContentResolver = mock(ContentResolver.class); when(mockContext.getContentResolver()).thenReturn(mockContentResolver); final Uri lookupUri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_LOOKUP_URI, String.valueOf(contactId)); new ValidateNotificationPeople().searchContacts(mockContext, lookupUri); ArgumentCaptor<Uri> queryUri = ArgumentCaptor.forClass(Uri.class); verify(mockContentResolver).query( queryUri.capture(), any(), /* selection= */ isNull(), /* selectionArgs= */ isNull(), /* sortOrder= */ isNull()); assertFalse(ContentProvider.uriHasUserId(queryUri.getValue())); } private void assertStringArrayEquals(String message, String[] expected, String[] result) { String expectedString = Arrays.toString(expected); String resultString = Arrays.toString(result); Loading Loading
core/java/android/provider/ContactsContract.java +23 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; /** * <p> Loading Loading @@ -2210,6 +2211,28 @@ public final class ContactsContract { public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) { return openContactPhotoInputStream(cr, contactUri, false); } /** * Creates and returns a corp lookup URI from the given enterprise lookup URI by removing * {@link #ENTERPRISE_CONTACT_LOOKUP_PREFIX} from the key. Returns {@code null} if the given * URI is not an enterprise lookup URI. * * @hide */ @Nullable public static Uri createCorpLookupUriFromEnterpriseLookupUri( @NonNull Uri enterpriseLookupUri) { final List<String> pathSegments = enterpriseLookupUri.getPathSegments(); if (pathSegments == null || pathSegments.size() <= 2) { return null; } final String key = pathSegments.get(2); if (TextUtils.isEmpty(key) || !key.startsWith(ENTERPRISE_CONTACT_LOOKUP_PREFIX)) { return null; } final String actualKey = key.substring(ENTERPRISE_CONTACT_LOOKUP_PREFIX.length()); return Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, actualKey); } } /** Loading
services/core/java/com/android/server/notification/ValidateNotificationPeople.java +45 −10 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.notification; import android.annotation.Nullable; import android.app.Notification; import android.app.Person; import android.content.ContentProvider; import android.content.Context; import android.content.pm.PackageManager; import android.database.ContentObserver; Loading @@ -28,6 +29,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import android.provider.Settings; Loading @@ -38,6 +40,8 @@ import android.util.Log; import android.util.LruCache; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import libcore.util.EmptyArray; import java.util.ArrayList; Loading Loading @@ -392,27 +396,58 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return searchContacts(context, numberUri); } private LookupResult searchContacts(Context context, Uri lookupUri) { @VisibleForTesting LookupResult searchContacts(Context context, Uri lookupUri) { LookupResult lookupResult = new LookupResult(); Cursor c = null; try { c = context.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null); final Uri corpLookupUri = ContactsContract.Contacts.createCorpLookupUriFromEnterpriseLookupUri(lookupUri); if (corpLookupUri == null) { addContacts(lookupResult, context, lookupUri); } else { addWorkContacts(lookupResult, context, corpLookupUri); } return lookupResult; } private void addWorkContacts(LookupResult lookupResult, Context context, Uri corpLookupUri) { final int workUserId = findWorkUserId(context); if (workUserId == -1) { Slog.w(TAG, "Work profile user ID not found for work contact: " + corpLookupUri); return; } final Uri corpLookupUriWithUserId = ContentProvider.maybeAddUserId(corpLookupUri, workUserId); addContacts(lookupResult, context, corpLookupUriWithUserId); } /** Returns the user ID of the managed profile or -1 if none is found. */ private int findWorkUserId(Context context) { final UserManager userManager = context.getSystemService(UserManager.class); final int[] profileIds = userManager.getProfileIds(context.getUserId(), /* enabledOnly= */ true); for (int profileId : profileIds) { if (userManager.isManagedProfile(profileId)) { return profileId; } } return -1; } /** Modifies the given lookup result to add contacts found at the given URI. */ private void addContacts(LookupResult lookupResult, Context context, Uri uri) { try (Cursor c = context.getContentResolver().query( uri, LOOKUP_PROJECTION, null, null, null)) { if (c == null) { Slog.w(TAG, "Null cursor from contacts query."); return lookupResult; return; } while (c.moveToNext()) { lookupResult.mergeContact(c); } } catch (Throwable t) { Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t); } finally { if (c != null) { c.close(); } } return lookupResult; } private static class LookupResult { private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr Loading
services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java +71 −0 Original line number Diff line number Diff line Loading @@ -16,11 +16,23 @@ package com.android.server.notification; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; import android.app.Person; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.os.UserManager; import android.provider.ContactsContract; import android.test.suitebuilder.annotation.SmallTest; import android.text.SpannableString; Loading @@ -30,6 +42,7 @@ import com.android.server.UiServiceTestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -169,6 +182,64 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase { assertStringArrayEquals("testPeopleArrayList", expected, result); } @Test public void testSearchContacts_workContact_queriesWorkContactProvider() throws Exception { final int personalUserId = 0; final int workUserId = 12; final int contactId = 12345; final Context mockContext = mock(Context.class); when(mockContext.getUserId()).thenReturn(personalUserId); final UserManager mockUserManager = mock(UserManager.class); when(mockContext.getSystemService(UserManager.class)).thenReturn(mockUserManager); when(mockUserManager.getProfileIds(personalUserId, /* enabledOnly= */ true)) .thenReturn(new int[] {personalUserId, workUserId}); when(mockUserManager.isManagedProfile(workUserId)).thenReturn(true); final ContentResolver mockContentResolver = mock(ContentResolver.class); when(mockContext.getContentResolver()).thenReturn(mockContentResolver); final Uri lookupUri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_LOOKUP_URI, ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX + contactId); new ValidateNotificationPeople().searchContacts(mockContext, lookupUri); ArgumentCaptor<Uri> queryUri = ArgumentCaptor.forClass(Uri.class); verify(mockContentResolver).query( queryUri.capture(), any(), /* selection= */ isNull(), /* selectionArgs= */ isNull(), /* sortOrder= */ isNull()); assertEquals(workUserId, ContentProvider.getUserIdFromUri(queryUri.getValue())); } @Test public void testSearchContacts_personalContact_queriesPersonalContactProvider() throws Exception { final int personalUserId = 0; final int workUserId = 12; final int contactId = 12345; final Context mockContext = mock(Context.class); when(mockContext.getUserId()).thenReturn(personalUserId); final UserManager mockUserManager = mock(UserManager.class); when(mockContext.getSystemService(UserManager.class)).thenReturn(mockUserManager); final ContentResolver mockContentResolver = mock(ContentResolver.class); when(mockContext.getContentResolver()).thenReturn(mockContentResolver); final Uri lookupUri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_LOOKUP_URI, String.valueOf(contactId)); new ValidateNotificationPeople().searchContacts(mockContext, lookupUri); ArgumentCaptor<Uri> queryUri = ArgumentCaptor.forClass(Uri.class); verify(mockContentResolver).query( queryUri.capture(), any(), /* selection= */ isNull(), /* selectionArgs= */ isNull(), /* sortOrder= */ isNull()); assertFalse(ContentProvider.uriHasUserId(queryUri.getValue())); } private void assertStringArrayEquals(String message, String[] expected, String[] result) { String expectedString = Arrays.toString(expected); String resultString = Arrays.toString(result); Loading