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

Commit a37572a4 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

reduce number of binder calls when loading page

Test: ZenModeAllBypassingAppsPreferenceControllerTest
Test: ZenModeAppsLinkPreferenceControllerTest
Test: manual - load page and validate that it loads a few seconds faster
Flag: EXEMPT bug fix
Fixes: 368623163
Change-Id: I6d34a21f0948b117a96beefc405de4b623f49609
parent 214a71a6
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.notification.modes;

import android.annotation.Nullable;
import android.app.INotificationManager;
import android.app.ZenBypassingApp;
import android.content.ContentProvider;
import android.content.Context;
import android.content.pm.ParceledListSlice;
@@ -30,6 +31,7 @@ import android.os.UserManager;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.service.notification.ConversationChannelWrapper;
import android.util.ArrayMap;
import android.util.Log;

import androidx.annotation.NonNull;
@@ -41,8 +43,9 @@ import com.google.common.collect.ImmutableList;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
@@ -76,16 +79,20 @@ class ZenHelperBackend {
    }

    /**
     * Returns all of a user's packages that have at least one channel that will bypass DND
     * Returns a mapping between a user's packages that have at least one channel that will
     * bypass DND, and a Boolean indicating whether all of the package's channels bypass.
     */
    List<String> getPackagesBypassingDnd(int userId,
            boolean includeConversationChannels) {
    Map<String, Boolean> getPackagesBypassingDnd(int userId) {
        Map<String, Boolean> bypassingAppsMap = new HashMap<>();
        try {
            return mInm.getPackagesBypassingDnd(userId, includeConversationChannels);
            List<ZenBypassingApp> bypassingApps = mInm.getPackagesBypassingDnd(userId).getList();
            for (ZenBypassingApp zba : bypassingApps) {
                bypassingAppsMap.put(zba.getPkg(), zba.doAllChannelsBypass());
            }
        } catch (Exception e) {
            Log.w(TAG, "Error calling NoMan", e);
            return new ArrayList<>();
        }
        return bypassingAppsMap;
    }

    /** Returns all conversation channels for profiles of the current user. */
+27 −17
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.text.BidiFormatter;
@@ -35,7 +37,6 @@ import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.notification.NotificationBackend;
import com.android.settings.notification.app.AppChannelsBypassingDndSettings;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
@@ -44,7 +45,9 @@ import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.AppPreference;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Adds a preference to the PreferenceScreen for each notification channel that can bypass DND.
@@ -54,7 +57,8 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
    public static final String KEY_NO_APPS = "all_none";
    private static final String KEY = "zen_mode_bypassing_apps_list";

    @Nullable private final NotificationBackend mNotificationBackend;
    @Nullable private final ZenHelperBackend mHelperBackend;
    private final UserManager mUserManager;

    @Nullable @VisibleForTesting ApplicationsState mApplicationsState;
    @VisibleForTesting PreferenceCategory mPreferenceCategory;
@@ -64,18 +68,18 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
    @Nullable private Fragment mHostFragment;

    public ZenModeAllBypassingAppsPreferenceController(Context context, @Nullable Application app,
            @Nullable Fragment host, @Nullable NotificationBackend notificationBackend) {
        this(context, app == null ? null : ApplicationsState.getInstance(app), host,
                notificationBackend);
            @Nullable Fragment host, @Nullable ZenHelperBackend helperBackend) {
        this(context, app == null ? null : ApplicationsState.getInstance(app), host, helperBackend);
    }

    private ZenModeAllBypassingAppsPreferenceController(Context context,
            @Nullable ApplicationsState appState, @Nullable Fragment host,
            @Nullable NotificationBackend notificationBackend) {
            @Nullable ZenHelperBackend helperBackend) {
        super(context);
        mNotificationBackend = notificationBackend;
        mApplicationsState = appState;
        mHostFragment = host;
        mHelperBackend = helperBackend;
        mUserManager = context.getSystemService(UserManager.class);

        if (mApplicationsState != null && host != null) {
            mAppSession = mApplicationsState.newSession(mAppSessionCallbacks, host.getLifecycle());
@@ -140,19 +144,25 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
        }

        boolean doAnyAppsPassCriteria = false;
        Map<Integer, Map<String, Boolean>> packagesBypassingDndByUser = new HashMap<>();
        for (UserHandle userHandle : mUserManager.getUserProfiles()) {
            packagesBypassingDndByUser.put(userHandle.getIdentifier(),
                    mHelperBackend.getPackagesBypassingDnd(userHandle.getIdentifier()));
        }
        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) {
            boolean doesAppBypassDnd = false;
            int userId = UserHandle.getUserId(app.info.uid);
            Map<String, Boolean> packagesBypassingDnd =
                    packagesBypassingDndByUser.getOrDefault(userId, new HashMap<>());
            if (packagesBypassingDnd.containsKey(pkg)) {
                doAnyAppsPassCriteria = true;
                doesAppBypassDnd = true;
            }

            Preference pref = mPreferenceCategory.findPreference(key);
            if (pref == null) {
                if (appChannelsBypassingDnd > 0) {
                if (doesAppBypassDnd) {
                    // does not exist but should
                    pref = new AppPreference(mPrefContext);
                    pref.setKey(key);
@@ -172,14 +182,14 @@ public class ZenModeAllBypassingAppsPreferenceController extends AbstractPrefere
                    });
                    pref.setTitle(BidiFormatter.getInstance().unicodeWrap(app.label));
                    updateIcon(pref, app);
                    if (appChannels > appChannelsBypassingDnd) {
                        pref.setSummary(R.string.zen_mode_bypassing_apps_summary_some);
                    } else {
                    if (packagesBypassingDnd.get(pkg)) {
                        pref.setSummary(R.string.zen_mode_bypassing_apps_summary_all);
                    } else {
                        pref.setSummary(R.string.zen_mode_bypassing_apps_summary_some);
                    }
                    mPreferenceCategory.addPreference(pref);
                }
            } else if (appChannelsBypassingDnd == 0) {
            } else if (!doesAppBypassDnd) {
                // exists but shouldn't anymore
                mPreferenceCategory.removePreference(pref);
            }
+1 −2
Original line number Diff line number Diff line
@@ -161,8 +161,7 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
        Multimap<Integer, String> packagesBypassingDnd = HashMultimap.create();
        for (UserHandle userHandle : mUserManager.getUserProfiles()) {
            packagesBypassingDnd.putAll(userHandle.getIdentifier(),
                    mHelperBackend.getPackagesBypassingDnd(userHandle.getIdentifier(),
                            /* includeConversationChannels= */ false));
                    mHelperBackend.getPackagesBypassingDnd(userHandle.getIdentifier()).keySet());
        }

        return ImmutableList.copyOf(
+6 −4
Original line number Diff line number Diff line
@@ -48,15 +48,17 @@ public class ZenModeSelectBypassingAppsFragment extends ZenModeFragmentBase impl
        } else {
            app = null;
        }
        return buildPreferenceControllers(context, app, this, new NotificationBackend());
        return buildPreferenceControllers(context, app, this, new NotificationBackend(),
                new ZenHelperBackend(context));
    }

    private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
            @Nullable Application app, @Nullable Fragment host,
            @Nullable NotificationBackend notificationBackend) {
            @Nullable NotificationBackend notificationBackend,
            @Nullable ZenHelperBackend zenHelperBackend) {
        final List<AbstractPreferenceController> controllers = new ArrayList<>();
        controllers.add(new ZenModeAllBypassingAppsPreferenceController(context, app, host,
                notificationBackend));
                zenHelperBackend));
        controllers.add(new ZenModeAddBypassingAppsPreferenceController(context, app, host,
                notificationBackend));
        return controllers;
@@ -86,7 +88,7 @@ public class ZenModeSelectBypassingAppsFragment extends ZenModeFragmentBase impl
                @Override
                public List<AbstractPreferenceController> createPreferenceControllers(
                        Context context) {
                    return buildPreferenceControllers(context, null, null, null);
                    return buildPreferenceControllers(context, null, null, null, null);
                }
            };
}
+15 −11
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -28,10 +27,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.Flags;
import android.app.NotificationChannel;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ParceledListSlice;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;

@@ -39,7 +36,6 @@ import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;

import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.applications.ApplicationsState;

import org.junit.Before;
@@ -54,6 +50,7 @@ import org.robolectric.RuntimeEnvironment;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RunWith(RobolectricTestRunner.class)
@EnableFlags(Flags.FLAG_MODES_UI)
@@ -66,7 +63,7 @@ public class ZenModeAllBypassingAppsPreferenceControllerTest {

    private Context mContext;
    @Mock
    private NotificationBackend mBackend;
    private ZenHelperBackend mBackend;
    @Mock
    private PreferenceCategory mPreferenceCategory;
    @Mock
@@ -102,18 +99,25 @@ public class ZenModeAllBypassingAppsPreferenceControllerTest {
        entry2.info.packageName = "test2";
        entry2.info.uid = 0;

        ApplicationsState.AppEntry entry3= mock(ApplicationsState.AppEntry.class);
        entry3.info = new ApplicationInfo();
        entry3.info.packageName = "test3";
        entry3.info.uid = 0;

        List<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
        appEntries.add(entry1);
        appEntries.add(entry2);
        List<NotificationChannel> channelsBypassing = new ArrayList<>();
        channelsBypassing.add(mock(NotificationChannel.class));
        channelsBypassing.add(mock(NotificationChannel.class));
        when(mBackend.getNotificationChannelsBypassingDnd(anyString(),
                anyInt())).thenReturn(new ParceledListSlice<>(channelsBypassing));
        appEntries.add(entry3);
        when(mBackend.getPackagesBypassingDnd(anyInt())).thenReturn(
                Map.of("test", true, "test2", false));

        // THEN there's are two preferences
        mController.updateAppList(appEntries);
        verify(mPreferenceCategory, times(2)).addPreference(any());
        ArgumentCaptor<Preference> captor = ArgumentCaptor.forClass(Preference.class);
        verify(mPreferenceCategory, times(2)).addPreference(captor.capture());
        List<Preference> prefs = captor.getAllValues();
        assertThat(prefs.get(0).getSummary().toString()).isEqualTo("All notifications");
        assertThat(prefs.get(1).getSummary().toString()).isEqualTo("Some notifications");
    }

    @Test
Loading