Merge "Better Support for profiles in "People that can interrupt"" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
c7be2f126e
@@ -71,7 +71,9 @@ public class UserAdapter extends BaseAdapter {
|
||||
&& userInfo.isPrivateProfile())) {
|
||||
mIcon = context.getPackageManager().getUserBadgeForDensityNoBackground(
|
||||
userHandle, /* density= */ 0);
|
||||
if (mIcon != null) {
|
||||
mIcon.setTint(tintColor);
|
||||
}
|
||||
} else {
|
||||
mIcon = UserIcons.getDefaultUserIconInColor(context.getResources(), tintColor);
|
||||
}
|
||||
|
@@ -18,13 +18,17 @@ package com.android.settings.notification.modes;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.INotificationManager;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.service.notification.ConversationChannelWrapper;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -39,6 +43,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Class used for Settings-system_server interactions that are not <em>directly</em> related to
|
||||
@@ -54,6 +59,7 @@ class ZenHelperBackend {
|
||||
|
||||
private final Context mContext;
|
||||
private final INotificationManager mInm;
|
||||
private final UserManager mUserManager;
|
||||
|
||||
static ZenHelperBackend getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
@@ -66,6 +72,7 @@ class ZenHelperBackend {
|
||||
mContext = context;
|
||||
mInm = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||
mUserManager = context.getSystemService(UserManager.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,10 +88,12 @@ class ZenHelperBackend {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns all conversation channels for profiles of the current user. */
|
||||
ImmutableList<ConversationChannelWrapper> getAllConversations() {
|
||||
return getConversations(false);
|
||||
}
|
||||
|
||||
/** Returns all important (priority) conversation channels for profiles of the current user. */
|
||||
ImmutableList<ConversationChannelWrapper> getImportantConversations() {
|
||||
return getConversations(true);
|
||||
}
|
||||
@@ -97,7 +106,9 @@ class ZenHelperBackend {
|
||||
onlyImportant);
|
||||
if (parceledList != null) {
|
||||
for (ConversationChannelWrapper conversation : parceledList.getList()) {
|
||||
if (!conversation.getNotificationChannel().isDemoted()) {
|
||||
if (conversation.getShortcutInfo() != null
|
||||
&& conversation.getNotificationChannel() != null
|
||||
&& !conversation.getNotificationChannel().isDemoted()) {
|
||||
list.add(conversation);
|
||||
}
|
||||
}
|
||||
@@ -109,39 +120,53 @@ class ZenHelperBackend {
|
||||
}
|
||||
}
|
||||
|
||||
record Contact(long id, @Nullable String displayName, @Nullable Uri photoUri) { }
|
||||
record Contact(UserHandle user, long contactId, @Nullable String displayName,
|
||||
@Nullable Uri photoUri) { }
|
||||
|
||||
/** Returns all contacts for profiles of the current user. */
|
||||
ImmutableList<Contact> getAllContacts() {
|
||||
try (Cursor cursor = queryAllContactsData()) {
|
||||
return getContactsFromCursor(cursor);
|
||||
}
|
||||
return getContactsForUserProfiles(this::queryAllContactsData);
|
||||
}
|
||||
|
||||
/** Returns all starred contacts for profiles of the current user. */
|
||||
ImmutableList<Contact> getStarredContacts() {
|
||||
try (Cursor cursor = queryStarredContactsData()) {
|
||||
return getContactsFromCursor(cursor);
|
||||
}
|
||||
return getContactsForUserProfiles(this::queryStarredContactsData);
|
||||
}
|
||||
|
||||
private ImmutableList<Contact> getContactsFromCursor(Cursor cursor) {
|
||||
ImmutableList.Builder<Contact> list = new ImmutableList.Builder<>();
|
||||
private ImmutableList<Contact> getContactsForUserProfiles(
|
||||
Function<UserHandle, Cursor> userQuery) {
|
||||
ImmutableList.Builder<Contact> contacts = new ImmutableList.Builder<>();
|
||||
for (UserHandle user : mUserManager.getAllProfiles()) {
|
||||
try (Cursor cursor = userQuery.apply(user)) {
|
||||
loadContactsFromCursor(user, cursor, contacts);
|
||||
}
|
||||
}
|
||||
return contacts.build();
|
||||
}
|
||||
|
||||
private void loadContactsFromCursor(UserHandle user, Cursor cursor,
|
||||
ImmutableList.Builder<Contact> contactsListBuilder) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
long id = cursor.getLong(0);
|
||||
String name = Strings.emptyToNull(cursor.getString(1));
|
||||
String photoUriStr = cursor.getString(2);
|
||||
Uri photoUri = !Strings.isNullOrEmpty(photoUriStr) ? Uri.parse(photoUriStr) : null;
|
||||
list.add(new Contact(id, name, photoUri));
|
||||
contactsListBuilder.add(new Contact(user, id, name,
|
||||
ContentProvider.maybeAddUserId(photoUri, user.getIdentifier())));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
return list.build();
|
||||
}
|
||||
|
||||
int getAllContactsCount() {
|
||||
try (Cursor cursor = queryAllContactsData()) {
|
||||
return cursor != null ? cursor.getCount() : 0;
|
||||
int count = 0;
|
||||
for (UserHandle user : mUserManager.getEnabledProfiles()) {
|
||||
try (Cursor cursor = queryAllContactsData(user)) {
|
||||
count += (cursor != null ? cursor.getCount() : 0);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static final String[] CONTACTS_PROJECTION = new String[] {
|
||||
ContactsContract.Contacts._ID,
|
||||
@@ -149,17 +174,17 @@ class ZenHelperBackend {
|
||||
ContactsContract.Contacts.PHOTO_THUMBNAIL_URI
|
||||
};
|
||||
|
||||
private Cursor queryStarredContactsData() {
|
||||
private Cursor queryStarredContactsData(UserHandle user) {
|
||||
return mContext.getContentResolver().query(
|
||||
ContactsContract.Contacts.CONTENT_URI,
|
||||
ContentProvider.maybeAddUserId(Contacts.CONTENT_URI, user.getIdentifier()),
|
||||
CONTACTS_PROJECTION,
|
||||
/* selection= */ ContactsContract.Data.STARRED + "=1", /* selectionArgs= */ null,
|
||||
/* sortOrder= */ ContactsContract.Contacts.DISPLAY_NAME_PRIMARY);
|
||||
}
|
||||
|
||||
private Cursor queryAllContactsData() {
|
||||
private Cursor queryAllContactsData(UserHandle user) {
|
||||
return mContext.getContentResolver().query(
|
||||
ContactsContract.Contacts.CONTENT_URI,
|
||||
ContentProvider.maybeAddUserId(Contacts.CONTENT_URI, user.getIdentifier()),
|
||||
CONTACTS_PROJECTION,
|
||||
/* selection= */ null, /* selectionArgs= */ null,
|
||||
/* sortOrder= */ ContactsContract.Contacts.DISPLAY_NAME_PRIMARY);
|
||||
|
@@ -28,11 +28,14 @@ import static android.service.notification.ZenPolicy.PEOPLE_TYPE_UNSET;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.icu.text.MessageFormat;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Contacts;
|
||||
import android.service.notification.ZenPolicy;
|
||||
import android.view.View;
|
||||
@@ -46,6 +49,7 @@ import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.dashboard.profileselector.ProfileSelectDialog;
|
||||
import com.android.settings.notification.app.ConversationListSettings;
|
||||
import com.android.settingslib.notification.modes.ZenMode;
|
||||
import com.android.settingslib.notification.modes.ZenModesBackend;
|
||||
@@ -55,6 +59,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -87,16 +92,18 @@ class ZenModePrioritySendersPreferenceController
|
||||
private static final Intent STARRED_CONTACTS_INTENT =
|
||||
new Intent(Contacts.Intents.UI.LIST_STARRED_ACTION)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
private static final Intent FALLBACK_INTENT = new Intent(Intent.ACTION_MAIN)
|
||||
private static final Intent FALLBACK_CONTACTS_INTENT = new Intent(Intent.ACTION_MAIN)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
|
||||
private final ZenHelperBackend mHelperBackend;
|
||||
private final UserManager mUserManager;
|
||||
private final PackageManager mPackageManager;
|
||||
private PreferenceCategory mPreferenceCategory;
|
||||
private final LinkedHashMap<String, SelectorWithWidgetPreference> mOptions =
|
||||
new LinkedHashMap<>();
|
||||
|
||||
private final ZenModeSummaryHelper mZenModeSummaryHelper;
|
||||
@Nullable private Dialog mProfileSelectDialog;
|
||||
|
||||
public ZenModePrioritySendersPreferenceController(Context context, String key,
|
||||
boolean isMessages, ZenModesBackend backend, ZenHelperBackend helperBackend) {
|
||||
@@ -107,11 +114,12 @@ class ZenModePrioritySendersPreferenceController
|
||||
String contactsPackage = context.getString(R.string.config_contacts_package_name);
|
||||
ALL_CONTACTS_INTENT.setPackage(contactsPackage);
|
||||
STARRED_CONTACTS_INTENT.setPackage(contactsPackage);
|
||||
FALLBACK_INTENT.setPackage(contactsPackage);
|
||||
FALLBACK_CONTACTS_INTENT.setPackage(contactsPackage);
|
||||
|
||||
mUserManager = mContext.getSystemService(UserManager.class);
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
if (!FALLBACK_INTENT.hasCategory(Intent.CATEGORY_APP_CONTACTS)) {
|
||||
FALLBACK_INTENT.addCategory(Intent.CATEGORY_APP_CONTACTS);
|
||||
if (!FALLBACK_CONTACTS_INTENT.hasCategory(Intent.CATEGORY_APP_CONTACTS)) {
|
||||
FALLBACK_CONTACTS_INTENT.addCategory(Intent.CATEGORY_APP_CONTACTS);
|
||||
}
|
||||
mZenModeSummaryHelper = new ZenModeSummaryHelper(mContext, mHelperBackend);
|
||||
}
|
||||
@@ -270,32 +278,48 @@ class ZenModePrioritySendersPreferenceController
|
||||
}
|
||||
|
||||
return v -> {
|
||||
if (KEY_STARRED.equals(key)
|
||||
&& STARRED_CONTACTS_INTENT.resolveActivity(mPackageManager) != null) {
|
||||
mContext.startActivity(STARRED_CONTACTS_INTENT);
|
||||
} else if (KEY_CONTACTS.equals(key)
|
||||
&& ALL_CONTACTS_INTENT.resolveActivity(mPackageManager) != null) {
|
||||
mContext.startActivity(ALL_CONTACTS_INTENT);
|
||||
if (KEY_STARRED.equals(key)) {
|
||||
startContactsActivity(STARRED_CONTACTS_INTENT);
|
||||
} else if (KEY_CONTACTS.equals(key)) {
|
||||
startContactsActivity(ALL_CONTACTS_INTENT);
|
||||
} else if (KEY_ANY_CONVERSATIONS.equals(key)
|
||||
|| KEY_IMPORTANT_CONVERSATIONS.equals(key)) {
|
||||
new SubSettingLauncher(mContext)
|
||||
.setDestination(ConversationListSettings.class.getName())
|
||||
.setSourceMetricsCategory(SettingsEnums.DND_MESSAGES)
|
||||
.launch();
|
||||
} else {
|
||||
mContext.startActivity(FALLBACK_INTENT);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void startContactsActivity(Intent preferredIntent) {
|
||||
Intent intent = preferredIntent.resolveActivity(mPackageManager) != null
|
||||
? preferredIntent : FALLBACK_CONTACTS_INTENT;
|
||||
|
||||
List<UserHandle> userProfiles = mUserManager.getEnabledProfiles();
|
||||
if (userProfiles.size() <= 1) {
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
|
||||
mProfileSelectDialog = ProfileSelectDialog.createDialog(mContext, userProfiles,
|
||||
position -> {
|
||||
mContext.startActivityAsUser(intent, userProfiles.get(position));
|
||||
if (mProfileSelectDialog != null) {
|
||||
mProfileSelectDialog.dismiss();
|
||||
mProfileSelectDialog = null;
|
||||
}
|
||||
});
|
||||
mProfileSelectDialog.show();
|
||||
}
|
||||
|
||||
private boolean isStarredIntentValid() {
|
||||
return STARRED_CONTACTS_INTENT.resolveActivity(mPackageManager) != null
|
||||
|| FALLBACK_INTENT.resolveActivity(mPackageManager) != null;
|
||||
|| FALLBACK_CONTACTS_INTENT.resolveActivity(mPackageManager) != null;
|
||||
}
|
||||
|
||||
private boolean isContactsIntentValid() {
|
||||
return ALL_CONTACTS_INTENT.resolveActivity(mPackageManager) != null
|
||||
|| FALLBACK_INTENT.resolveActivity(mPackageManager) != null;
|
||||
|| FALLBACK_CONTACTS_INTENT.resolveActivity(mPackageManager) != null;
|
||||
}
|
||||
|
||||
void updateSummaries() {
|
||||
|
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.settings.notification.modes;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.app.Flags;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.platform.test.annotations.EnableFlags;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
import android.provider.ContactsContract;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.settings.notification.modes.ZenHelperBackend.Contact;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@EnableFlags(Flags.FLAG_MODES_UI)
|
||||
public class ZenHelperBackendTest {
|
||||
@Rule
|
||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
|
||||
private Context mContext;
|
||||
private ZenHelperBackend mBackend;
|
||||
private HashMap<Integer, FakeContactsProvider> mContactsProviders = new HashMap<>();
|
||||
|
||||
private int mUserId;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.getApplication();
|
||||
mBackend = new ZenHelperBackend(mContext);
|
||||
|
||||
mUserId = mContext.getUserId();
|
||||
addContactsProvider(mUserId);
|
||||
}
|
||||
|
||||
private int addMainUserProfile() {
|
||||
UserInfo workProfile = new UserInfo(mUserId + 10, "Work Profile", 0);
|
||||
workProfile.userType = UserManager.USER_TYPE_PROFILE_MANAGED;
|
||||
UserManager userManager = mContext.getSystemService(UserManager.class);
|
||||
shadowOf(userManager).addProfile(mUserId, workProfile.id, workProfile);
|
||||
|
||||
addContactsProvider(workProfile.id);
|
||||
|
||||
return workProfile.id;
|
||||
}
|
||||
|
||||
private void addContactsProvider(int userId) {
|
||||
ProviderInfo providerInfo = new ProviderInfo();
|
||||
providerInfo.authority = String.format("%s@%s", userId, ContactsContract.AUTHORITY);
|
||||
mContactsProviders.put(userId, Robolectric.buildContentProvider(FakeContactsProvider.class)
|
||||
.create(providerInfo).get());
|
||||
}
|
||||
|
||||
private void addContact(int userId, String name, boolean starred) {
|
||||
mContactsProviders.get(userId).addContact(name, starred);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllContacts_singleProfile() {
|
||||
addContact(mUserId, "Huey", false);
|
||||
addContact(mUserId, "Dewey", true);
|
||||
addContact(mUserId, "Louie", false);
|
||||
|
||||
ImmutableList<Contact> allContacts = mBackend.getAllContacts();
|
||||
|
||||
assertThat(allContacts).containsExactly(
|
||||
new Contact(UserHandle.of(mUserId), 1, "Huey", null),
|
||||
new Contact(UserHandle.of(mUserId), 2, "Dewey", null),
|
||||
new Contact(UserHandle.of(mUserId), 3, "Louie", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllContacts_multipleProfiles() {
|
||||
int profileId = addMainUserProfile();
|
||||
addContact(mUserId, "Huey", false);
|
||||
addContact(mUserId, "Dewey", true);
|
||||
addContact(mUserId, "Louie", false);
|
||||
addContact(profileId, "Fry", false);
|
||||
addContact(profileId, "Bender", true);
|
||||
|
||||
ImmutableList<Contact> allContacts = mBackend.getAllContacts();
|
||||
|
||||
assertThat(allContacts).containsExactly(
|
||||
new Contact(UserHandle.of(mUserId), 1, "Huey", null),
|
||||
new Contact(UserHandle.of(mUserId), 2, "Dewey", null),
|
||||
new Contact(UserHandle.of(mUserId), 3, "Louie", null),
|
||||
new Contact(UserHandle.of(profileId), 1, "Fry", null),
|
||||
new Contact(UserHandle.of(profileId), 2, "Bender", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getStarredContacts_singleProfile() {
|
||||
addContact(mUserId, "Huey", false);
|
||||
addContact(mUserId, "Dewey", true);
|
||||
addContact(mUserId, "Louie", false);
|
||||
|
||||
ImmutableList<Contact> allContacts = mBackend.getStarredContacts();
|
||||
|
||||
assertThat(allContacts).containsExactly(
|
||||
new Contact(UserHandle.of(mUserId), 2, "Dewey", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getStarredContacts_multipleProfiles() {
|
||||
int profileId = addMainUserProfile();
|
||||
addContact(mUserId, "Huey", false);
|
||||
addContact(mUserId, "Dewey", true);
|
||||
addContact(mUserId, "Louie", false);
|
||||
addContact(profileId, "Fry", false);
|
||||
addContact(profileId, "Bender", true);
|
||||
|
||||
ImmutableList<Contact> allContacts = mBackend.getStarredContacts();
|
||||
|
||||
assertThat(allContacts).containsExactly(
|
||||
new Contact(UserHandle.of(mUserId), 2, "Dewey", null),
|
||||
new Contact(UserHandle.of(profileId), 2, "Bender", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllContactsCount_singleProfile() {
|
||||
addContact(mUserId, "Huey", false);
|
||||
addContact(mUserId, "Dewey", true);
|
||||
addContact(mUserId, "Louie", false);
|
||||
|
||||
assertThat(mBackend.getAllContactsCount()).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllContactsCount_multipleProfiles() {
|
||||
int profileId = addMainUserProfile();
|
||||
addContact(mUserId, "Huey", false);
|
||||
addContact(mUserId, "Dewey", true);
|
||||
addContact(mUserId, "Louie", false);
|
||||
addContact(profileId, "Fry", false);
|
||||
addContact(profileId, "Bender", true);
|
||||
|
||||
assertThat(mBackend.getAllContactsCount()).isEqualTo(5);
|
||||
}
|
||||
|
||||
private static class FakeContactsProvider extends ContentProvider {
|
||||
|
||||
private record ContactRow(int id, String name, boolean starred) {}
|
||||
|
||||
private final ArrayList<ContactRow> mContacts = new ArrayList<>();
|
||||
|
||||
FakeContactsProvider() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int addContact(String name, boolean starred) {
|
||||
mContacts.add(new ContactRow(mContacts.size() + 1, name, starred));
|
||||
return mContacts.size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
|
||||
@Nullable String selection, @Nullable String[] selectionArgs,
|
||||
@Nullable String sortOrder) {
|
||||
Uri baseUri = ContentProvider.getUriWithoutUserId(uri);
|
||||
if (!ContactsContract.Contacts.CONTENT_URI.equals(baseUri)) {
|
||||
throw new IllegalArgumentException("Unsupported uri for fake: " + uri);
|
||||
}
|
||||
|
||||
if (projection == null || !Iterables.elementsEqual(ImmutableList.copyOf(projection),
|
||||
ImmutableList.of(ContactsContract.Contacts._ID,
|
||||
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
|
||||
ContactsContract.Contacts.PHOTO_THUMBNAIL_URI))) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported projection for fake: " + Arrays.toString(projection));
|
||||
}
|
||||
|
||||
if (selection != null && !selection.equals(ContactsContract.Data.STARRED + "=1")) {
|
||||
throw new IllegalArgumentException("Unsupported selection for fake: " + selection);
|
||||
}
|
||||
boolean selectingStarred = selection != null; // Checked as only valid selection above
|
||||
|
||||
|
||||
MatrixCursor cursor = new MatrixCursor(projection);
|
||||
for (ContactRow contactRow : mContacts) {
|
||||
if (!selectingStarred || contactRow.starred) {
|
||||
cursor.addRow(ImmutableList.of(contactRow.id, contactRow.name, Uri.EMPTY));
|
||||
}
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getType(@NonNull Uri uri) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(@NonNull Uri uri, @Nullable String selection,
|
||||
@Nullable String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(@NonNull Uri uri, @Nullable ContentValues values,
|
||||
@Nullable String selection, @Nullable String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
@@ -43,6 +43,7 @@ import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.platform.test.annotations.EnableFlags;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
import android.service.notification.ConversationChannelWrapper;
|
||||
@@ -229,13 +230,13 @@ public final class ZenModePeopleLinkPreferenceControllerTest {
|
||||
|
||||
private void setUpContacts(Collection<Integer> allIds, Collection<Integer> starredIds) {
|
||||
when(mHelperBackend.getAllContacts()).thenReturn(ImmutableList.copyOf(
|
||||
allIds.stream()
|
||||
.map(id -> new Contact(id, "#" + id, Uri.parse("photo://" + id)))
|
||||
allIds.stream().map(id -> new Contact(UserHandle.SYSTEM, id, "#" + id,
|
||||
Uri.parse("photo://" + id)))
|
||||
.toList()));
|
||||
|
||||
when(mHelperBackend.getStarredContacts()).thenReturn(ImmutableList.copyOf(
|
||||
starredIds.stream()
|
||||
.map(id -> new Contact(id, "#" + id, Uri.parse("photo://" + id)))
|
||||
starredIds.stream().map(id -> new Contact(UserHandle.SYSTEM, id, "#" + id,
|
||||
Uri.parse("photo://" + id)))
|
||||
.toList()));
|
||||
}
|
||||
|
||||
@@ -253,6 +254,6 @@ public final class ZenModePeopleLinkPreferenceControllerTest {
|
||||
}
|
||||
|
||||
private static ColorDrawable photoOf(Contact contact) {
|
||||
return new ColorDrawable((int) contact.id());
|
||||
return new ColorDrawable((int) contact.contactId());
|
||||
}
|
||||
}
|
@@ -39,21 +39,41 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.Flags;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.platform.test.annotations.EnableFlags;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
import android.provider.Contacts;
|
||||
import android.service.notification.ZenPolicy;
|
||||
import android.service.notification.ZenPolicy.ConversationSenders;
|
||||
import android.service.notification.ZenPolicy.PeopleType;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.testing.EmptyFragmentActivity;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
import androidx.test.core.content.pm.PackageInfoBuilder;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.notification.modes.TestModeBuilder;
|
||||
import com.android.settingslib.notification.modes.ZenMode;
|
||||
import com.android.settingslib.notification.modes.ZenModesBackend;
|
||||
@@ -70,6 +90,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.shadows.ShadowDialog;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
@@ -84,7 +105,13 @@ public final class ZenModePrioritySendersPreferenceControllerTest {
|
||||
@Rule
|
||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<EmptyFragmentActivity> mActivityScenario =
|
||||
new ActivityScenarioRule<>(EmptyFragmentActivity.class);
|
||||
|
||||
private Context mContext;
|
||||
private Activity mActivity;
|
||||
private PackageManager mPackageManager;
|
||||
@Mock private ZenModesBackend mBackend;
|
||||
@Mock private ZenHelperBackend mHelperBackend;
|
||||
|
||||
@@ -97,6 +124,9 @@ public final class ZenModePrioritySendersPreferenceControllerTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
|
||||
mActivityScenario.getScenario().onActivity(activity -> mActivity = activity);
|
||||
mPackageManager = mContext.getPackageManager();
|
||||
|
||||
mMessagesController = new ZenModePrioritySendersPreferenceController(mContext, "messages",
|
||||
true, mBackend, mHelperBackend);
|
||||
@@ -114,8 +144,8 @@ public final class ZenModePrioritySendersPreferenceControllerTest {
|
||||
mPreferenceScreen.addPreference(mMessagesPrefCategory);
|
||||
|
||||
when(mHelperBackend.getStarredContacts()).thenReturn(ImmutableList.of());
|
||||
when(mHelperBackend.getAllContacts()).thenReturn(
|
||||
ImmutableList.of(new ZenHelperBackend.Contact(1, "The only contact", null)));
|
||||
when(mHelperBackend.getAllContacts()).thenReturn(ImmutableList.of(
|
||||
new ZenHelperBackend.Contact(UserHandle.SYSTEM, 1, "The only contact", null)));
|
||||
when(mHelperBackend.getAllContactsCount()).thenReturn(1);
|
||||
|
||||
when(mHelperBackend.getImportantConversations()).thenReturn(ImmutableList.of());
|
||||
@@ -1439,4 +1469,142 @@ public final class ZenModePrioritySendersPreferenceControllerTest {
|
||||
assertThat(captor.getValue().getPolicy().getPriorityCallSenders())
|
||||
.isEqualTo(PEOPLE_TYPE_NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_hasContactsApp_hasSettingsButton() {
|
||||
String contactsPackage = mContext.getString(R.string.config_contacts_package_name);
|
||||
setUpContactsApp(contactsPackage, /* withPreciseIntents= */ false);
|
||||
mCallsController.displayPreference(mPreferenceScreen);
|
||||
|
||||
SelectorWithWidgetPreference contactsPref = getBoundSelectorPreference(KEY_STARRED);
|
||||
|
||||
assertThat(((View) contactsPref.getExtraWidget().getParent()).getVisibility()).isEqualTo(
|
||||
View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void displayPreference_noContactsApp_noSettingsButton() {
|
||||
String contactsPackage = mContext.getString(R.string.config_contacts_package_name);
|
||||
shadowOf(mPackageManager).removePackage(contactsPackage);
|
||||
mCallsController.displayPreference(mPreferenceScreen);
|
||||
|
||||
SelectorWithWidgetPreference contactsPref = getBoundSelectorPreference(KEY_STARRED);
|
||||
|
||||
assertThat(((View) contactsPref.getExtraWidget().getParent()).getVisibility()).isEqualTo(
|
||||
View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contactsSettingsClick_usesBestIntent() {
|
||||
String contactsPackage = mContext.getString(R.string.config_contacts_package_name);
|
||||
setUpContactsApp(contactsPackage, /* withPreciseIntents= */ true);
|
||||
|
||||
mCallsController.displayPreference(mPreferenceScreen);
|
||||
mCallsController.updateZenMode(mCallsPrefCategory, TestModeBuilder.EXAMPLE);
|
||||
|
||||
SelectorWithWidgetPreference contactsPref = getBoundSelectorPreference(KEY_CONTACTS);
|
||||
contactsPref.getExtraWidget().performClick();
|
||||
|
||||
Intent nextActivity = shadowOf(mActivity).getNextStartedActivity();
|
||||
assertThat(nextActivity).isNotNull();
|
||||
assertThat(nextActivity.getPackage()).isEqualTo(contactsPackage);
|
||||
assertThat(nextActivity.getAction()).isEqualTo(Contacts.Intents.UI.LIST_DEFAULT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void starredContactsSettingsClick_usesBestIntent() {
|
||||
String contactsPackage = mContext.getString(R.string.config_contacts_package_name);
|
||||
setUpContactsApp(contactsPackage, /* withPreciseIntents= */ true);
|
||||
|
||||
mCallsController.displayPreference(mPreferenceScreen);
|
||||
mCallsController.updateZenMode(mCallsPrefCategory, TestModeBuilder.EXAMPLE);
|
||||
SelectorWithWidgetPreference contactsPref = getBoundSelectorPreference(KEY_STARRED);
|
||||
|
||||
contactsPref.getExtraWidget().performClick();
|
||||
|
||||
Intent nextActivity = shadowOf(mActivity).getNextStartedActivity();
|
||||
assertThat(nextActivity).isNotNull();
|
||||
assertThat(nextActivity.getPackage()).isEqualTo(contactsPackage);
|
||||
assertThat(nextActivity.getAction()).isEqualTo(Contacts.Intents.UI.LIST_STARRED_ACTION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contactsSettingsClick_usesFallbackIntent() {
|
||||
String contactsPackage = mContext.getString(R.string.config_contacts_package_name);
|
||||
setUpContactsApp(contactsPackage, /* withPreciseIntents= */ false);
|
||||
|
||||
mCallsController.displayPreference(mPreferenceScreen);
|
||||
mCallsController.updateZenMode(mCallsPrefCategory, TestModeBuilder.EXAMPLE);
|
||||
SelectorWithWidgetPreference contactsPref = getBoundSelectorPreference(KEY_CONTACTS);
|
||||
|
||||
contactsPref.getExtraWidget().performClick();
|
||||
|
||||
Intent nextActivity = shadowOf(mActivity).getNextStartedActivity();
|
||||
assertThat(nextActivity).isNotNull();
|
||||
assertThat(nextActivity.getPackage()).isEqualTo(contactsPackage);
|
||||
assertThat(nextActivity.getAction()).isEqualTo(Intent.ACTION_MAIN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contactsSettingsClick_multipleProfiles_showsProfileChooserDialog() {
|
||||
String contactsPackage = mContext.getString(R.string.config_contacts_package_name);
|
||||
setUpContactsApp(contactsPackage, /* withPreciseIntents= */ true);
|
||||
|
||||
UserInfo workProfile = new UserInfo(mContext.getUserId() + 10, "Work Profile", 0);
|
||||
workProfile.userType = UserManager.USER_TYPE_PROFILE_MANAGED;
|
||||
UserManager userManager = mContext.getSystemService(UserManager.class);
|
||||
shadowOf(userManager).addProfile(mContext.getUserId(), workProfile.id, workProfile);
|
||||
|
||||
mCallsController.displayPreference(mPreferenceScreen);
|
||||
mCallsController.updateZenMode(mCallsPrefCategory, TestModeBuilder.EXAMPLE);
|
||||
SelectorWithWidgetPreference contactsPref = getBoundSelectorPreference(KEY_CONTACTS);
|
||||
|
||||
contactsPref.getExtraWidget().performClick();
|
||||
|
||||
Dialog profileSelectDialog = ShadowDialog.getLatestDialog();
|
||||
assertThat(profileSelectDialog).isNotNull();
|
||||
TextView dialogTitle = profileSelectDialog.findViewById(android.R.id.title);
|
||||
assertThat(dialogTitle.getText().toString()).isEqualTo("Choose profile");
|
||||
}
|
||||
|
||||
private void setUpContactsApp(String contactsPackage, boolean withPreciseIntents) {
|
||||
ComponentName contactsActivity = new ComponentName(contactsPackage, "ContactsActivity");
|
||||
shadowOf(mPackageManager).installPackage(
|
||||
PackageInfoBuilder.newBuilder()
|
||||
.setPackageName(contactsPackage)
|
||||
.build());
|
||||
shadowOf(mPackageManager).addActivityIfNotPresent(contactsActivity);
|
||||
|
||||
// Fallback / default intent filter.
|
||||
IntentFilter mainFilter = new IntentFilter(Intent.ACTION_MAIN);
|
||||
mainFilter.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
mainFilter.addCategory(Intent.CATEGORY_APP_CONTACTS);
|
||||
shadowOf(mPackageManager).addIntentFilterForActivity(contactsActivity, mainFilter);
|
||||
|
||||
if (withPreciseIntents) {
|
||||
IntentFilter listFilter = new IntentFilter(Contacts.Intents.UI.LIST_DEFAULT);
|
||||
listFilter.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
shadowOf(mPackageManager).addIntentFilterForActivity(contactsActivity, listFilter);
|
||||
|
||||
IntentFilter starredFilter = new IntentFilter(Contacts.Intents.UI.LIST_STARRED_ACTION);
|
||||
starredFilter.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
shadowOf(mPackageManager).addIntentFilterForActivity(contactsActivity, starredFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private SelectorWithWidgetPreference getBoundSelectorPreference(String key) {
|
||||
SelectorWithWidgetPreference selectorPref = checkNotNull(
|
||||
mCallsPrefCategory.findPreference(key));
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
View view = inflater.inflate(selectorPref.getLayoutResource(), null);
|
||||
LinearLayout widgetView = view.findViewById(android.R.id.widget_frame);
|
||||
assertThat(widgetView).isNotNull();
|
||||
inflater.inflate(selectorPref.getWidgetLayoutResource(), widgetView, true);
|
||||
|
||||
PreferenceViewHolder viewHolder = PreferenceViewHolder.createInstanceForTests(view);
|
||||
selectorPref.onBindViewHolder(viewHolder);
|
||||
|
||||
return selectorPref;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user