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

Commit 7fb9bfcc authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Ignore notification update for not active user" into tm-qpr-dev

parents 5c002a64 8b9b0c9e
Loading
Loading
Loading
Loading
+64 −13
Original line number Diff line number Diff line
@@ -70,12 +70,10 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseSetArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -109,8 +107,10 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
@@ -177,8 +177,8 @@ public class BubbleController implements ConfigurationChangeListener {
    private int mCurrentUserId;
    // Current profiles of the user (e.g. user with a workprofile)
    private SparseArray<UserInfo> mCurrentProfiles;
    // Saves notification keys of active bubbles when users are switched.
    private final SparseSetArray<String> mSavedBubbleKeysPerUser;
    // Saves data about active bubbles when users are switched.
    private final SparseArray<UserBubbleData> mSavedUserBubbleData;

    // Used when ranking updates occur and we check if things should bubble / unbubble
    private NotificationListenerService.Ranking mTmpRanking;
@@ -271,7 +271,7 @@ public class BubbleController implements ConfigurationChangeListener {
        mCurrentUserId = ActivityManager.getCurrentUser();
        mBubblePositioner = positioner;
        mBubbleData = data;
        mSavedBubbleKeysPerUser = new SparseSetArray<>();
        mSavedUserBubbleData = new SparseArray<>();
        mBubbleIconFactory = new BubbleIconFactory(context);
        mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(context);
        mDisplayController = displayController;
@@ -420,6 +420,13 @@ public class BubbleController implements ConfigurationChangeListener {
        List<UserInfo> users = mUserManager.getAliveUsers();
        mDataRepository.sanitizeBubbles(users);

        // Init profiles
        SparseArray<UserInfo> userProfiles = new SparseArray<>();
        for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
            userProfiles.put(user.id, user);
        }
        mCurrentProfiles = userProfiles;

        mShellController.addConfigurationChangeListener(this);
    }

@@ -774,11 +781,13 @@ public class BubbleController implements ConfigurationChangeListener {
     */
    private void saveBubbles(@UserIdInt int userId) {
        // First clear any existing keys that might be stored.
        mSavedBubbleKeysPerUser.remove(userId);
        mSavedUserBubbleData.remove(userId);
        UserBubbleData userBubbleData = new UserBubbleData();
        // Add in all active bubbles for the current user.
        for (Bubble bubble : mBubbleData.getBubbles()) {
            mSavedBubbleKeysPerUser.add(userId, bubble.getKey());
            userBubbleData.add(bubble.getKey(), bubble.showInShade());
        }
        mSavedUserBubbleData.put(userId, userBubbleData);
    }

    /**
@@ -787,22 +796,23 @@ public class BubbleController implements ConfigurationChangeListener {
     * @param userId the id of the user
     */
    private void restoreBubbles(@UserIdInt int userId) {
        ArraySet<String> savedBubbleKeys = mSavedBubbleKeysPerUser.get(userId);
        if (savedBubbleKeys == null) {
        UserBubbleData savedBubbleData = mSavedUserBubbleData.get(userId);
        if (savedBubbleData == null) {
            // There were no bubbles saved for this used.
            return;
        }
        mSysuiProxy.getShouldRestoredEntries(savedBubbleKeys, (entries) -> {
        mSysuiProxy.getShouldRestoredEntries(savedBubbleData.getKeys(), (entries) -> {
            mMainExecutor.execute(() -> {
                for (BubbleEntry e : entries) {
                    if (canLaunchInTaskView(mContext, e)) {
                        updateBubble(e, true /* suppressFlyout */, false /* showInShade */);
                        boolean showInShade = savedBubbleData.isShownInShade(e.getKey());
                        updateBubble(e, true /* suppressFlyout */, showInShade);
                    }
                }
            });
        });
        // Finally, remove the entries for this user now that bubbles are restored.
        mSavedBubbleKeysPerUser.remove(userId);
        mSavedUserBubbleData.remove(userId);
    }

    @Override
@@ -993,7 +1003,19 @@ public class BubbleController implements ConfigurationChangeListener {
     */
    @VisibleForTesting
    public void updateBubble(BubbleEntry notif) {
        int bubbleUserId = notif.getStatusBarNotification().getUserId();
        if (isCurrentProfile(bubbleUserId)) {
            updateBubble(notif, false /* suppressFlyout */, true /* showInShade */);
        } else {
            // Skip update, but store it in user bubbles so it gets restored after user switch
            mSavedUserBubbleData.get(bubbleUserId, new UserBubbleData()).add(notif.getKey(),
                    true /* shownInShade */);
            if (DEBUG_BUBBLE_CONTROLLER) {
                Log.d(TAG,
                        "Ignore update to bubble for not active user. Bubble userId=" + bubbleUserId
                                + " current userId=" + mCurrentUserId);
            }
        }
    }

    /**
@@ -1842,4 +1864,33 @@ public class BubbleController implements ConfigurationChangeListener {
            }
        }
    }

    /**
     * Bubble data that is stored per user.
     * Used to store and restore active bubbles during user switching.
     */
    private static class UserBubbleData {
        private final Map<String, Boolean> mKeyToShownInShadeMap = new HashMap<>();

        /**
         * Add bubble key and whether it should be shown in notification shade
         */
        void add(String key, boolean shownInShade) {
            mKeyToShownInShadeMap.put(key, shownInShade);
        }

        /**
         * Get all bubble keys stored for this user
         */
        Set<String> getKeys() {
            return mKeyToShownInShadeMap.keySet();
        }

        /**
         * Check if this bubble with the given key should be shown in the notification shade
         */
        boolean isShownInShade(String key) {
            return mKeyToShownInShadeMap.get(key);
        }
    }
}
+2 −3
Original line number Diff line number Diff line
@@ -23,12 +23,10 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.app.NotificationChannel;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
import android.util.ArraySet;
import android.util.Pair;
import android.util.SparseArray;

@@ -42,6 +40,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
@@ -284,7 +283,7 @@ public interface Bubbles {

        void getPendingOrActiveEntry(String key, Consumer<BubbleEntry> callback);

        void getShouldRestoredEntries(ArraySet<String> savedBubbleKeys,
        void getShouldRestoredEntries(Set<String> savedBubbleKeys,
                Consumer<List<BubbleEntry>> callback);

        void setNotificationInterruption(String key);
+2 −2
Original line number Diff line number Diff line
@@ -40,7 +40,6 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.ZenModeConfig;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -83,6 +82,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
@@ -262,7 +262,7 @@ public class BubblesManager implements Dumpable {
            }

            @Override
            public void getShouldRestoredEntries(ArraySet<String> savedBubbleKeys,
            public void getShouldRestoredEntries(Set<String> savedBubbleKeys,
                    Consumer<List<BubbleEntry>> callback) {
                sysuiMainExecutor.execute(() -> {
                    List<BubbleEntry> result = new ArrayList<>();
+54 −2
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.Notification;
@@ -143,7 +144,10 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
@@ -252,6 +256,8 @@ public class BubblesTest extends SysuiTestCase {
    private TaskViewTransitions mTaskViewTransitions;
    @Mock
    private Optional<OneHandedController> mOneHandedOptional;
    @Mock
    private UserManager mUserManager;

    private TestableBubblePositioner mPositioner;

@@ -314,6 +320,9 @@ public class BubblesTest extends SysuiTestCase {
        mPositioner.setMaxBubbles(5);
        mBubbleData = new BubbleData(mContext, mBubbleLogger, mPositioner, syncExecutor);

        when(mUserManager.getProfiles(ActivityManager.getCurrentUser())).thenReturn(
                Collections.singletonList(mock(UserInfo.class)));

        TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
                new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
                        mock(PowerManager.class),
@@ -339,7 +348,7 @@ public class BubblesTest extends SysuiTestCase {
                mStatusBarService,
                mWindowManager,
                mWindowManagerShellWrapper,
                mock(UserManager.class),
                mUserManager,
                mLauncherApps,
                mBubbleLogger,
                mTaskStackListener,
@@ -1025,7 +1034,7 @@ public class BubblesTest extends SysuiTestCase {
        assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry2.getKey())).isNotNull();

        // Switch users
        mBubbleController.onUserChanged(secondUserId);
        switchUser(secondUserId);
        assertThat(mBubbleData.getOverflowBubbles()).isEmpty();

        // Give this user some bubbles
@@ -1042,6 +1051,41 @@ public class BubblesTest extends SysuiTestCase {
        verify(mDataRepository, times(2)).loadBubbles(anyInt(), any());
    }

    @Test
    public void testOnUserChanged_bubblesRestored() {
        int firstUserId = mBubbleEntry.getStatusBarNotification().getUser().getIdentifier();
        int secondUserId = mBubbleEntryUser11.getStatusBarNotification().getUser().getIdentifier();
        // Mock current profile
        when(mLockscreenUserManager.isCurrentProfile(firstUserId)).thenReturn(true);
        when(mLockscreenUserManager.isCurrentProfile(secondUserId)).thenReturn(false);

        mBubbleController.updateBubble(mBubbleEntry);
        assertThat(mBubbleController.hasBubbles()).isTrue();
        // We start with 1 bubble
        assertThat(mBubbleData.getBubbles()).hasSize(1);

        // Switch to second user
        switchUser(secondUserId);

        // Second user has no bubbles
        assertThat(mBubbleController.hasBubbles()).isFalse();

        // Send bubble update for first user, ensure it does not show up
        mBubbleController.updateBubble(mBubbleEntry2);
        assertThat(mBubbleController.hasBubbles()).isFalse();

        // Start returning notif for first user again
        when(mCommonNotifCollection.getAllNotifs()).thenReturn(Arrays.asList(mRow, mRow2));

        // Switch back to first user
        switchUser(firstUserId);

        // Check we now have two bubbles, one previous and one new that came in
        assertThat(mBubbleController.hasBubbles()).isTrue();
        // Now there are 2 bubbles
        assertThat(mBubbleData.getBubbles()).hasSize(2);
    }

    /**
     * Verifies we only load the overflow data once.
     */
@@ -1443,6 +1487,14 @@ public class BubblesTest extends SysuiTestCase {
                .build();
    }

    private void switchUser(int userId) {
        when(mLockscreenUserManager.isCurrentProfile(anyInt())).thenAnswer(
                (Answer<Boolean>) invocation -> invocation.<Integer>getArgument(0) == userId);
        SparseArray<UserInfo> userInfos = new SparseArray<>(1);
        userInfos.put(userId, mock(UserInfo.class));
        mBubbleController.onCurrentProfilesChanged(userInfos);
        mBubbleController.onUserChanged(userId);
    }

    /**
     * Asserts that the bubble stack is expanded and also validates the cached state is updated.