From 9f7af5946e4782154dd8c751cf3a31225a8a607b Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Thu, 16 Feb 2023 15:30:24 -0500 Subject: [PATCH] Reduce jank on DND apps page 1) Remove call to redisplay the api when registering our app listener - this meant all preferences were always removed/readded on page load because the app list isn't ready at that time 2) Stop rebuilding the UI for events we don't care about 3) Keep existing preferences when possible and just do the diff of prefs that need to be added/removed Fixes: 234298144 Test: ZenModeAddBypassingAppsPreferenceControllerTest Test: ZenModeAllBypassingAppsPreferenceControllerTest Test: manually view page; add & remove apps that have dnd breakthrough Change-Id: I57b36d36135dd25d1d2fd73073cf6b7a033659a6 --- ...eAddBypassingAppsPreferenceController.java | 71 ++++++++-------- ...eAllBypassingAppsPreferenceController.java | 83 +++++++------------ ...BypassingAppsPreferenceControllerTest.java | 7 +- 3 files changed, 72 insertions(+), 89 deletions(-) diff --git a/src/com/android/settings/notification/zen/ZenModeAddBypassingAppsPreferenceController.java b/src/com/android/settings/notification/zen/ZenModeAddBypassingAppsPreferenceController.java index 5cffb9c5789..966461055f2 100644 --- a/src/com/android/settings/notification/zen/ZenModeAddBypassingAppsPreferenceController.java +++ b/src/com/android/settings/notification/zen/ZenModeAddBypassingAppsPreferenceController.java @@ -53,6 +53,7 @@ import java.util.List; public class ZenModeAddBypassingAppsPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin { + public static final String KEY_NO_APPS = "add_none"; private static final String KEY = "zen_mode_non_bypassing_apps_list"; private static final String KEY_ADD = "zen_mode_bypassing_apps_add"; private final NotificationBackend mNotificationBackend; @@ -118,9 +119,7 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere } ApplicationsState.AppFilter filter = ApplicationsState.FILTER_ALL_ENABLED; - List apps = mAppSession.rebuild(filter, - ApplicationsState.ALPHA_COMPARATOR); - updateAppList(apps); + mAppSession.rebuild(filter, ApplicationsState.ALPHA_COMPARATOR); } // Set the icon for the given preference to the entry icon from cache if available, or look @@ -153,57 +152,63 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere mPreferenceScreen.addPreference(mPreferenceCategory); } - List appsWithNoBypassingDndNotificationChannels = new ArrayList<>(); - for (ApplicationsState.AppEntry entry : apps) { - String pkg = entry.info.packageName; - final int appChannels = mNotificationBackend.getChannelCount(pkg, entry.info.uid); + boolean doAnyAppsPassCriteria = false; + for (ApplicationsState.AppEntry app : apps) { + String pkg = app.info.packageName; + final String key = getKey(pkg, app.info.uid); + final int appChannels = mNotificationBackend.getChannelCount(pkg, app.info.uid); final int appChannelsBypassingDnd = mNotificationBackend - .getNotificationChannelsBypassingDnd(pkg, entry.info.uid).getList().size(); + .getNotificationChannelsBypassingDnd(pkg, app.info.uid).getList().size(); if (appChannelsBypassingDnd == 0 && appChannels > 0) { - final String key = ZenModeAllBypassingAppsPreferenceController.getKey(pkg); - Preference pref = mPreferenceCategory.findPreference(""); - if (pref == null) { + doAnyAppsPassCriteria = true; + } + + Preference pref = mPreferenceCategory.findPreference(key); + + if (pref == null) { + if (appChannelsBypassingDnd == 0 && appChannels > 0) { + // does not exist but should pref = new AppPreference(mPrefContext); pref.setKey(key); pref.setOnPreferenceClickListener(preference -> { Bundle args = new Bundle(); - args.putString(AppInfoBase.ARG_PACKAGE_NAME, entry.info.packageName); - args.putInt(AppInfoBase.ARG_PACKAGE_UID, entry.info.uid); + args.putString(AppInfoBase.ARG_PACKAGE_NAME, app.info.packageName); + args.putInt(AppInfoBase.ARG_PACKAGE_UID, app.info.uid); new SubSettingLauncher(mContext) .setDestination(AppChannelsBypassingDndSettings.class.getName()) .setArguments(args) .setResultListener(mHostFragment, 0) - .setUserHandle(new UserHandle(UserHandle.getUserId(entry.info.uid))) + .setUserHandle(new UserHandle(UserHandle.getUserId(app.info.uid))) .setSourceMetricsCategory( SettingsEnums.NOTIFICATION_ZEN_MODE_OVERRIDING_APP) .launch(); return true; }); + pref.setTitle(BidiFormatter.getInstance().unicodeWrap(app.label)); + updateIcon(pref, app); + mPreferenceCategory.addPreference(pref); } - pref.setTitle(BidiFormatter.getInstance().unicodeWrap(entry.label)); - updateIcon(pref, entry); - appsWithNoBypassingDndNotificationChannels.add(pref); + } else if (appChannelsBypassingDnd != 0 || appChannels == 0) { + // exists but shouldn't anymore + mPreferenceCategory.removePreference(pref); } } - if (appsWithNoBypassingDndNotificationChannels.size() == 0) { - Preference pref = mPreferenceCategory.findPreference( - ZenModeAllBypassingAppsPreferenceController.KEY_NO_APPS); + Preference pref = mPreferenceCategory.findPreference(KEY_NO_APPS); + if (!doAnyAppsPassCriteria) { if (pref == null) { pref = new Preference(mPrefContext); - pref.setKey(ZenModeAllBypassingAppsPreferenceController.KEY_NO_APPS); - pref.setTitle(R.string.zen_mode_bypassing_apps_subtext_none); + pref.setKey(KEY_NO_APPS); + pref.setTitle(R.string.zen_mode_bypassing_apps_none); } mPreferenceCategory.addPreference(pref); + } else if (pref != null) { + mPreferenceCategory.removePreference(pref); } + } - if (ZenModeAllBypassingAppsPreferenceController.hasAppListChanged( - appsWithNoBypassingDndNotificationChannels, mPreferenceCategory)) { - mPreferenceCategory.removeAll(); - for (Preference prefToAdd : appsWithNoBypassingDndNotificationChannels) { - mPreferenceCategory.addPreference(prefToAdd); - } - } + static String getKey(String pkg, int uid) { + return "add|" + pkg + "|" + uid; } private final ApplicationsState.Callbacks mAppSessionCallbacks = @@ -211,12 +216,12 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere @Override public void onRunningStateChanged(boolean running) { - updateAppList(); + } @Override public void onPackageListChanged() { - updateAppList(); + } @Override @@ -231,7 +236,7 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere @Override public void onPackageSizeChanged(String packageName) { - updateAppList(); + } @Override @@ -239,7 +244,7 @@ public class ZenModeAddBypassingAppsPreferenceController extends AbstractPrefere @Override public void onLauncherInfoChanged() { - updateAppList(); + } @Override diff --git a/src/com/android/settings/notification/zen/ZenModeAllBypassingAppsPreferenceController.java b/src/com/android/settings/notification/zen/ZenModeAllBypassingAppsPreferenceController.java index 4cbfacb31fc..f4b7036c3d0 100644 --- a/src/com/android/settings/notification/zen/ZenModeAllBypassingAppsPreferenceController.java +++ b/src/com/android/settings/notification/zen/ZenModeAllBypassingAppsPreferenceController.java @@ -44,7 +44,6 @@ import com.android.settingslib.widget.AppPreference; import java.util.ArrayList; import java.util.List; -import java.util.Objects; /** @@ -52,7 +51,7 @@ import java.util.Objects; */ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin { - public static final String KEY_NO_APPS = getKey("none"); + public static final String KEY_NO_APPS = "all_none"; private static final String KEY = "zen_mode_bypassing_apps_list"; private final NotificationBackend mNotificationBackend; @@ -109,9 +108,7 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere } ApplicationsState.AppFilter filter = ApplicationsState.FILTER_ALL_ENABLED; - List apps = mAppSession.rebuild(filter, - ApplicationsState.ALPHA_COMPARATOR); - updateAppList(apps); + mAppSession.rebuild(filter, ApplicationsState.ALPHA_COMPARATOR); } // Set the icon for the given preference to the entry icon from cache if available, or look @@ -138,17 +135,21 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere return; } - List appsBypassingDnd = new ArrayList<>(); + boolean doAnyAppsPassCriteria = false; for (ApplicationsState.AppEntry app : apps) { String pkg = app.info.packageName; + final String key = getKey(pkg, app.info.uid); final int appChannels = mNotificationBackend.getChannelCount(pkg, app.info.uid); final int appChannelsBypassingDnd = mNotificationBackend .getNotificationChannelsBypassingDnd(pkg, app.info.uid).getList().size(); if (appChannelsBypassingDnd > 0) { - final String key = getKey(pkg); - // re-use previously created preference when possible - Preference pref = mPreferenceCategory.findPreference(key); - if (pref == null) { + doAnyAppsPassCriteria = true; + } + + Preference pref = mPreferenceCategory.findPreference(key); + if (pref == null) { + if (appChannelsBypassingDnd > 0) { + // does not exist but should pref = new AppPreference(mPrefContext); pref.setKey(key); pref.setOnPreferenceClickListener(preference -> { @@ -165,59 +166,40 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere .launch(); return true; }); + pref.setTitle(BidiFormatter.getInstance().unicodeWrap(app.label)); + updateIcon(pref, app); + if (appChannels > appChannelsBypassingDnd) { + pref.setSummary(R.string.zen_mode_bypassing_apps_summary_some); + } else { + pref.setSummary(R.string.zen_mode_bypassing_apps_summary_all); + } + mPreferenceCategory.addPreference(pref); } - pref.setTitle(BidiFormatter.getInstance().unicodeWrap(app.label)); - updateIcon(pref, app); - if (appChannels > appChannelsBypassingDnd) { - pref.setSummary(R.string.zen_mode_bypassing_apps_summary_some); - } else { - pref.setSummary(R.string.zen_mode_bypassing_apps_summary_all); - } - - appsBypassingDnd.add(pref); + } + else if (appChannelsBypassingDnd == 0) { + // exists but shouldn't anymore + mPreferenceCategory.removePreference(pref); } } - if (appsBypassingDnd.size() == 0) { - Preference pref = mPreferenceCategory.findPreference(KEY_NO_APPS); + Preference pref = mPreferenceCategory.findPreference(KEY_NO_APPS); + if (!doAnyAppsPassCriteria) { if (pref == null) { pref = new Preference(mPrefContext); pref.setKey(KEY_NO_APPS); pref.setTitle(R.string.zen_mode_bypassing_apps_none); } - appsBypassingDnd.add(pref); + mPreferenceCategory.addPreference(pref); + } else if (pref != null) { + mPreferenceCategory.removePreference(pref); } - - if (hasAppListChanged(appsBypassingDnd, mPreferenceCategory)) { - mPreferenceCategory.removeAll(); - for (Preference prefToAdd : appsBypassingDnd) { - mPreferenceCategory.addPreference(prefToAdd); - } - } - } - - static boolean hasAppListChanged(List newAppPreferences, - PreferenceCategory preferenceCategory) { - if (newAppPreferences.size() != preferenceCategory.getPreferenceCount()) { - return true; - } - - for (int i = 0; i < newAppPreferences.size(); i++) { - Preference newAppPref = newAppPreferences.get(i); - Preference pref = preferenceCategory.getPreference(i); - if (!Objects.equals(newAppPref.getKey(), pref.getKey())) { - return true; - } - } - return false; - } /** * Create a unique key to idenfity an AppPreference */ - static String getKey(String pkg) { - return pkg; + static String getKey(String pkg, int uid) { + return "all|" + pkg + "|" + uid; } private final ApplicationsState.Callbacks mAppSessionCallbacks = @@ -225,12 +207,10 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere @Override public void onRunningStateChanged(boolean running) { - updateAppList(); } @Override public void onPackageListChanged() { - updateAppList(); } @Override @@ -240,12 +220,10 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere @Override public void onPackageIconChanged() { - updateAppList(); } @Override public void onPackageSizeChanged(String packageName) { - updateAppList(); } @Override @@ -253,7 +231,6 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere @Override public void onLauncherInfoChanged() { - updateAppList(); } @Override diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeAddBypassingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeAddBypassingAppsPreferenceControllerTest.java index 52f2c51a3f4..2569ca3592f 100644 --- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeAddBypassingAppsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeAddBypassingAppsPreferenceControllerTest.java @@ -138,8 +138,9 @@ public class ZenModeAddBypassingAppsPreferenceControllerTest { Preference pref = prefCaptor.getValue(); assertThat(pref.getKey()).isEqualTo( - ZenModeAllBypassingAppsPreferenceController.getKey( - appWithChannelsNoneBypassing.info.packageName)); + ZenModeAddBypassingAppsPreferenceController.getKey( + appWithChannelsNoneBypassing.info.packageName, + appWithChannelsNoneBypassing.info.uid)); } @Test @@ -159,6 +160,6 @@ public class ZenModeAddBypassingAppsPreferenceControllerTest { Preference pref = prefCaptor.getValue(); assertThat(pref.getKey()).isEqualTo( - ZenModeAllBypassingAppsPreferenceController.KEY_NO_APPS); + ZenModeAddBypassingAppsPreferenceController.KEY_NO_APPS); } }