Files
app_Settings/src/com/android/settings/notification/app/RecentConversationsPreferenceController.java
Julia Reynolds 86af9e9da0 Add a11y announcement
Since the button for clearing recent conversations may still
exist after the user triggers the button since some of the
conversations might not be removable

Test: manual with talkback
Fixes: 185433664
Change-Id: Id58d76237643e4e206ea6d551cdf7dd9f5742282
2021-05-17 11:11:29 -04:00

258 lines
10 KiB
Java

/*
* Copyright (C) 2020 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.app;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import android.app.people.ConversationChannel;
import android.app.people.IPeopleManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.widget.Button;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.widget.LayoutPreference;
import java.text.Collator;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class RecentConversationsPreferenceController extends AbstractPreferenceController {
private static final String TAG = "RecentConversationsPC";
private static final String KEY = "recent_conversations";
private List<ConversationChannel> mConversations;
private final IPeopleManager mPs;
private final NotificationBackend mBackend;
public RecentConversationsPreferenceController(Context context, NotificationBackend backend,
IPeopleManager ps) {
super(context);
mBackend = backend;
mPs = ps;
}
@Override
public String getPreferenceKey() {
return KEY;
}
@Override
public boolean isAvailable() {
return true;
}
LayoutPreference getClearAll(PreferenceGroup parent) {
LayoutPreference pref = new LayoutPreference(
mContext, R.layout.conversations_clear_recents);
pref.setOrder(1);
Button button = pref.findViewById(R.id.conversation_settings_clear_recents);
button.setOnClickListener(v -> {
try {
mPs.removeAllRecentConversations();
// Removing recents is asynchronous, so we can't immediately reload the list from
// the backend. Instead, proactively remove all of items that were marked as
// clearable, so long as we didn't get an error
for (int i = parent.getPreferenceCount() - 1; i >= 0; i--) {
Preference p = parent.getPreference(i);
if (p instanceof RecentConversationPreference) {
if (((RecentConversationPreference) p).hasClearListener()) {
parent.removePreference(p);
}
}
}
button.announceForAccessibility(mContext.getString(R.string.recent_convos_removed));
} catch (RemoteException e) {
Slog.w(TAG, "Could not clear recents", e);
}
});
return pref;
}
@Override
public void updateState(Preference preference) {
PreferenceCategory pref = (PreferenceCategory) preference;
// Load conversations
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... unused) {
try {
mConversations = mPs.getRecentConversations().getList();
} catch (RemoteException e) {
Slog.w(TAG, "Could get recents", e);
}
Collections.sort(mConversations, mConversationComparator);
return null;
}
@Override
protected void onPostExecute(Void unused) {
if (mContext == null) {
return;
}
populateList(mConversations, pref);
}
}.execute();
}
protected void populateList(List<ConversationChannel> conversations,
PreferenceGroup containerGroup) {
containerGroup.removeAll();
boolean hasClearable = false;
if (conversations != null) {
hasClearable = populateConversations(conversations, containerGroup);
}
if (containerGroup.getPreferenceCount() == 0) {
containerGroup.setVisible(false);
} else {
containerGroup.setVisible(true);
if (hasClearable) {
Preference clearAll = getClearAll(containerGroup);
if (clearAll != null) {
containerGroup.addPreference(clearAll);
}
}
}
}
protected boolean populateConversations(List<ConversationChannel> conversations,
PreferenceGroup containerGroup) {
int order = 100;
boolean hasClearable = false;
for (ConversationChannel conversation : conversations) {
if (conversation.getParentNotificationChannel().getImportance() == IMPORTANCE_NONE
|| (conversation.getParentNotificationChannelGroup() != null
&& conversation.getParentNotificationChannelGroup().isBlocked())) {
continue;
}
RecentConversationPreference pref =
createConversationPref(containerGroup, conversation, order++);
containerGroup.addPreference(pref);
if (pref.hasClearListener()) {
hasClearable = true;
}
}
return hasClearable;
}
protected RecentConversationPreference createConversationPref(PreferenceGroup parent,
final ConversationChannel conversation, int order) {
final String pkg = conversation.getShortcutInfo().getPackage();
final int uid = conversation.getUid();
final String conversationId = conversation.getShortcutInfo().getId();
RecentConversationPreference pref = new RecentConversationPreference(mContext);
if (!conversation.hasActiveNotifications()) {
pref.setOnClearClickListener(() -> {
try {
mPs.removeRecentConversation(pkg, UserHandle.getUserId(uid), conversationId);
parent.removePreference(pref);
} catch (RemoteException e) {
Slog.w(TAG, "Could not clear recent", e);
}
});
}
pref.setOrder(order);
pref.setTitle(getTitle(conversation));
pref.setSummary(getSummary(conversation));
pref.setIcon(mBackend.getConversationDrawable(mContext, conversation.getShortcutInfo(),
pkg, uid, false));
pref.setKey(conversation.getParentNotificationChannel().getId()
+ ":" + conversationId);
pref.setOnPreferenceClickListener(preference -> {
mBackend.createConversationNotificationChannel(
pkg, uid,
conversation.getParentNotificationChannel(),
conversationId);
getSubSettingLauncher(conversation, pref.getTitle()).launch();
return true;
});
return pref;
}
CharSequence getSummary(ConversationChannel conversation) {
return conversation.getParentNotificationChannelGroup() == null
? conversation.getParentNotificationChannel().getName()
: mContext.getString(R.string.notification_conversation_summary,
conversation.getParentNotificationChannel().getName(),
conversation.getParentNotificationChannelGroup().getName());
}
CharSequence getTitle(ConversationChannel conversation) {
ShortcutInfo si = conversation.getShortcutInfo();
return si.getLabel();
}
SubSettingLauncher getSubSettingLauncher(ConversationChannel conversation,
CharSequence title) {
Bundle channelArgs = new Bundle();
channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, conversation.getUid());
channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME,
conversation.getShortcutInfo().getPackage());
channelArgs.putString(Settings.EXTRA_CHANNEL_ID,
conversation.getParentNotificationChannel().getId());
channelArgs.putString(Settings.EXTRA_CONVERSATION_ID,
conversation.getShortcutInfo().getId());
return new SubSettingLauncher(mContext)
.setDestination(ChannelNotificationSettings.class.getName())
.setArguments(channelArgs)
.setExtras(channelArgs)
.setUserHandle(UserHandle.getUserHandleForUid(conversation.getUid()))
.setTitleText(title)
.setSourceMetricsCategory(SettingsEnums.NOTIFICATION_CONVERSATION_LIST_SETTINGS);
}
protected Comparator<ConversationChannel> mConversationComparator =
new Comparator<ConversationChannel>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(ConversationChannel o1, ConversationChannel o2) {
int labelComparison = sCollator.compare(o1.getShortcutInfo().getLabel(),
o2.getShortcutInfo().getLabel());
if (labelComparison == 0) {
return o1.getParentNotificationChannel().getId().compareTo(
o2.getParentNotificationChannel().getId());
}
return labelComparison;
}
};
}