Merge "Update ZenModeAddBypassingApps to not binder call for every app" into main
This commit is contained in:
@@ -23,6 +23,7 @@ import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY
|
|||||||
|
|
||||||
import static com.android.server.notification.Flags.notificationHideUnusedChannels;
|
import static com.android.server.notification.Flags.notificationHideUnusedChannels;
|
||||||
|
|
||||||
|
import android.annotation.FlaggedApi;
|
||||||
import android.app.Flags;
|
import android.app.Flags;
|
||||||
import android.app.INotificationManager;
|
import android.app.INotificationManager;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
@@ -67,10 +68,13 @@ import com.android.settingslib.utils.StringUtil;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class NotificationBackend {
|
public class NotificationBackend {
|
||||||
private static final String TAG = "NotificationBackend";
|
private static final String TAG = "NotificationBackend";
|
||||||
@@ -368,6 +372,20 @@ public class NotificationBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a set of all apps that have any notification channels (not including deleted ones).
|
||||||
|
*/
|
||||||
|
@FlaggedApi(Flags.FLAG_NM_BINDER_PERF_GET_APPS_WITH_CHANNELS)
|
||||||
|
public @NonNull Set<String> getPackagesWithAnyChannels(int userId) {
|
||||||
|
try {
|
||||||
|
List<String> packages = sINM.getPackagesWithAnyChannels(userId);
|
||||||
|
return new HashSet<>(packages);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(TAG, "Error calling NoMan", e);
|
||||||
|
return Collections.EMPTY_SET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void updateChannel(String pkg, int uid, NotificationChannel channel) {
|
public void updateChannel(String pkg, int uid, NotificationChannel channel) {
|
||||||
try {
|
try {
|
||||||
sINM.updateNotificationChannelForPackage(pkg, uid, channel);
|
sINM.updateNotificationChannelForPackage(pkg, uid, channel);
|
||||||
|
@@ -17,11 +17,13 @@
|
|||||||
package com.android.settings.notification.modes;
|
package com.android.settings.notification.modes;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.app.Flags;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
@@ -44,7 +46,11 @@ import com.android.settingslib.utils.ThreadUtils;
|
|||||||
import com.android.settingslib.widget.AppPreference;
|
import com.android.settingslib.widget.AppPreference;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,6 +64,8 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
private static final String KEY = "zen_mode_non_bypassing_apps_list";
|
private static final String KEY = "zen_mode_non_bypassing_apps_list";
|
||||||
private static final String KEY_ADD = "zen_mode_bypassing_apps_add";
|
private static final String KEY_ADD = "zen_mode_bypassing_apps_add";
|
||||||
@Nullable private final NotificationBackend mNotificationBackend;
|
@Nullable private final NotificationBackend mNotificationBackend;
|
||||||
|
@Nullable private final ZenHelperBackend mHelperBackend;
|
||||||
|
@Nullable private final UserManager mUserManager;
|
||||||
|
|
||||||
@Nullable @VisibleForTesting ApplicationsState mApplicationsState;
|
@Nullable @VisibleForTesting ApplicationsState mApplicationsState;
|
||||||
@VisibleForTesting PreferenceScreen mPreferenceScreen;
|
@VisibleForTesting PreferenceScreen mPreferenceScreen;
|
||||||
@@ -69,18 +77,22 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
@Nullable private Fragment mHostFragment;
|
@Nullable private Fragment mHostFragment;
|
||||||
|
|
||||||
public ZenModeAddBypassingAppsPreferenceController(Context context, @Nullable Application app,
|
public ZenModeAddBypassingAppsPreferenceController(Context context, @Nullable Application app,
|
||||||
@Nullable Fragment host, @Nullable NotificationBackend notificationBackend) {
|
@Nullable Fragment host, @Nullable NotificationBackend notificationBackend,
|
||||||
|
@Nullable ZenHelperBackend helperBackend) {
|
||||||
this(context, app == null ? null : ApplicationsState.getInstance(app), host,
|
this(context, app == null ? null : ApplicationsState.getInstance(app), host,
|
||||||
notificationBackend);
|
notificationBackend, helperBackend);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ZenModeAddBypassingAppsPreferenceController(Context context,
|
private ZenModeAddBypassingAppsPreferenceController(Context context,
|
||||||
@Nullable ApplicationsState appState, @Nullable Fragment host,
|
@Nullable ApplicationsState appState, @Nullable Fragment host,
|
||||||
@Nullable NotificationBackend notificationBackend) {
|
@Nullable NotificationBackend notificationBackend,
|
||||||
|
@Nullable ZenHelperBackend helperBackend) {
|
||||||
super(context);
|
super(context);
|
||||||
mNotificationBackend = notificationBackend;
|
mNotificationBackend = notificationBackend;
|
||||||
mApplicationsState = appState;
|
mApplicationsState = appState;
|
||||||
mHostFragment = host;
|
mHostFragment = host;
|
||||||
|
mHelperBackend = helperBackend;
|
||||||
|
mUserManager = context.getSystemService(UserManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -147,7 +159,7 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void updateAppList(List<ApplicationsState.AppEntry> apps) {
|
void updateAppList(List<ApplicationsState.AppEntry> apps) {
|
||||||
if (apps == null) {
|
if (apps == null || mNotificationBackend == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,21 +169,49 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
mPreferenceScreen.addPreference(mPreferenceCategory);
|
mPreferenceScreen.addPreference(mPreferenceCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<Integer, Set<String>> packagesByUser = new HashMap<>();
|
||||||
|
Map<Integer, Map<String, Boolean>> packagesBypassingDndByUser = new HashMap<>();
|
||||||
|
if (Flags.nmBinderPerfGetAppsWithChannels()) {
|
||||||
|
if (mHelperBackend == null || mUserManager == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (UserHandle userHandle : mUserManager.getUserProfiles()) {
|
||||||
|
int userId = userHandle.getIdentifier();
|
||||||
|
packagesByUser.put(userId, mNotificationBackend.getPackagesWithAnyChannels(userId));
|
||||||
|
packagesBypassingDndByUser.put(userId,
|
||||||
|
mHelperBackend.getPackagesBypassingDnd(userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
boolean doAnyAppsPassCriteria = false;
|
boolean doAnyAppsPassCriteria = false;
|
||||||
for (ApplicationsState.AppEntry app : apps) {
|
for (ApplicationsState.AppEntry app : apps) {
|
||||||
String pkg = app.info.packageName;
|
String pkg = app.info.packageName;
|
||||||
final String key = getKey(pkg, app.info.uid);
|
final String key = getKey(pkg, app.info.uid);
|
||||||
|
int userId = UserHandle.getUserId(app.info.uid);
|
||||||
|
|
||||||
|
boolean doesAppBypassDnd, doesAppHaveAnyChannels;
|
||||||
|
if (Flags.nmBinderPerfGetAppsWithChannels()) {
|
||||||
|
Set<String> packagesWithChannels = packagesByUser.getOrDefault(userId,
|
||||||
|
Collections.EMPTY_SET);
|
||||||
|
Map<String, Boolean> packagesBypassingDnd =
|
||||||
|
packagesBypassingDndByUser.getOrDefault(userId, new HashMap<>());
|
||||||
|
doesAppBypassDnd = packagesBypassingDnd.containsKey(pkg);
|
||||||
|
doesAppHaveAnyChannels = packagesWithChannels.contains(pkg);
|
||||||
|
} else {
|
||||||
final int appChannels = mNotificationBackend.getChannelCount(pkg, app.info.uid);
|
final int appChannels = mNotificationBackend.getChannelCount(pkg, app.info.uid);
|
||||||
final int appChannelsBypassingDnd = mNotificationBackend
|
final int appChannelsBypassingDnd = mNotificationBackend
|
||||||
.getNotificationChannelsBypassingDnd(pkg, app.info.uid).getList().size();
|
.getNotificationChannelsBypassingDnd(pkg, app.info.uid).getList().size();
|
||||||
if (appChannelsBypassingDnd == 0 && appChannels > 0) {
|
doesAppBypassDnd = (appChannelsBypassingDnd != 0);
|
||||||
|
doesAppHaveAnyChannels = (appChannels > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!doesAppBypassDnd && doesAppHaveAnyChannels) {
|
||||||
doAnyAppsPassCriteria = true;
|
doAnyAppsPassCriteria = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Preference pref = mPreferenceCategory.findPreference(key);
|
Preference pref = mPreferenceCategory.findPreference(key);
|
||||||
|
|
||||||
if (pref == null) {
|
if (pref == null) {
|
||||||
if (appChannelsBypassingDnd == 0 && appChannels > 0) {
|
if (!doesAppBypassDnd && doesAppHaveAnyChannels) {
|
||||||
// does not exist but should
|
// does not exist but should
|
||||||
pref = new AppPreference(mPrefContext);
|
pref = new AppPreference(mPrefContext);
|
||||||
pref.setKey(key);
|
pref.setKey(key);
|
||||||
@@ -193,7 +233,7 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere
|
|||||||
updateIcon(pref, app);
|
updateIcon(pref, app);
|
||||||
mPreferenceCategory.addPreference(pref);
|
mPreferenceCategory.addPreference(pref);
|
||||||
}
|
}
|
||||||
} else if (appChannelsBypassingDnd != 0 || appChannels == 0) {
|
} else if (doesAppBypassDnd || !doesAppHaveAnyChannels) {
|
||||||
// exists but shouldn't anymore
|
// exists but shouldn't anymore
|
||||||
mPreferenceCategory.removePreference(pref);
|
mPreferenceCategory.removePreference(pref);
|
||||||
}
|
}
|
||||||
|
@@ -60,7 +60,7 @@ public class ZenModeSelectBypassingAppsFragment extends ZenModeFragmentBase impl
|
|||||||
controllers.add(new ZenModeAllBypassingAppsPreferenceController(context, app, host,
|
controllers.add(new ZenModeAllBypassingAppsPreferenceController(context, app, host,
|
||||||
zenHelperBackend));
|
zenHelperBackend));
|
||||||
controllers.add(new ZenModeAddBypassingAppsPreferenceController(context, app, host,
|
controllers.add(new ZenModeAddBypassingAppsPreferenceController(context, app, host,
|
||||||
notificationBackend));
|
notificationBackend, zenHelperBackend));
|
||||||
return controllers;
|
return controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ package com.android.settings.notification.modes;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@@ -30,6 +31,8 @@ import android.content.Context;
|
|||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.ParceledListSlice;
|
import android.content.pm.ParceledListSlice;
|
||||||
import android.platform.test.annotations.EnableFlags;
|
import android.platform.test.annotations.EnableFlags;
|
||||||
|
import android.platform.test.annotations.UsesFlags;
|
||||||
|
import android.platform.test.flag.junit.FlagsParameterization;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
@@ -46,36 +49,50 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.ParameterizedRobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(ParameterizedRobolectricTestRunner.class)
|
||||||
|
@UsesFlags(android.app.Flags.class)
|
||||||
@EnableFlags(Flags.FLAG_MODES_UI)
|
@EnableFlags(Flags.FLAG_MODES_UI)
|
||||||
public class ZenModeAddBypassingAppsPreferenceControllerTest {
|
public class ZenModeAddBypassingAppsPreferenceControllerTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private NotificationBackend mBackend;
|
private NotificationBackend mBackend;
|
||||||
@Mock
|
@Mock
|
||||||
|
private ZenHelperBackend mHelperBackend;
|
||||||
|
@Mock
|
||||||
private PreferenceCategory mPreferenceCategory;
|
private PreferenceCategory mPreferenceCategory;
|
||||||
@Mock
|
@Mock
|
||||||
private ApplicationsState mApplicationState;
|
private ApplicationsState mApplicationState;
|
||||||
private ZenModeAddBypassingAppsPreferenceController mController;
|
private ZenModeAddBypassingAppsPreferenceController mController;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
|
@ParameterizedRobolectricTestRunner.Parameters(name = "{0}")
|
||||||
|
public static List<FlagsParameterization> getParams() {
|
||||||
|
return FlagsParameterization.allCombinationsOf(
|
||||||
|
Flags.FLAG_NM_BINDER_PERF_GET_APPS_WITH_CHANNELS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZenModeAddBypassingAppsPreferenceControllerTest(FlagsParameterization flags) {
|
||||||
|
mSetFlagsRule.setFlagsParameterization(flags);
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mContext = RuntimeEnvironment.application;
|
mContext = RuntimeEnvironment.application;
|
||||||
|
|
||||||
mController = new ZenModeAddBypassingAppsPreferenceController(
|
mController = new ZenModeAddBypassingAppsPreferenceController(
|
||||||
mContext, null, mock(Fragment.class), mBackend);
|
mContext, null, mock(Fragment.class), mBackend, mHelperBackend);
|
||||||
mController.mPreferenceCategory = mPreferenceCategory;
|
mController.mPreferenceCategory = mPreferenceCategory;
|
||||||
mController.mApplicationsState = mApplicationState;
|
mController.mApplicationsState = mApplicationState;
|
||||||
mController.mPrefContext = mContext;
|
mController.mPrefContext = mContext;
|
||||||
@@ -132,6 +149,12 @@ public class ZenModeAddBypassingAppsPreferenceControllerTest {
|
|||||||
appWithChannelsNoneBypassing.info.uid))
|
appWithChannelsNoneBypassing.info.uid))
|
||||||
.thenReturn(new ParceledListSlice<>(new ArrayList<>()));
|
.thenReturn(new ParceledListSlice<>(new ArrayList<>()));
|
||||||
|
|
||||||
|
// used when NM_BINDER_PERF_GET_APPS_WITH_CHANNELS flag is true
|
||||||
|
when(mBackend.getPackagesWithAnyChannels(anyInt())).thenReturn(
|
||||||
|
Set.of("appWithBypassingChannels", "appWithChannelsNoneBypassing"));
|
||||||
|
when(mHelperBackend.getPackagesBypassingDnd(anyInt())).thenReturn(
|
||||||
|
Map.of("appWithBypassingChannels", false));
|
||||||
|
|
||||||
List<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
|
List<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
|
||||||
appEntries.add(appWithBypassingChannels);
|
appEntries.add(appWithBypassingChannels);
|
||||||
appEntries.add(appWithoutChannels);
|
appEntries.add(appWithoutChannels);
|
||||||
|
Reference in New Issue
Block a user