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

Commit 1b0f9e4e authored by Matías Hernández's avatar Matías Hernández
Browse files

Fix calculation of areChannelsBypassingDnd

The value in PreferencesHelper might be wrong on boot (always false, because it was calculated before loading channel info) or after switching users (retained the value from the previous user). This situation would persist until a channel's priority was manually updated.

Also renamed the field in PreferencesHelper to make it clearer that the value corresponds to the current user.

Test: atest + manual
Fixes: 280848017
Change-Id: I1d20339f04f3b27404a0aaeffb563cc5023120d8
parent 066951a1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1021,6 +1021,7 @@ public class NotificationManagerService extends SystemService {
        }
        mAssistants.resetDefaultAssistantsIfNecessary();
        mPreferencesHelper.syncChannelsBypassingDnd();
    }
    @VisibleForTesting
@@ -1861,6 +1862,7 @@ public class NotificationManagerService extends SystemService {
                    mConditionProviders.onUserSwitched(userId);
                    mListeners.onUserSwitched(userId);
                    mZenModeHelper.onUserSwitched(userId);
                    mPreferencesHelper.syncChannelsBypassingDnd();
                }
                // assistant is the only thing that cares about managed profiles specifically
                mAssistants.onUserSwitched(userId);
+32 −26
Original line number Diff line number Diff line
@@ -202,7 +202,7 @@ public class PreferencesHelper implements RankingConfig {
    private SparseBooleanArray mLockScreenShowNotifications;
    private SparseBooleanArray mLockScreenPrivateNotifications;
    private boolean mIsMediaNotificationFilteringEnabled = DEFAULT_MEDIA_NOTIFICATION_FILTERING;
    private boolean mAreChannelsBypassingDnd;
    private boolean mCurrentUserHasChannelsBypassingDnd;
    private boolean mHideSilentStatusBarIcons = DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS;
    private boolean mShowReviewPermissionsNotification;

@@ -230,7 +230,6 @@ public class PreferencesHelper implements RankingConfig {
        updateBadgingEnabled();
        updateBubblesEnabled();
        updateMediaNotificationFilteringEnabled();
        syncChannelsBypassingDnd(Process.SYSTEM_UID, true);  // init comes from system
    }

    public void readXml(TypedXmlPullParser parser, boolean forRestore, int userId)
@@ -893,7 +892,7 @@ public class PreferencesHelper implements RankingConfig {
            r.groups.put(group.getId(), group);
        }
        if (needsDndChange) {
            updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
            updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
        }
    }

@@ -972,7 +971,7 @@ public class PreferencesHelper implements RankingConfig {
                        existing.setBypassDnd(bypassDnd);
                        needsPolicyFileChange = true;

                        if (bypassDnd != mAreChannelsBypassingDnd
                        if (bypassDnd != mCurrentUserHasChannelsBypassingDnd
                                || previousExistingImportance != existing.getImportance()) {
                            needsDndChange = true;
                        }
@@ -1031,7 +1030,7 @@ public class PreferencesHelper implements RankingConfig {
                }

                r.channels.put(channel.getId(), channel);
                if (channel.canBypassDnd() != mAreChannelsBypassingDnd) {
                if (channel.canBypassDnd() != mCurrentUserHasChannelsBypassingDnd) {
                    needsDndChange = true;
                }
                MetricsLogger.action(getChannelLog(channel, pkg).setType(
@@ -1041,7 +1040,7 @@ public class PreferencesHelper implements RankingConfig {
        }

        if (needsDndChange) {
            updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
            updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
        }

        return needsPolicyFileChange;
@@ -1127,14 +1126,14 @@ public class PreferencesHelper implements RankingConfig {
                // relevantly affected without the parent channel already having been.
            }

            if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
            if (updatedChannel.canBypassDnd() != mCurrentUserHasChannelsBypassingDnd
                    || channel.getImportance() != updatedChannel.getImportance()) {
                needsDndChange = true;
                changed = true;
            }
        }
        if (needsDndChange) {
            updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
            updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
        }
        if (changed) {
            updateConfig();
@@ -1321,7 +1320,7 @@ public class PreferencesHelper implements RankingConfig {
            }
        }
        if (channelBypassedDnd) {
            updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
            updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
        }
        return deletedChannel;
    }
@@ -1538,7 +1537,7 @@ public class PreferencesHelper implements RankingConfig {
            }
        }
        if (groupBypassedDnd) {
            updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
            updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
        }
        return deletedChannels;
    }
@@ -1685,8 +1684,8 @@ public class PreferencesHelper implements RankingConfig {
                }
            }
        }
        if (!deletedChannelIds.isEmpty() && mAreChannelsBypassingDnd) {
            updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
        if (!deletedChannelIds.isEmpty() && mCurrentUserHasChannelsBypassingDnd) {
            updateCurrentUserHasChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
        }
        return deletedChannelIds;
    }
@@ -1788,21 +1787,28 @@ public class PreferencesHelper implements RankingConfig {
    }

    /**
     * Syncs {@link #mAreChannelsBypassingDnd} with the current user's notification policy before
     * updating
     * Syncs {@link #mCurrentUserHasChannelsBypassingDnd} with the current user's notification
     * policy before updating. Must be called:
     * <ul>
     *     <li>On system init, after channels and DND configurations are loaded.</li>
     *     <li>When the current user changes, after the corresponding DND config is loaded.</li>
     * </ul>
     */
    private void syncChannelsBypassingDnd(int callingUid, boolean fromSystemOrSystemUi) {
        mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state
                & NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1;
    void syncChannelsBypassingDnd() {
        mCurrentUserHasChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state
                & NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) != 0;

        updateChannelsBypassingDnd(callingUid, fromSystemOrSystemUi);
        updateCurrentUserHasChannelsBypassingDnd(/* callingUid= */ Process.SYSTEM_UID,
                /* fromSystemOrSystemUi= */ true);
    }

    /**
     * Updates the user's NotificationPolicy based on whether the current userId
     * has channels bypassing DND
     * Updates the user's NotificationPolicy based on whether the current userId has channels
     * bypassing DND. It should be called whenever a channel is created, updated, or deleted, or
     * when the current user is switched.
     */
    private void updateChannelsBypassingDnd(int callingUid, boolean fromSystemOrSystemUi) {
    private void updateCurrentUserHasChannelsBypassingDnd(int callingUid,
            boolean fromSystemOrSystemUi) {
        ArraySet<Pair<String, Integer>> candidatePkgs = new ArraySet<>();

        final int currentUserId = getCurrentUser();
@@ -1817,7 +1823,7 @@ public class PreferencesHelper implements RankingConfig {

                for (NotificationChannel channel : r.channels.values()) {
                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                        candidatePkgs.add(new Pair(r.pkg, r.uid));
                        candidatePkgs.add(new Pair<>(r.pkg, r.uid));
                        break;
                    }
                }
@@ -1830,9 +1836,9 @@ public class PreferencesHelper implements RankingConfig {
            }
        }
        boolean haveBypassingApps = candidatePkgs.size() > 0;
        if (mAreChannelsBypassingDnd != haveBypassingApps) {
            mAreChannelsBypassingDnd = haveBypassingApps;
            updateZenPolicy(mAreChannelsBypassingDnd, callingUid, fromSystemOrSystemUi);
        if (mCurrentUserHasChannelsBypassingDnd != haveBypassingApps) {
            mCurrentUserHasChannelsBypassingDnd = haveBypassingApps;
            updateZenPolicy(mCurrentUserHasChannelsBypassingDnd, callingUid, fromSystemOrSystemUi);
        }
    }

@@ -1869,7 +1875,7 @@ public class PreferencesHelper implements RankingConfig {
    }

    public boolean areChannelsBypassingDnd() {
        return mAreChannelsBypassingDnd;
        return mCurrentUserHasChannelsBypassingDnd;
    }

    /**
+20 −0
Original line number Diff line number Diff line
@@ -422,6 +422,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    @Mock
    MultiRateLimiter mToastRateLimiter;
    BroadcastReceiver mPackageIntentReceiver;
    BroadcastReceiver mUserSwitchIntentReceiver;
    NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
    TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
@@ -652,8 +653,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                    && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
                mPackageIntentReceiver = broadcastReceivers.get(i);
            }
            if (filter.hasAction(Intent.ACTION_USER_SWITCHED)) {
                mUserSwitchIntentReceiver = broadcastReceivers.get(i);
            }
        }
        assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
        assertNotNull("User-switch receiver should exist", mUserSwitchIntentReceiver);
        // Pretend the shortcut exists
        List<ShortcutInfo> shortcutInfos = new ArrayList<>();
@@ -12174,6 +12179,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
    }
    @Test
    public void onUserSwitched_updatesZenModeAndChannelsBypassingDnd() {
        Intent intent = new Intent(Intent.ACTION_USER_SWITCHED);
        intent.putExtra(Intent.EXTRA_USER_HANDLE, 20);
        mService.mZenModeHelper = mock(ZenModeHelper.class);
        mService.setPreferencesHelper(mPreferencesHelper);
        mUserSwitchIntentReceiver.onReceive(mContext, intent);
        InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
        inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
        inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd();
        inOrder.verifyNoMoreInteractions();
    }
    private static <T extends Parcelable> T parcelAndUnparcel(T source,
            Parcelable.Creator<T> creator) {
        Parcel parcel = Parcel.obtain();
+4 −1
Original line number Diff line number Diff line
@@ -2478,7 +2478,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                mPermissionHelper, mPermissionManager, mLogger,
                mAppOpsManager, mStatsEventBuilderFactory, false);

        mHelper.syncChannelsBypassingDnd();

        // create notification channel that can bypass dnd, but app is blocked
        // expected result: areChannelsBypassingDnd = false
@@ -2509,6 +2509,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                mPermissionHelper, mPermissionManager, mLogger,
                mAppOpsManager, mStatsEventBuilderFactory, false);
        mHelper.syncChannelsBypassingDnd();

        // create notification channel that can bypass dnd, but app is blocked
        // expected result: areChannelsBypassingDnd = false
@@ -2533,6 +2534,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                mPermissionHelper, mPermissionManager, mLogger,
                mAppOpsManager, mStatsEventBuilderFactory, false);
        mHelper.syncChannelsBypassingDnd();

        // create notification channel that can bypass dnd, but app is blocked
        // expected result: areChannelsBypassingDnd = false
@@ -2587,6 +2589,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                mPermissionHelper, mPermissionManager, mLogger,
                mAppOpsManager, mStatsEventBuilderFactory, false);
        mHelper.syncChannelsBypassingDnd();
        assertFalse(mHelper.areChannelsBypassingDnd());
        verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyBoolean());
        resetZenModeHelper();