Show icons for allowed contacts

Test: atest com.android.settings.notification.modes
Bug: 346551087
Flag: android.app.modes_ui
Change-Id: If2b6b06b4a9c16bdefb03850ad1615e96c601fbd
This commit is contained in:
Matías Hernández
2024-07-21 00:47:31 +02:00
parent 5c466c5ba3
commit d8b9fe8f01
13 changed files with 559 additions and 97 deletions

View File

@@ -17,25 +17,67 @@
package com.android.settings.notification.modes;
import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_NONE;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_ANYONE;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_NONE;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_STARRED;
import static android.service.notification.ZenPolicy.STATE_ALLOW;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.graphics.drawable.Drawable;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.ZenPolicy;
import android.service.notification.ZenPolicy.ConversationSenders;
import android.service.notification.ZenPolicy.PeopleType;
import android.util.IconDrawableFactory;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.notification.modes.ZenHelperBackend.Contact;
import com.android.settingslib.notification.ConversationIconFactory;
import com.android.settingslib.notification.modes.ZenMode;
import com.google.common.collect.ImmutableList;
import java.util.function.Function;
/**
* Preference with a link and summary about what calls and messages can break through the mode
* Preference with a link and summary about what calls and messages can break through the mode,
* and icons representing those people.
*/
class ZenModePeopleLinkPreferenceController extends AbstractZenModePreferenceController {
private final ZenModeSummaryHelper mSummaryHelper;
private final ZenHelperBackend mHelperBackend;
private final ConversationIconFactory mConversationIconFactory;
public ZenModePeopleLinkPreferenceController(Context context, String key,
ZenModePeopleLinkPreferenceController(Context context, String key,
ZenHelperBackend helperBackend) {
this(context, key, helperBackend,
new ConversationIconFactory(context,
context.getSystemService(LauncherApps.class),
context.getPackageManager(),
IconDrawableFactory.newInstance(context, false),
context.getResources().getDimensionPixelSize(
R.dimen.zen_mode_circular_icon_diameter)));
}
@VisibleForTesting
ZenModePeopleLinkPreferenceController(Context context, String key,
ZenHelperBackend helperBackend, ConversationIconFactory conversationIconFactory) {
super(context, key);
mSummaryHelper = new ZenModeSummaryHelper(mContext, helperBackend);
mHelperBackend = helperBackend;
mConversationIconFactory = conversationIconFactory;
}
@Override
@@ -50,8 +92,104 @@ class ZenModePeopleLinkPreferenceController extends AbstractZenModePreferenceCon
ZenSubSettingLauncher.forModeFragment(mContext, ZenModePeopleFragment.class,
zenMode.getId(), 0).toIntent());
preference.setSummary(mSummaryHelper.getPeopleSummary(zenMode));
// TODO: b/346551087 - Show people icons
((CircularIconsPreference) preference).displayIcons(CircularIconSet.EMPTY);
preference.setSummary(mSummaryHelper.getPeopleSummary(zenMode.getPolicy()));
((CircularIconsPreference) preference).displayIcons(getPeopleIcons(zenMode.getPolicy()));
}
// Represents "Either<Contact, ConversationChannelWrapper>".
record PeopleItem(@Nullable Contact contact,
@Nullable ConversationChannelWrapper conversation) {
PeopleItem(@NonNull Contact contact) {
this(contact, null);
}
PeopleItem(@NonNull ConversationChannelWrapper conversation) {
this(null, conversation);
}
}
private CircularIconSet<?> getPeopleIcons(ZenPolicy policy) {
if (getCallersOrMessagesAllowed(policy) == PEOPLE_TYPE_ANYONE) {
return new CircularIconSet<>(
ImmutableList.of(IconUtil.makeCircularIconPreferenceItem(mContext,
R.drawable.ic_zen_mode_people_all)),
Function.identity());
}
ImmutableList.Builder<PeopleItem> peopleItems = ImmutableList.builder();
fetchContactsAllowed(policy, peopleItems);
fetchConversationsAllowed(policy, peopleItems);
return new CircularIconSet<>(peopleItems.build(), this::loadPeopleIcon);
}
/**
* Adds {@link PeopleItem} entries corresponding to the set of people (contacts) who can
* break through via either call OR message.
*/
private void fetchContactsAllowed(ZenPolicy policy,
ImmutableList.Builder<PeopleItem> peopleItems) {
@PeopleType int peopleAllowed = getCallersOrMessagesAllowed(policy);
ImmutableList<Contact> contactsAllowed = ImmutableList.of();
if (peopleAllowed == PEOPLE_TYPE_CONTACTS) {
contactsAllowed = mHelperBackend.getAllContacts();
} else if (peopleAllowed == PEOPLE_TYPE_STARRED) {
contactsAllowed = mHelperBackend.getStarredContacts();
}
for (Contact contact : contactsAllowed) {
peopleItems.add(new PeopleItem(contact));
}
}
/**
* Adds {@link PeopleItem} entries corresponding to the set of conversation channels that can
* break through.
*/
private void fetchConversationsAllowed(ZenPolicy policy,
ImmutableList.Builder<PeopleItem> peopleItems) {
@ConversationSenders int conversationSendersAllowed =
policy.getPriorityCategoryConversations() == STATE_ALLOW
? policy.getPriorityConversationSenders()
: CONVERSATION_SENDERS_NONE;
ImmutableList<ConversationChannelWrapper> conversationsAllowed = ImmutableList.of();
if (conversationSendersAllowed == CONVERSATION_SENDERS_ANYONE) {
// TODO: b/354658240 - Need to handle CONVERSATION_SENDERS_ANYONE?
return;
} else if (conversationSendersAllowed == CONVERSATION_SENDERS_IMPORTANT) {
conversationsAllowed = mHelperBackend.getImportantConversations();
}
for (ConversationChannelWrapper conversation : conversationsAllowed) {
peopleItems.add(new PeopleItem(conversation));
}
}
/** Returns the broadest set of people who can call OR message. */
private @PeopleType int getCallersOrMessagesAllowed(ZenPolicy policy) {
@PeopleType int callersAllowed = policy.getPriorityCategoryCalls() == STATE_ALLOW
? policy.getPriorityCallSenders() : PEOPLE_TYPE_NONE;
@PeopleType int messagesAllowed = policy.getPriorityCategoryMessages() == STATE_ALLOW
? policy.getPriorityMessageSenders() : PEOPLE_TYPE_NONE;
// Order is ANYONE -> CONTACTS -> STARRED -> NONE, so just taking the minimum works.
return Math.min(callersAllowed, messagesAllowed);
}
@WorkerThread
private Drawable loadPeopleIcon(PeopleItem peopleItem) {
if (peopleItem.contact != null) {
return mHelperBackend.getContactPhoto(peopleItem.contact);
} else if (peopleItem.conversation != null) {
return mConversationIconFactory.getConversationDrawable(
peopleItem.conversation.getShortcutInfo(),
peopleItem.conversation.getPkg(),
peopleItem.conversation.getUid(),
/* important= */ true);
} else {
throw new IllegalArgumentException("Neither contact nor conversation!");
}
}
}