diff options
| author | 2022-02-08 02:43:16 +0000 | |
|---|---|---|
| committer | 2022-02-08 02:48:59 +0000 | |
| commit | b090c961ee55720f5abddf57fb57b3d7639c966e (patch) | |
| tree | 5624b90b8d71221c0cbd6f08d1b41a371bfc9770 | |
| parent | 3747c15a65148a9579bf3773457afb48e5e1f575 (diff) | |
Change HeadsUpManagerPhone to use VisualStabilityProvider
Fixes: 218371335
Test: atest VisualStabilityProviderTest
Change-Id: I74f5dddecfa83ba3def93e68c553149ca2525dd1
8 files changed, 217 insertions, 28 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java index 6c52b5e8de1c..a17873869691 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java @@ -49,6 +49,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; @@ -174,6 +175,7 @@ public abstract class SystemUIDefaultModule { StatusBarStateController statusBarStateController, KeyguardBypassController bypassController, GroupMembershipManager groupManager, + VisualStabilityProvider visualStabilityProvider, ConfigurationController configurationController) { return new HeadsUpManagerPhone( context, @@ -181,6 +183,7 @@ public abstract class SystemUIDefaultModule { statusBarStateController, bypassController, groupManager, + visualStabilityProvider, configurationController ); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt index 3f866fe63f1d..5adf31b75fa7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProvider.kt @@ -1,25 +1,57 @@ package com.android.systemui.statusbar.notification.collection.provider +import android.util.ArraySet import com.android.systemui.dagger.SysUISingleton import com.android.systemui.util.ListenerSet import javax.inject.Inject @SysUISingleton class VisualStabilityProvider @Inject constructor() { - private val listeners = ListenerSet<OnReorderingAllowedListener>() + /** All persistent and temporary listeners, in the order they were added */ + private val allListeners = ListenerSet<OnReorderingAllowedListener>() + + /** The subset of active listeners which are temporary (will be removed after called) */ + private val temporaryListeners = ArraySet<OnReorderingAllowedListener>() var isReorderingAllowed = true set(value) { if (field != value) { field = value if (value) { - listeners.forEach(OnReorderingAllowedListener::onReorderingAllowed) + notifyReorderingAllowed() } } } - fun addPersistentReorderingAllowedListener(listener: OnReorderingAllowedListener) = - listeners.addIfAbsent(listener) + private fun notifyReorderingAllowed() { + allListeners.forEach { listener -> + if (temporaryListeners.remove(listener)) { + allListeners.remove(listener) + } + listener.onReorderingAllowed() + } + } + + /** Add a listener which will be called until it is explicitly removed. */ + fun addPersistentReorderingAllowedListener(listener: OnReorderingAllowedListener) { + temporaryListeners.remove(listener) + allListeners.addIfAbsent(listener) + } + + /** Add a listener which will be removed when it is called. */ + fun addTemporaryReorderingAllowedListener(listener: OnReorderingAllowedListener) { + // Only add to the temporary set if it was added to the global set + // to keep permanent listeners permanent + if (allListeners.addIfAbsent(listener)) { + temporaryListeners.add(listener) + } + } + + /** Remove a listener from receiving any callbacks, whether it is persistent or temporary. */ + fun removeReorderingAllowedListener(listener: OnReorderingAllowedListener) { + temporaryListeners.remove(listener) + allListeners.remove(listener) + } } fun interface OnReorderingAllowedListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 77cff344558f..2a76418b1f03 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -33,7 +33,8 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener; +import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -52,7 +53,7 @@ import java.util.Stack; * A implementation of HeadsUpManager for phone and car. */ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, - VisualStabilityManager.Callback, OnHeadsUpChangedListener { + OnHeadsUpChangedListener { private static final String TAG = "HeadsUpManagerPhone"; @VisibleForTesting @@ -60,8 +61,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, private final KeyguardBypassController mBypassController; private final GroupMembershipManager mGroupMembershipManager; private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>(); - // TODO (b/162832756): remove visual stability manager when migrating to new pipeline - private VisualStabilityManager mVisualStabilityManager; + private final VisualStabilityProvider mVisualStabilityProvider; private boolean mReleaseOnExpandFinish; private boolean mTrackingHeadsUp; @@ -104,6 +104,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, StatusBarStateController statusBarStateController, KeyguardBypassController bypassController, GroupMembershipManager groupMembershipManager, + VisualStabilityProvider visualStabilityProvider, ConfigurationController configurationController) { super(context, logger); Resources resources = mContext.getResources(); @@ -111,6 +112,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, statusBarStateController.addCallback(mStatusBarStateListener); mBypassController = bypassController; mGroupMembershipManager = groupMembershipManager; + mVisualStabilityProvider = visualStabilityProvider; updateResources(); configurationController.addCallback(new ConfigurationController.ConfigurationListener() { @@ -126,10 +128,6 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, }); } - void setup(VisualStabilityManager visualStabilityManager) { - mVisualStabilityManager = visualStabilityManager; - } - public void setAnimationStateHandler(AnimationStateHandler handler) { mAnimationStateHandler = handler; } @@ -333,14 +331,13 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, // We should not defer the removal if reordering isn't allowed since otherwise // these won't disappear until reordering is allowed again, which happens only once // the notification panel is collapsed again. - return mVisualStabilityManager.isReorderingAllowed() && super.shouldExtendLifetime(entry); + return mVisualStabilityProvider.isReorderingAllowed() && super.shouldExtendLifetime(entry); } /////////////////////////////////////////////////////////////////////////////////////////////// - // VisualStabilityManager.Callback overrides: + // OnReorderingAllowedListener: - @Override - public void onChangeAllowed() { + private final OnReorderingAllowedListener mOnReorderingAllowedListener = () -> { mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false); for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) { if (isAlerting(entry.getKey())) { @@ -350,7 +347,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, } mEntriesToRemoveWhenReorderingAllowed.clear(); mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true); - } + }; /////////////////////////////////////////////////////////////////////////////////////////////// // HeadsUpManager utility (protected) methods overrides: @@ -431,13 +428,13 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, public void setEntry(@NonNull final NotificationEntry entry) { Runnable removeHeadsUpRunnable = () -> { - if (!mVisualStabilityManager.isReorderingAllowed() + if (!mVisualStabilityProvider.isReorderingAllowed() // We don't want to allow reordering while pulsing, but headsup need to // time out anyway && !entry.showingPulsing()) { mEntriesToRemoveWhenReorderingAllowed.add(entry); - mVisualStabilityManager.addReorderingAllowedCallback(HeadsUpManagerPhone.this, - false /* persistent */); + mVisualStabilityProvider.addTemporaryReorderingAllowedListener( + mOnReorderingAllowedListener); } else if (mTrackingHeadsUp) { mEntriesToRemoveAfterExpand.add(entry); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index c8cc807475f3..4748d9c4fa71 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1185,10 +1185,11 @@ public class StatusBar extends CoreStartable implements }); initializer.initializeStatusBar(mStatusBarComponent); - mHeadsUpManager.setup(mVisualStabilityManager); mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView); mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener()); - mHeadsUpManager.addListener(mVisualStabilityManager); + if (!mNotifPipelineFlags.isNewPipelineEnabled()) { + mHeadsUpManager.addListener(mVisualStabilityManager); + } mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); createNavigationBar(result); diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java index 66fc9ac15857..b7f90a479518 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java @@ -50,6 +50,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; @@ -167,6 +168,7 @@ public abstract class TvSystemUIModule { StatusBarStateController statusBarStateController, KeyguardBypassController bypassController, GroupMembershipManager groupManager, + VisualStabilityProvider visualStabilityProvider, ConfigurationController configurationController) { return new HeadsUpManagerPhone( context, @@ -174,6 +176,7 @@ public abstract class TvSystemUIModule { statusBarStateController, bypassController, groupManager, + visualStabilityProvider, configurationController ); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt new file mode 100644 index 000000000000..b56f8e9364c4 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.collection.provider + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.mock +import org.junit.After +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.never +import org.mockito.Mockito.spy +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class VisualStabilityProviderTest : SysuiTestCase() { + private val visualStabilityProvider = VisualStabilityProvider() + private val listener: OnReorderingAllowedListener = mock() + + @After + fun tearDown() { + // Verify that every interaction is verified in every test + verifyNoMoreInteractions(listener) + } + + @Test + fun testPersistentListenerIgnoredIfStateNotChanged() { + visualStabilityProvider.addPersistentReorderingAllowedListener(listener) + visualStabilityProvider.isReorderingAllowed = true + verify(listener, never()).onReorderingAllowed() + } + + @Test + fun testPersistentListenerCalledTwice() { + visualStabilityProvider.addPersistentReorderingAllowedListener(listener) + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, times(1)).onReorderingAllowed() + + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, times(2)).onReorderingAllowed() + } + + @Test + fun testTemporaryListenerCalledOnce() { + visualStabilityProvider.addTemporaryReorderingAllowedListener(listener) + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, times(1)).onReorderingAllowed() + + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, times(1)).onReorderingAllowed() + } + + @Test + fun testPersistentListenerCanBeRemoved() { + visualStabilityProvider.addPersistentReorderingAllowedListener(listener) + visualStabilityProvider.removeReorderingAllowedListener(listener) + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, never()).onReorderingAllowed() + } + + @Test + fun testTemporaryListenerCanBeRemoved() { + visualStabilityProvider.addTemporaryReorderingAllowedListener(listener) + visualStabilityProvider.removeReorderingAllowedListener(listener) + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, never()).onReorderingAllowed() + } + + @Test + fun testPersistentListenerStaysPersistent() { + visualStabilityProvider.addPersistentReorderingAllowedListener(listener) + visualStabilityProvider.addTemporaryReorderingAllowedListener(listener) + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, times(1)).onReorderingAllowed() + + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, times(2)).onReorderingAllowed() + } + + @Test + fun testTemporaryListenerBecomesPersistent() { + visualStabilityProvider.addTemporaryReorderingAllowedListener(listener) + visualStabilityProvider.addPersistentReorderingAllowedListener(listener) + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, times(1)).onReorderingAllowed() + + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(listener, times(2)).onReorderingAllowed() + } + + @Test + fun testPersistentListenerCanRemoveSelf() { + val selfRemovingListener = spy(object : OnReorderingAllowedListener { + override fun onReorderingAllowed() { + visualStabilityProvider.removeReorderingAllowedListener(this) + } + }) + visualStabilityProvider.addPersistentReorderingAllowedListener(selfRemovingListener) + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(selfRemovingListener, times(1)).onReorderingAllowed() + + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(selfRemovingListener, times(1)).onReorderingAllowed() + } + + @Test + fun testTemporaryListenerCanReAddSelf() { + val selfAddingListener = spy(object : OnReorderingAllowedListener { + override fun onReorderingAllowed() { + visualStabilityProvider.addTemporaryReorderingAllowedListener(this) + } + }) + visualStabilityProvider.addTemporaryReorderingAllowedListener(selfAddingListener) + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(selfAddingListener, times(1)).onReorderingAllowed() + + visualStabilityProvider.isReorderingAllowed = false + visualStabilityProvider.isReorderingAllowed = true + verify(selfAddingListener, times(2)).onReorderingAllowed() + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 4457ae046260..72f8f70058fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -60,6 +60,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.icon.IconBuilder; import com.android.systemui.statusbar.notification.icon.IconManager; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; @@ -139,6 +140,7 @@ public class NotificationTestHelper { mStatusBarStateController, mock(KeyguardBypassController.class), mock(NotificationGroupManagerLegacy.class), + mock(VisualStabilityProvider.class), mock(ConfigurationControllerImpl.class) ); mHeadsUpManager.mHandler.removeCallbacksAndMessages(null); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index e8b9c7b4d289..421d8f6a1889 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -36,7 +36,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; -import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManagerLogger; @@ -62,7 +62,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { @Mock private HeadsUpManagerLogger mHeadsUpManagerLogger; @Mock private NotificationGroupManagerLegacy mGroupManager; @Mock private View mNotificationShadeWindowView; - @Mock private VisualStabilityManager mVSManager; + @Mock private VisualStabilityProvider mVSProvider; @Mock private StatusBar mBar; @Mock private StatusBarStateController mStatusBarStateController; @Mock private KeyguardBypassController mBypassController; @@ -74,7 +74,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { Context context, HeadsUpManagerLogger headsUpManagerLogger, NotificationGroupManagerLegacy groupManager, - VisualStabilityManager vsManager, + VisualStabilityProvider visualStabilityProvider, StatusBarStateController statusBarStateController, KeyguardBypassController keyguardBypassController, ConfigurationController configurationController @@ -85,9 +85,9 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { statusBarStateController, keyguardBypassController, groupManager, + visualStabilityProvider, configurationController ); - setup(vsManager); mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME; mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME; } @@ -103,14 +103,14 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { mDependency.injectMockDependency(AccessibilityManagerWrapper.class); when(accessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt())) .thenReturn(TEST_AUTO_DISMISS_TIME); - when(mVSManager.isReorderingAllowed()).thenReturn(true); + when(mVSProvider.isReorderingAllowed()).thenReturn(true); mDependency.injectMockDependency(NotificationShadeWindowController.class); mDependency.injectMockDependency(ConfigurationController.class); mHeadsUpManager = new TestableHeadsUpManagerPhone( mContext, mHeadsUpManagerLogger, mGroupManager, - mVSManager, + mVSProvider, mStatusBarStateController, mBypassController, mConfigurationController |