Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f7af594 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

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
parent 16927143
Loading
Loading
Loading
Loading
+38 −33
Original line number Diff line number Diff line
@@ -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<ApplicationsState.AppEntry> 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<Preference> 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("");
                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);
        }

        if (ZenModeAllBypassingAppsPreferenceController.hasAppListChanged(
                appsWithNoBypassingDndNotificationChannels, mPreferenceCategory)) {
            mPreferenceCategory.removeAll();
            for (Preference prefToAdd : appsWithNoBypassingDndNotificationChannels) {
                mPreferenceCategory.addPreference(prefToAdd);
        } else if (pref != null) {
            mPreferenceCategory.removePreference(pref);
        }
    }

    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
+30 −53
Original line number Diff line number Diff line
@@ -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<ApplicationsState.AppEntry> 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<Preference> 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
                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,7 +166,6 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
                                .launch();
                        return true;
                    });
                }
                    pref.setTitle(BidiFormatter.getInstance().unicodeWrap(app.label));
                    updateIcon(pref, app);
                    if (appChannels > appChannelsBypassingDnd) {
@@ -173,51 +173,33 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
                    } else {
                        pref.setSummary(R.string.zen_mode_bypassing_apps_summary_all);
                    }

                appsBypassingDnd.add(pref);
                    mPreferenceCategory.addPreference(pref);
                }
            }
            else if (appChannelsBypassingDnd == 0) {
                // exists but shouldn't anymore
                mPreferenceCategory.removePreference(pref);
            }
        }

        if (appsBypassingDnd.size() == 0) {
        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);
        }

        if (hasAppListChanged(appsBypassingDnd, mPreferenceCategory)) {
            mPreferenceCategory.removeAll();
            for (Preference prefToAdd : appsBypassingDnd) {
                mPreferenceCategory.addPreference(prefToAdd);
            }
            mPreferenceCategory.addPreference(pref);
        } else if (pref != null) {
            mPreferenceCategory.removePreference(pref);
        }
    }

    static boolean hasAppListChanged(List<Preference> 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
+4 −3
Original line number Diff line number Diff line
@@ -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);
    }
}