Merge "Distinguish the profile of DND-bypassing apps" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
d133ec93ab
@@ -19,28 +19,32 @@ package com.android.settings.notification.modes;
|
||||
import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
|
||||
import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.text.BidiFormatter;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
import com.android.settingslib.notification.modes.ZenMode;
|
||||
import com.android.settingslib.notification.modes.ZenModesBackend;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Preference with a link and summary about what apps can break through the mode
|
||||
@@ -51,12 +55,21 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
|
||||
|
||||
private final ZenModeSummaryHelper mSummaryHelper;
|
||||
private final ApplicationsState mApplicationsState;
|
||||
private final UserManager mUserManager;
|
||||
private ApplicationsState.Session mAppSession;
|
||||
private final ZenHelperBackend mHelperBackend;
|
||||
private ZenMode mZenMode;
|
||||
private Preference mPreference;
|
||||
private final Fragment mHost;
|
||||
|
||||
ZenModeAppsLinkPreferenceController(Context context, String key, Fragment host,
|
||||
ZenModesBackend backend, ZenHelperBackend helperBackend) {
|
||||
this(context, key, host,
|
||||
ApplicationsState.getInstance((Application) context.getApplicationContext()),
|
||||
backend, helperBackend);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
ZenModeAppsLinkPreferenceController(Context context, String key, Fragment host,
|
||||
ApplicationsState applicationsState, ZenModesBackend backend,
|
||||
ZenHelperBackend helperBackend) {
|
||||
@@ -64,6 +77,7 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
|
||||
mSummaryHelper = new ZenModeSummaryHelper(mContext, helperBackend);
|
||||
mHelperBackend = helperBackend;
|
||||
mApplicationsState = applicationsState;
|
||||
mUserManager = context.getSystemService(UserManager.class);
|
||||
mHost = host;
|
||||
}
|
||||
|
||||
@@ -90,10 +104,10 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
|
||||
if (mApplicationsState != null && mHost != null) {
|
||||
mAppSession = mApplicationsState.newSession(mAppSessionCallbacks, mHost.getLifecycle());
|
||||
}
|
||||
triggerUpdateAppsBypassingDndSummaryText();
|
||||
triggerUpdateAppsBypassingDnd();
|
||||
}
|
||||
|
||||
private void triggerUpdateAppsBypassingDndSummaryText() {
|
||||
private void triggerUpdateAppsBypassingDnd() {
|
||||
if (mAppSession == null) {
|
||||
return;
|
||||
}
|
||||
@@ -108,31 +122,28 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
|
||||
mAppSession.rebuild(filter, ApplicationsState.ALPHA_COMPARATOR, false);
|
||||
}
|
||||
|
||||
private void updateAppsBypassingDndSummaryText(List<ApplicationsState.AppEntry> apps) {
|
||||
Set<String> appNames = getAppsBypassingDnd(apps);
|
||||
mPreference.setSummary(mSummaryHelper.getAppsSummary(mZenMode, appNames));
|
||||
private void displayAppsBypassingDnd(List<AppEntry> allApps) {
|
||||
ImmutableList<AppEntry> apps = getAppsBypassingDndSortedByName(allApps);
|
||||
|
||||
mPreference.setSummary(mSummaryHelper.getAppsSummary(mZenMode, apps));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
ArraySet<String> getAppsBypassingDnd(@NonNull List<ApplicationsState.AppEntry> apps) {
|
||||
ArraySet<String> appsBypassingDnd = new ArraySet<>();
|
||||
ImmutableList<AppEntry> getAppsBypassingDndSortedByName(@NonNull List<AppEntry> allApps) {
|
||||
Multimap<Integer, String> packagesBypassingDnd = HashMultimap.create();
|
||||
for (UserHandle userHandle : mUserManager.getUserProfiles()) {
|
||||
packagesBypassingDnd.putAll(userHandle.getIdentifier(),
|
||||
mHelperBackend.getPackagesBypassingDnd(userHandle.getIdentifier(),
|
||||
/* includeConversationChannels= */ false));
|
||||
}
|
||||
|
||||
Map<String, String> pkgLabelMap = new HashMap<String, String>();
|
||||
for (ApplicationsState.AppEntry entry : apps) {
|
||||
if (entry.info != null) {
|
||||
pkgLabelMap.put(entry.info.packageName, entry.label);
|
||||
}
|
||||
}
|
||||
for (String pkg : mHelperBackend.getPackagesBypassingDnd(mContext.getUserId(),
|
||||
/* includeConversationChannels= */ false)) {
|
||||
// Settings may hide some packages from the user, so if they're not present here
|
||||
// we skip displaying them, even if they bypass dnd.
|
||||
if (pkgLabelMap.get(pkg) == null) {
|
||||
continue;
|
||||
}
|
||||
appsBypassingDnd.add(BidiFormatter.getInstance().unicodeWrap(pkgLabelMap.get(pkg)));
|
||||
}
|
||||
return appsBypassingDnd;
|
||||
return ImmutableList.copyOf(
|
||||
allApps.stream()
|
||||
.filter(app -> packagesBypassingDnd.containsEntry(
|
||||
UserHandle.getUserId(app.info.uid), app.info.packageName))
|
||||
.sorted(Comparator.comparing((AppEntry app) -> app.label)
|
||||
.thenComparing(app -> UserHandle.getUserId(app.info.uid)))
|
||||
.toList());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -145,12 +156,12 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
|
||||
|
||||
@Override
|
||||
public void onPackageListChanged() {
|
||||
triggerUpdateAppsBypassingDndSummaryText();
|
||||
triggerUpdateAppsBypassingDnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
|
||||
updateAppsBypassingDndSummaryText(apps);
|
||||
displayAppsBypassingDnd(apps);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -171,7 +182,7 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
|
||||
|
||||
@Override
|
||||
public void onLoadEntriesCompleted() {
|
||||
triggerUpdateAppsBypassingDndSummaryText();
|
||||
triggerUpdateAppsBypassingDnd();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@
|
||||
package com.android.settings.notification.modes;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Application;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.view.Menu;
|
||||
@@ -29,7 +28,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.core.view.MenuProvider;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.notification.modes.ZenMode;
|
||||
|
||||
@@ -58,9 +56,7 @@ public class ZenModeFragment extends ZenModeFragmentBase {
|
||||
prefControllers.add(new ZenModePeopleLinkPreferenceController(
|
||||
context, "zen_mode_people", mHelperBackend));
|
||||
prefControllers.add(new ZenModeAppsLinkPreferenceController(
|
||||
context, "zen_mode_apps", this,
|
||||
ApplicationsState.getInstance((Application) context.getApplicationContext()),
|
||||
mBackend, mHelperBackend));
|
||||
context, "zen_mode_apps", this, mBackend, mHelperBackend));
|
||||
prefControllers.add(new ZenModeOtherLinkPreferenceController(
|
||||
context, "zen_other_settings", mHelperBackend));
|
||||
prefControllers.add(new ZenModeDisplayLinkPreferenceController(
|
||||
|
@@ -49,17 +49,18 @@ import android.util.ArrayMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.text.BidiFormatter;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||
import com.android.settingslib.notification.modes.ZenMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
class ZenModeSummaryHelper {
|
||||
@@ -412,7 +413,7 @@ class ZenModeSummaryHelper {
|
||||
* on the given mode and provided set of apps.
|
||||
*/
|
||||
public @NonNull String getAppsSummary(@NonNull ZenMode zenMode,
|
||||
@Nullable Set<String> appsBypassing) {
|
||||
@Nullable List<AppEntry> appsBypassing) {
|
||||
if (zenMode.getPolicy().getAllowedChannels() == ZenPolicy.CHANNEL_POLICY_PRIORITY) {
|
||||
return formatAppsList(appsBypassing);
|
||||
} else if (zenMode.getPolicy().getAllowedChannels() == ZenPolicy.CHANNEL_POLICY_NONE) {
|
||||
@@ -424,28 +425,34 @@ class ZenModeSummaryHelper {
|
||||
/**
|
||||
* Generates a formatted string declaring which apps can interrupt in the style of
|
||||
* "App, App2, and 4 more can interrupt."
|
||||
* Apps selected for explicit mention are selected in order from the provided set sorted
|
||||
* alphabetically.
|
||||
* Apps selected for explicit mention are picked in order from the provided list.
|
||||
*/
|
||||
public @NonNull String formatAppsList(@Nullable Set<String> appsBypassingDnd) {
|
||||
@VisibleForTesting
|
||||
public @NonNull String formatAppsList(@Nullable List<AppEntry> appsBypassingDnd) {
|
||||
if (appsBypassingDnd == null) {
|
||||
return mContext.getResources().getString(R.string.zen_mode_apps_priority_apps);
|
||||
}
|
||||
final int numAppsBypassingDnd = appsBypassingDnd.size();
|
||||
String[] appsBypassingDndArr = appsBypassingDnd.toArray(new String[numAppsBypassingDnd]);
|
||||
// Sorts the provided apps alphabetically.
|
||||
Arrays.sort(appsBypassingDndArr);
|
||||
List<String> appNames = appsBypassingDnd.stream().limit(3)
|
||||
.map(app -> {
|
||||
String appName = BidiFormatter.getInstance().unicodeWrap(app.label);
|
||||
if (app.isManagedProfile()) {
|
||||
appName = mContext.getString(R.string.zen_mode_apps_work_app, appName);
|
||||
}
|
||||
return appName;
|
||||
})
|
||||
.toList();
|
||||
|
||||
MessageFormat msgFormat = new MessageFormat(
|
||||
mContext.getString(R.string.zen_mode_apps_subtext),
|
||||
Locale.getDefault());
|
||||
Map<String, Object> args = new HashMap<>();
|
||||
args.put("count", numAppsBypassingDnd);
|
||||
if (numAppsBypassingDnd >= 1) {
|
||||
args.put("app_1", appsBypassingDndArr[0]);
|
||||
if (numAppsBypassingDnd >= 2) {
|
||||
args.put("app_2", appsBypassingDndArr[1]);
|
||||
if (numAppsBypassingDnd == 3) {
|
||||
args.put("app_3", appsBypassingDndArr[2]);
|
||||
args.put("count", appsBypassingDnd.size());
|
||||
if (appNames.size() >= 1) {
|
||||
args.put("app_1", appNames.get(0));
|
||||
if (appNames.size() >= 2) {
|
||||
args.put("app_2", appNames.get(1));
|
||||
if (appNames.size() == 3) {
|
||||
args.put("app_3", appNames.get(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user