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

Commit 55f7f698 authored by Jahdiel Alvarez's avatar Jahdiel Alvarez
Browse files

Refactored NMS to handle user switch via the onUserSwitching method

The NotificationManagerService listens for user switch events via the
ACTION_USER_SWITCHED broadcast intent. This change refactors the logic
to handle user switch events by overriding SystemService's
onUserSwitching method. The onUserSwitching method is an earlier and
more stable signal for user switch than the broadcast. SystemServices
should rely on SystemService user lifecycle methods for user-aware
operations.

With respect to the stopping previous user apps feature, this results
in the early killing ocurring after NotificationManagerService has
handled the user switch events, which avoids it from restarting early
killed packages.

Test: atest NotificationManagerServiceTest
Test: Manually run user switch on device
Bug: 337077643
Bug: 323200731
Change-Id: I90c2ecb2fcfd0693bdc6c01aa9f4b83705e56ce8
parent 22ed7392
Loading
Loading
Loading
Loading
+38 −15
Original line number Diff line number Diff line
@@ -245,7 +245,6 @@ import android.os.DeadObjectException;
import android.os.DeviceIdleManager;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IInterface;
@@ -2038,6 +2037,7 @@ public class NotificationManagerService extends SystemService {
                    mSnoozeHelper.clearData(userHandle);
                }
            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
                if (!Flags.useSsmUserSwitchSignal()) {
                    final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                    mUserProfiles.updateCache(context);
                    if (!mUserProfiles.isProfileUser(userId, context)) {
@@ -2051,6 +2051,7 @@ public class NotificationManagerService extends SystemService {
                    }
                    // assistant is the only thing that cares about managed profiles specifically
                    mAssistants.onUserSwitched(userId);
                }
            } else if (action.equals(Intent.ACTION_USER_ADDED)) {
                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                if (userId != USER_NULL) {
@@ -2570,7 +2571,9 @@ public class NotificationManagerService extends SystemService {
        // calling onDestroy()
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_USER_STOPPED);
        if (!Flags.useSsmUserSwitchSignal()) {
            filter.addAction(Intent.ACTION_USER_SWITCHED);
        }
        filter.addAction(Intent.ACTION_USER_ADDED);
        filter.addAction(Intent.ACTION_USER_REMOVED);
        filter.addAction(Intent.ACTION_USER_UNLOCKED);
@@ -2965,6 +2968,26 @@ public class NotificationManagerService extends SystemService {
        }, 500);
    }
    @Override
    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
        if (!Flags.useSsmUserSwitchSignal()) {
            return;
        }
        final int userId = to.getUserIdentifier();
        mUserProfiles.updateCache(getContext());
        if (!mUserProfiles.isProfileUser(userId, getContext())) {
            // reload per-user settings
            mSettingsObserver.update(null);
            // Refresh managed services
            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);
    }
    @Override
    public void onUserStopping(@NonNull TargetUser user) {
        mHandler.post(() -> {
+7 −0
Original line number Diff line number Diff line
@@ -128,3 +128,10 @@ flag {
  description: "Adds an IPCDataCache for notification channel/group lookups"
  bug: "331677193"
}

flag {
  name: "use_ssm_user_switch_signal"
  namespace: "systemui"
  description: "This flag controls which signal is used to handle a user switch system event"
  bug: "337077643"
}
+28 −7
Original line number Diff line number Diff line
@@ -341,7 +341,6 @@ import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
@@ -503,7 +502,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    @Mock
    MultiRateLimiter mToastRateLimiter;
    BroadcastReceiver mPackageIntentReceiver;
    BroadcastReceiver mUserSwitchIntentReceiver;
    BroadcastReceiver mUserIntentReceiver;
    BroadcastReceiver mNotificationTimeoutReceiver;
    NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
    TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
@@ -802,11 +801,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                    && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
                mPackageIntentReceiver = broadcastReceivers.get(i);
            }
            if (filter.hasAction(Intent.ACTION_USER_SWITCHED)) {
            if (filter.hasAction(Intent.ACTION_USER_SWITCHED)
                    || filter.hasAction(Intent.ACTION_PROFILE_UNAVAILABLE)
                    || filter.hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
                // There may be multiple receivers, get the NMS one
                if (broadcastReceivers.get(i).toString().contains(
                        NotificationManagerService.class.getName())) {
                    mUserSwitchIntentReceiver = broadcastReceivers.get(i);
                    mUserIntentReceiver = broadcastReceivers.get(i);
                }
            }
            if (filter.hasAction(ACTION_NOTIFICATION_TIMEOUT)
@@ -815,7 +816,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
            }
        }
        assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
        assertNotNull("User-switch receiver should exist", mUserSwitchIntentReceiver);
        assertNotNull("User receiver should exist", mUserIntentReceiver);
        if (!Flags.allNotifsNeedTtl()) {
            assertNotNull("Notification timeout receiver should exist",
                    mNotificationTimeoutReceiver);
@@ -976,7 +977,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    private void simulateProfileAvailabilityActions(String intentAction) {
        final Intent intent = new Intent(intentAction);
        intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE);
        mUserSwitchIntentReceiver.onReceive(mContext, intent);
        mUserIntentReceiver.onReceive(mContext, intent);
    }
    private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() {
@@ -14482,13 +14483,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    }
    @Test
    @EnableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
    public void onUserSwitched_updatesZenModeAndChannelsBypassingDnd() {
        mService.mZenModeHelper = mock(ZenModeHelper.class);
        mService.setPreferencesHelper(mPreferencesHelper);
        UserInfo prevUser = new UserInfo();
        prevUser.id = 10;
        UserInfo newUser = new UserInfo();
        newUser.id = 20;
        mService.onUserSwitching(new TargetUser(prevUser), new TargetUser(newUser));
        InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
        inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));
        inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd();
        inOrder.verifyNoMoreInteractions();
    }
    @Test
    @DisableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL)
    public void onUserSwitched_broadcast_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);
        mUserIntentReceiver.onReceive(mContext, intent);
        InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper);
        inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20));