From bb7dc5afcb5085e4f0e733fbd0e250ec2779563f Mon Sep 17 00:00:00 2001 From: Caitlin Cassidy Date: Tue, 28 Dec 2021 16:53:34 +0000 Subject: [PATCH 1/4] [Status Bar Refactor] Pass status bar view's controller to NotificationShadeWindowViewController instead of the view itself. Bug: 209005990 Test: new NotificationShadeWindowViewControllerTest Change-Id: I6303fb934701a88f7ce52e5e73e8d3df5f18fed8 --- ...NotificationShadeWindowViewController.java | 28 +-- .../phone/PhoneStatusBarViewController.kt | 25 ++ .../systemui/statusbar/phone/StatusBar.java | 3 +- ...tificationShadeWindowViewControllerTest.kt | 238 ++++++++++++++++++ .../phone/PhoneStatusBarViewControllerTest.kt | 84 ++++++- 5 files changed, 353 insertions(+), 25 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java index a6980a45aa27c..879e6943dce08 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import android.app.StatusBarManager; -import android.graphics.RectF; import android.hardware.display.AmbientDisplayConfiguration; import android.media.AudioManager; import android.media.session.MediaSessionLegacyHelper; @@ -75,7 +74,7 @@ public class NotificationShadeWindowViewController { private boolean mTouchCancelled; private boolean mExpandAnimationRunning; private NotificationStackScrollLayout mStackScrollLayout; - private PhoneStatusBarView mStatusBarView; + private PhoneStatusBarViewController mStatusBarViewController; private StatusBar mService; private NotificationShadeWindowController mNotificationShadeWindowController; private DragDownHelper mDragDownHelper; @@ -86,8 +85,6 @@ public class NotificationShadeWindowViewController { private final NotificationPanelViewController mNotificationPanelViewController; private final PanelExpansionStateManager mPanelExpansionStateManager; - // Used for determining view / touch intersection - private final RectF mTempRect = new RectF(); private boolean mIsTrackingBarGesture = false; @Inject @@ -175,7 +172,7 @@ public class NotificationShadeWindowViewController { mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() { @Override public Boolean handleDispatchTouchEvent(MotionEvent ev) { - if (mStatusBarView == null) { + if (mStatusBarViewController == null) { // Fix for b/192490822 Log.w(TAG, "Ignoring touch while statusBarView not yet set."); return false; } @@ -243,27 +240,27 @@ public class NotificationShadeWindowViewController { expandingBelowNotch = true; } if (expandingBelowNotch) { - return mStatusBarView.dispatchTouchEvent(ev); + return mStatusBarViewController.sendTouchToView(ev); } if (!mIsTrackingBarGesture && isDown && mNotificationPanelViewController.isFullyCollapsed()) { float x = ev.getRawX(); float y = ev.getRawY(); - if (isIntersecting(mStatusBarView, x, y)) { + if (mStatusBarViewController.touchIsWithinView(x, y)) { if (mService.isSameStatusBarState(WINDOW_STATE_SHOWING)) { mIsTrackingBarGesture = true; - return mStatusBarView.dispatchTouchEvent(ev); + return mStatusBarViewController.sendTouchToView(ev); } else { // it's hidden or hiding, don't send to notification shade. return true; } } } else if (mIsTrackingBarGesture) { - final boolean sendToNotification = mStatusBarView.dispatchTouchEvent(ev); + final boolean sendToStatusBar = mStatusBarViewController.sendTouchToView(ev); if (isUp || isCancel) { mIsTrackingBarGesture = false; } - return sendToNotification; + return sendToStatusBar; } return null; @@ -442,8 +439,8 @@ public class NotificationShadeWindowViewController { } } - public void setStatusBarView(PhoneStatusBarView statusBarView) { - mStatusBarView = statusBarView; + public void setStatusBarViewController(PhoneStatusBarViewController statusBarViewController) { + mStatusBarViewController = statusBarViewController; } public void setService(StatusBar statusBar, NotificationShadeWindowController controller) { @@ -455,11 +452,4 @@ public class NotificationShadeWindowViewController { void setDragDownHelper(DragDownHelper dragDownHelper) { mDragDownHelper = dragDownHelper; } - - private boolean isIntersecting(View view, float x, float y) { - int[] mTempLocation = view.getLocationOnScreen(); - mTempRect.set(mTempLocation[0], mTempLocation[1], mTempLocation[0] + view.getWidth(), - mTempLocation[1] + view.getHeight()); - return mTempRect.contains(x, y); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index b9386bd01e039..1cb19ab727aaf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone import android.content.res.Configuration import android.graphics.Point +import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver @@ -92,6 +93,30 @@ class PhoneStatusBarViewController private constructor( mView.importantForAccessibility = mode } + /** + * Sends a touch event to the status bar view. + * + * This is required in certain cases because the status bar view is in a separate window from + * the rest of SystemUI, and other windows may decide that their touch should instead be treated + * as a status bar window touch. + */ + fun sendTouchToView(ev: MotionEvent): Boolean { + return mView.dispatchTouchEvent(ev) + } + + /** + * Returns true if the given (x, y) point (in screen coordinates) is within the status bar + * view's range and false otherwise. + */ + fun touchIsWithinView(x: Float, y: Float): Boolean { + val left = mView.locationOnScreen[0] + val top = mView.locationOnScreen[1] + return left <= x && + x <= left + mView.width && + top <= y && + y <= top + mView.height + } + class StatusBarViewsCenterProvider : UnfoldMoveFromCenterAnimator.ViewCenterProvider { override fun getViewCenter(view: View, outPoint: Point) = when (view.id) { 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 07914cf1d9c4b..8fe03e46e25dc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1133,7 +1133,8 @@ public class StatusBar extends CoreStartable implements mStatusBarView = statusBarView; mPhoneStatusBarViewController = statusBarViewController; mStatusBarTransitions = statusBarTransitions; - mNotificationShadeWindowViewController.setStatusBarView(mStatusBarView); + mNotificationShadeWindowViewController + .setStatusBarViewController(mPhoneStatusBarViewController); // Ensure we re-propagate panel expansion values to the panel controller and // any listeners it may have, such as PanelBar. This will also ensure we // re-display the notification panel if necessary (for example, if diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt new file mode 100644 index 0000000000000..adb76e16507db --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2021 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.phone + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.view.MotionEvent +import androidx.test.filters.SmallTest +import com.android.keyguard.LockIconViewController +import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingCollectorFake +import com.android.systemui.dock.DockManager +import com.android.systemui.statusbar.LockscreenShadeTransitionController +import com.android.systemui.statusbar.NotificationShadeDepthController +import com.android.systemui.statusbar.NotificationShadeWindowController +import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.phone.NotificationShadeWindowView.InteractionEventHandler +import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager +import com.android.systemui.tuner.TunerService +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.mockito.Mockito.anyFloat +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever + +@RunWith(AndroidTestingRunner::class) +@RunWithLooper(setAsMainLooper = true) +@SmallTest +class NotificationShadeWindowViewControllerTest : SysuiTestCase() { + private lateinit var mController: NotificationShadeWindowViewController + + @Mock + private lateinit var mView: NotificationShadeWindowView + @Mock + private lateinit var mTunerService: TunerService + @Mock + private lateinit var mStatusBarStateController: SysuiStatusBarStateController + @Mock + private lateinit var mStatusBar: StatusBar + @Mock + private lateinit var mDockManager: DockManager + @Mock + private lateinit var mNotificationPanelViewController: NotificationPanelViewController + @Mock + private lateinit var mNotificationShadeDepthController: NotificationShadeDepthController + @Mock + private lateinit var mNotificationShadeWindowController: NotificationShadeWindowController + @Mock + private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController + @Mock + private lateinit var mStatusBarKeyguardViewManager: StatusBarKeyguardViewManager + @Mock + private lateinit var mLockscreenShadeTransitionController: LockscreenShadeTransitionController + @Mock + private lateinit var mLockIconViewController: LockIconViewController + @Mock + private lateinit var mPhoneStatusBarViewController: PhoneStatusBarViewController + + private lateinit var mInteractionEventHandlerCaptor: ArgumentCaptor + private lateinit var mInteractionEventHandler: InteractionEventHandler + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(mView.bottom).thenReturn(VIEW_BOTTOM) + + mController = NotificationShadeWindowViewController( + mLockscreenShadeTransitionController, + FalsingCollectorFake(), + mTunerService, + mStatusBarStateController, + mDockManager, + mNotificationShadeDepthController, + mView, + mNotificationPanelViewController, + PanelExpansionStateManager(), + stackScrollLayoutController, + mStatusBarKeyguardViewManager, + mLockIconViewController + ) + mController.setupExpandedStatusBar() + mController.setService(mStatusBar, mNotificationShadeWindowController) + + mInteractionEventHandlerCaptor = + ArgumentCaptor.forClass(InteractionEventHandler::class.java) + verify(mView).setInteractionEventHandler(mInteractionEventHandlerCaptor.capture()) + mInteractionEventHandler = mInteractionEventHandlerCaptor.value + } + + // Note: So far, these tests only cover interactions with the status bar view controller. More + // tests need to be added to test the rest of handleDispatchTouchEvent. + + @Test + fun handleDispatchTouchEvent_nullStatusBarViewController_returnsFalse() { + mController.setStatusBarViewController(null) + + val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv) + + assertThat(returnVal).isFalse() + } + + @Test + fun handleDispatchTouchEvent_downTouchBelowView_sendsTouchToSb() { + mController.setStatusBarViewController(mPhoneStatusBarViewController) + val ev = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0) + whenever(mPhoneStatusBarViewController.sendTouchToView(ev)).thenReturn(true) + + val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(ev) + + verify(mPhoneStatusBarViewController).sendTouchToView(ev) + assertThat(returnVal).isTrue() + } + + @Test + fun handleDispatchTouchEvent_downTouchBelowViewThenAnotherTouch_sendsTouchToSb() { + mController.setStatusBarViewController(mPhoneStatusBarViewController) + val downEvBelow = MotionEvent.obtain( + 0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0 + ) + mInteractionEventHandler.handleDispatchTouchEvent(downEvBelow) + + val nextEvent = MotionEvent.obtain( + 0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0 + ) + whenever(mPhoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true) + + val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(nextEvent) + + verify(mPhoneStatusBarViewController).sendTouchToView(nextEvent) + assertThat(returnVal).isTrue() + } + + @Test + fun handleDispatchTouchEvent_downAndPanelCollapsedAndInSbBoundAndSbWindowShow_sendsTouchToSb() { + mController.setStatusBarViewController(mPhoneStatusBarViewController) + whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(true) + whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true) + whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) + .thenReturn(true) + whenever(mPhoneStatusBarViewController.sendTouchToView(downEv)).thenReturn(true) + + val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv) + + verify(mPhoneStatusBarViewController).sendTouchToView(downEv) + assertThat(returnVal).isTrue() + } + + @Test + fun handleDispatchTouchEvent_panelNotCollapsed_returnsNull() { + mController.setStatusBarViewController(mPhoneStatusBarViewController) + whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(true) + whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) + .thenReturn(true) + // Item we're testing + whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(false) + + val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv) + + verify(mPhoneStatusBarViewController, never()).sendTouchToView(downEv) + assertThat(returnVal).isNull() + } + + @Test + fun handleDispatchTouchEvent_touchNotInSbBounds_returnsNull() { + mController.setStatusBarViewController(mPhoneStatusBarViewController) + whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(true) + whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true) + // Item we're testing + whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) + .thenReturn(false) + + val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv) + + verify(mPhoneStatusBarViewController, never()).sendTouchToView(downEv) + assertThat(returnVal).isNull() + } + + @Test + fun handleDispatchTouchEvent_sbWindowNotShowing_noSendTouchToSbAndReturnsTrue() { + mController.setStatusBarViewController(mPhoneStatusBarViewController) + whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true) + whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) + .thenReturn(true) + // Item we're testing + whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(false) + + val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv) + + verify(mPhoneStatusBarViewController, never()).sendTouchToView(downEv) + assertThat(returnVal).isTrue() + } + + @Test + fun handleDispatchTouchEvent_downEventSentToSbThenAnotherEvent_sendsTouchToSb() { + mController.setStatusBarViewController(mPhoneStatusBarViewController) + whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(true) + whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true) + whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) + .thenReturn(true) + + // Down event first + mInteractionEventHandler.handleDispatchTouchEvent(downEv) + + // Then another event + val nextEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0) + whenever(mPhoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true) + + val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(nextEvent) + + verify(mPhoneStatusBarViewController).sendTouchToView(nextEvent) + assertThat(returnVal).isTrue() + } +} + +private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) +private const val VIEW_BOTTOM = 100 diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt index 235de1e7cb7a7..c65a6b6cde1af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt @@ -77,9 +77,10 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { val parent = FrameLayout(mContext) // add parent to keep layout params view = LayoutInflater.from(mContext) .inflate(R.layout.status_bar, parent, false) as PhoneStatusBarView + view.setLeftTopRightBottom(VIEW_LEFT, VIEW_TOP, VIEW_RIGHT, VIEW_BOTTOM) } - controller = createController(view) + controller = createAndInitController(view) } @Test @@ -99,8 +100,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { val view = createViewMock() val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java) unfoldConfig.isEnabled = true - controller = createController(view) - controller.init() + controller = createAndInitController(view) verify(view.viewTreeObserver).addOnPreDrawListener(argumentCaptor.capture()) argumentCaptor.value.onPreDraw() @@ -108,6 +108,64 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { verify(moveFromCenterAnimation).onViewsReady(any()) } + @Test + fun touchIsWithinView_inBounds_returnsTrue() { + val view = createViewMockWithScreenLocation() + controller = createAndInitController(view) + + assertThat(controller.touchIsWithinView(VIEW_LEFT + 1f, VIEW_TOP + 1f)).isTrue() + } + + @Test + fun touchIsWithinView_onTopLeftCorner_returnsTrue() { + val view = createViewMockWithScreenLocation() + controller = createAndInitController(view) + + assertThat(controller.touchIsWithinView(VIEW_LEFT.toFloat(), VIEW_TOP.toFloat())).isTrue() + } + + @Test + fun touchIsWithinView_onBottomRightCorner_returnsTrue() { + val view = createViewMockWithScreenLocation() + controller = createAndInitController(view) + + assertThat(controller.touchIsWithinView( + VIEW_RIGHT.toFloat(), VIEW_BOTTOM.toFloat()) + ).isTrue() + } + + @Test + fun touchIsWithinView_xTooSmall_returnsFalse() { + val view = createViewMockWithScreenLocation() + controller = createAndInitController(view) + + assertThat(controller.touchIsWithinView(VIEW_LEFT - 1f, VIEW_TOP + 1f)).isFalse() + } + + @Test + fun touchIsWithinView_xTooLarge_returnsFalse() { + val view = createViewMockWithScreenLocation() + controller = createAndInitController(view) + + assertThat(controller.touchIsWithinView(VIEW_RIGHT + 1f, VIEW_TOP + 1f)).isFalse() + } + + @Test + fun touchIsWithinView_yTooSmall_returnsFalse() { + val view = createViewMockWithScreenLocation() + controller = createAndInitController(view) + + assertThat(controller.touchIsWithinView(VIEW_LEFT + 1f, VIEW_TOP - 1f)).isFalse() + } + + @Test + fun touchIsWithinView_yTooLarge_returnsFalse() { + val view = createViewMockWithScreenLocation() + controller = createAndInitController(view) + + assertThat(controller.touchIsWithinView(VIEW_LEFT + 1f, VIEW_BOTTOM + 1f)).isFalse() + } + private fun createViewMock(): PhoneStatusBarView { val view = spy(view) val viewTreeObserver = mock(ViewTreeObserver::class.java) @@ -116,12 +174,23 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { return view } - private fun createController(view: PhoneStatusBarView): PhoneStatusBarViewController { + private fun createViewMockWithScreenLocation(): PhoneStatusBarView { + val view = spy(view) + val location = IntArray(2) + location[0] = VIEW_LEFT + location[1] = VIEW_TOP + `when`(view.locationOnScreen).thenReturn(location) + return view + } + + private fun createAndInitController(view: PhoneStatusBarView): PhoneStatusBarViewController { return PhoneStatusBarViewController.Factory( Optional.of(sysuiUnfoldComponent), Optional.of(progressProvider), configurationController - ).create(view, touchEventHandler) + ).create(view, touchEventHandler).also { + it.init() + } } private class UnfoldConfig : UnfoldTransitionConfig { @@ -142,3 +211,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { } } } + +private const val VIEW_LEFT = 30 +private const val VIEW_RIGHT = 100 +private const val VIEW_TOP = 40 +private const val VIEW_BOTTOM = 100 From 06a2da0b98983ea6c300b5eb152fa58a7176781f Mon Sep 17 00:00:00 2001 From: Caitlin Cassidy Date: Tue, 28 Dec 2021 18:55:09 +0000 Subject: [PATCH 2/4] [Status Bar Refactor] Move status bar window state tracking into a centralized class and add some listeners for it. Bug: 212424936 Test: manual (verified callbacks trigger) Test: new StatusBarWindowStateControllerTest Change-Id: Ib75206c05551ddf6512dd608295b9043dabd7c88 --- .../NotificationPanelViewController.java | 17 ++- .../systemui/statusbar/phone/StatusBar.java | 11 +- .../phone/StatusBarCommandQueueCallbacks.java | 27 ----- .../phone/dagger/StatusBarPhoneModule.java | 3 + .../window/StatusBarWindowStateController.kt | 85 +++++++++++++++ .../window/StatusBarWindowStateListener.kt | 24 +++++ .../NotificationPanelViewControllerTest.java | 7 +- .../statusbar/phone/StatusBarTest.java | 3 + .../StatusBarWindowStateControllerTest.kt | 102 ++++++++++++++++++ 9 files changed, 247 insertions(+), 32 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 434671c02035e..08b5cf5613f0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.view.View.GONE; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -197,6 +198,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; +import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.util.Utils; import com.android.systemui.util.settings.SecureSettings; @@ -732,7 +734,9 @@ public class NotificationPanelViewController extends PanelViewController { NotificationEntryManager notificationEntryManager, CommunalStateController communalStateController, KeyguardStateController keyguardStateController, - StatusBarStateController statusBarStateController, DozeLog dozeLog, + StatusBarStateController statusBarStateController, + StatusBarWindowStateController statusBarWindowStateController, + DozeLog dozeLog, DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper, LatencyTracker latencyTracker, PowerManager powerManager, AccessibilityManager accessibilityManager, @DisplayId int displayId, @@ -862,6 +866,7 @@ public class NotificationPanelViewController extends PanelViewController { mQs.animateHeaderSlidingOut(); } }); + statusBarWindowStateController.addListener(this::onStatusBarWindowStateChanged); mThemeResId = mView.getContext().getThemeResId(); mKeyguardBypassController = bypassController; mUpdateMonitor = keyguardUpdateMonitor; @@ -5006,4 +5011,14 @@ public class NotificationPanelViewController extends PanelViewController { public PhoneStatusBarView.TouchEventHandler getStatusBarTouchEventHandler() { return mStatusBarViewTouchEventHandler; } + + private void onStatusBarWindowStateChanged(@StatusBarManager.WindowVisibleState int state) { + if (state != WINDOW_STATE_SHOWING + && mStatusBarStateController.getState() == StatusBarState.SHADE) { + collapsePanel( + false /* animate */, + false /* delayed */, + 1.0f /* speedUpFactor */); + } + } } 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 8fe03e46e25dc..4ecbb7c4d1ea1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -232,6 +232,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.window.StatusBarWindowController; +import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.util.DumpUtilsKt; import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -337,9 +338,11 @@ public class StatusBar extends CoreStartable implements private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; private StatusBarCommandQueueCallbacks mCommandQueueCallbacks; - void setWindowState(int state) { - mStatusBarWindowState = state; + void onStatusBarWindowStateChanged(@WindowVisibleState int state) { + updateBubblesVisibility(); + mStatusBarWindowState = state; mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN; + // TODO(b/212424936): Have this icon manager just implement its own listener. mStatusBarHideIconsForBouncerManager.setStatusBarWindowHidden(mStatusBarWindowHidden); if (mStatusBarView != null) { // Should #updateHideIconsForBouncer always be called, regardless of whether we have a @@ -464,7 +467,7 @@ public class StatusBar extends CoreStartable implements private PhoneStatusBarViewController mPhoneStatusBarViewController; private PhoneStatusBarTransitions mStatusBarTransitions; private AuthRippleController mAuthRippleController; - private int mStatusBarWindowState = WINDOW_STATE_SHOWING; + @WindowVisibleState private int mStatusBarWindowState = WINDOW_STATE_SHOWING; protected NotificationShadeWindowController mNotificationShadeWindowController; private final StatusBarWindowController mStatusBarWindowController; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -692,6 +695,7 @@ public class StatusBar extends CoreStartable implements LightBarController lightBarController, AutoHideController autoHideController, StatusBarWindowController statusBarWindowController, + StatusBarWindowStateController statusBarWindowStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, StatusBarSignalPolicy statusBarSignalPolicy, PulseExpansionHandler pulseExpansionHandler, @@ -872,6 +876,7 @@ public class StatusBar extends CoreStartable implements mStartingSurfaceOptional = startingSurfaceOptional; mNotifPipelineFlags = notifPipelineFlags; lockscreenShadeTransitionController.setStatusbar(this); + statusBarWindowStateController.addListener(this::onStatusBarWindowStateChanged); mScreenOffAnimationController = screenOffAnimationController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java index b391de3c5ab18..51f2e6728b805 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java @@ -16,8 +16,6 @@ package com.android.systemui.statusbar.phone; -import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; -import static android.app.StatusBarManager.windowStateToString; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.InsetsState.containsType; @@ -58,7 +56,6 @@ import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.qs.QSPanelController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DisableFlagsLogger; -import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; @@ -514,30 +511,6 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { .setTopAppHidesStatusBarAndTriggerUpdate(topAppHidesStatusBar); } - @Override - public void setWindowState( - int displayId, @StatusBarManager.WindowType int window, - @StatusBarManager.WindowVisibleState int state) { - if (displayId != mDisplayId) { - return; - } - boolean showing = state == WINDOW_STATE_SHOWING; - if (mNotificationShadeWindowView != null - && window == StatusBarManager.WINDOW_STATUS_BAR - && !mStatusBar.isSameStatusBarState(state)) { - mStatusBar.setWindowState(state); - if (StatusBar.DEBUG_WINDOW_STATE) { - Log.d(StatusBar.TAG, "Status bar " + windowStateToString(state)); - } - if (!showing && mStatusBarStateController.getState() == StatusBarState.SHADE) { - mNotificationPanelViewController.collapsePanel( - false /* animate */, false /* delayed */, 1.0f /* speedUpFactor */); - } - } - - mStatusBar.updateBubblesVisibility(); - } - @Override public void showAssistDisclosure() { mAssistManager.showDisclosure(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index f93a8dcad2234..4830b37dcc9a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -105,6 +105,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.window.StatusBarWindowController; +import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.MessageRouter; @@ -140,6 +141,7 @@ public interface StatusBarPhoneModule { LightBarController lightBarController, AutoHideController autoHideController, StatusBarWindowController statusBarWindowController, + StatusBarWindowStateController statusBarWindowStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, StatusBarSignalPolicy statusBarSignalPolicy, PulseExpansionHandler pulseExpansionHandler, @@ -235,6 +237,7 @@ public interface StatusBarPhoneModule { lightBarController, autoHideController, statusBarWindowController, + statusBarWindowStateController, keyguardUpdateMonitor, statusBarSignalPolicy, pulseExpansionHandler, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt new file mode 100644 index 0000000000000..facbe8abfd138 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2021 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.window + +import android.app.StatusBarManager +import android.app.StatusBarManager.WindowVisibleState +import android.app.StatusBarManager.WINDOW_STATE_SHOWING +import android.app.StatusBarManager.WINDOW_STATUS_BAR +import android.app.StatusBarManager.windowStateToString +import android.util.Log +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.DisplayId +import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.statusbar.phone.StatusBar +import javax.inject.Inject + +/** + * A centralized class maintaining the state of the status bar window. + * + * Classes that want to get updates about the status bar window state should subscribe to this class + * via [addListener] and should NOT add their own callback on [CommandQueue]. + */ +@SysUISingleton +class StatusBarWindowStateController @Inject constructor( + @DisplayId private val thisDisplayId: Int, + commandQueue: CommandQueue +) { + private val commandQueueCallback = object : CommandQueue.Callbacks { + override fun setWindowState( + displayId: Int, + @StatusBarManager.WindowType window: Int, + @WindowVisibleState state: Int + ) { + this@StatusBarWindowStateController.setWindowState(displayId, window, state) + } + } + private val listeners: MutableSet = HashSet() + + @WindowVisibleState private var windowState: Int = WINDOW_STATE_SHOWING + + init { + commandQueue.addCallback(commandQueueCallback) + } + + /** Adds a listener. */ + fun addListener(listener: StatusBarWindowStateListener) { + listeners.add(listener) + } + + private fun setWindowState( + displayId: Int, + @StatusBarManager.WindowType window: Int, + @WindowVisibleState state: Int + ) { + if (displayId != thisDisplayId) { + return + } + if (window != WINDOW_STATUS_BAR) { + return + } + if (windowState == state) { + return + } + + windowState = state + if (StatusBar.DEBUG_WINDOW_STATE) { + Log.d(StatusBar.TAG, "Status bar " + windowStateToString(state)) + } + listeners.forEach { it.onStatusBarWindowStateChanged(state) } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt new file mode 100644 index 0000000000000..5586c1b5d291d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 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.window + +import android.app.StatusBarManager + +/** Listener interface for changes in the status bar window state. */ +interface StatusBarWindowStateListener { + fun onStatusBarWindowStateChanged(@StatusBarManager.WindowVisibleState state: Int) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index 1cd9b9e774236..df11bf6178235 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -141,6 +141,7 @@ import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; +import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.settings.SecureSettings; @@ -358,6 +359,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { private NotificationsQSContainerController mNotificationsQSContainerController; @Mock private QsFrameTranslateController mQsFrameTranslateController; + @Mock + private StatusBarWindowStateController mStatusBarWindowStateController; private Optional mSysUIUnfoldComponent = Optional.empty(); private SysuiStatusBarStateController mStatusBarStateController; private NotificationPanelViewController mNotificationPanelViewController; @@ -491,7 +494,9 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController, mFalsingManager, new FalsingCollectorFake(), mNotificationLockscreenUserManager, mNotificationEntryManager, - mCommunalStateController, mKeyguardStateController, mStatusBarStateController, + mCommunalStateController, mKeyguardStateController, + mStatusBarStateController, + mStatusBarWindowStateController, mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper, mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor, mCommunalSourceMonitor, mMetricsLogger, mActivityManager, mConfigurationController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 9d5b17ea67389..a4b64803a859f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -147,6 +147,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.window.StatusBarWindowController; +import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.MessageRouterImpl; @@ -228,6 +229,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private DynamicPrivacyController mDynamicPrivacyController; @Mock private AutoHideController mAutoHideController; @Mock private StatusBarWindowController mStatusBarWindowController; + @Mock private StatusBarWindowStateController mStatusBarWindowStateController; @Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager; @Mock private UserSwitcherController mUserSwitcherController; @Mock private NetworkController mNetworkController; @@ -374,6 +376,7 @@ public class StatusBarTest extends SysuiTestCase { mLightBarController, mAutoHideController, mStatusBarWindowController, + mStatusBarWindowStateController, mKeyguardUpdateMonitor, mStatusBarSignalPolicy, mPulseExpansionHandler, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt new file mode 100644 index 0000000000000..8576d4f56906a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 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.window + +import android.app.StatusBarManager.WindowVisibleState +import android.app.StatusBarManager.WINDOW_NAVIGATION_BAR +import android.app.StatusBarManager.WINDOW_STATE_HIDDEN +import android.app.StatusBarManager.WINDOW_STATE_SHOWING +import android.app.StatusBarManager.WINDOW_STATUS_BAR +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.CommandQueue +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.ArgumentCaptor +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +class StatusBarWindowStateControllerTest : SysuiTestCase() { + private lateinit var controller: StatusBarWindowStateController + private lateinit var callback: CommandQueue.Callbacks + + @Mock + private lateinit var commandQueue: CommandQueue + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + controller = StatusBarWindowStateController(DISPLAY_ID, commandQueue) + + val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java) + verify(commandQueue).addCallback(callbackCaptor.capture()) + callback = callbackCaptor.value!! + } + + @Test + fun setWindowState_notSameDisplayId_listenersNotNotified() { + val listener = TestListener() + controller.addListener(listener) + + callback.setWindowState(DISPLAY_ID + 1, WINDOW_STATUS_BAR, WINDOW_STATE_HIDDEN) + + assertThat(listener.state).isNull() + } + + @Test + fun setWindowState_notStatusBarWindow_listenersNotNotified() { + val listener = TestListener() + controller.addListener(listener) + + callback.setWindowState(DISPLAY_ID, WINDOW_NAVIGATION_BAR, WINDOW_STATE_HIDDEN) + + assertThat(listener.state).isNull() + } + + @Test + fun setWindowState_sameState_listenersNotNotified() { + val listener = TestListener() + controller.addListener(listener) + + callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, WINDOW_STATE_SHOWING) + + assertThat(listener.state).isNull() + } + + @Test + fun setWindowState_newState_listenersNotified() { + val listener = TestListener() + controller.addListener(listener) + val newState = WINDOW_STATE_HIDDEN + + callback.setWindowState(DISPLAY_ID, WINDOW_STATUS_BAR, newState) + + assertThat(listener.state).isEqualTo(newState) + } + + private class TestListener : StatusBarWindowStateListener { + @WindowVisibleState var state: Int? = null + override fun onStatusBarWindowStateChanged(@WindowVisibleState state: Int) { + this.state = state + } + } +} + +private const val DISPLAY_ID = 10 From 9bed7dc0cae850d22c0d9a5a3c7acb8ea8ef7248 Mon Sep 17 00:00:00 2001 From: Caitlin Cassidy Date: Wed, 29 Dec 2021 16:48:23 +0000 Subject: [PATCH 3/4] [Status Bar Refactor] Have NotificationShadeWindowViewController query the window state directly instead of going through StatusBar.java. Bug: 212424936 Test: NotificationShadeWindowViewControllerTest Change-Id: I91fc2063185882c837fa4ba9e102b974003a710a --- .../NotificationShadeWindowViewController.java | 8 +++++--- .../systemui/statusbar/phone/StatusBar.java | 4 ---- .../window/StatusBarWindowStateController.kt | 3 +++ .../NotificationShadeWindowViewControllerTest.kt | 15 +++++++++------ .../phone/NotificationShadeWindowViewTest.java | 3 +++ 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java index 879e6943dce08..4e2eb6a19d537 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -16,8 +16,6 @@ package com.android.systemui.statusbar.phone; -import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; - import android.app.StatusBarManager; import android.hardware.display.AmbientDisplayConfiguration; import android.media.AudioManager; @@ -46,6 +44,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; +import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.tuner.TunerService; import java.io.FileDescriptor; @@ -67,6 +66,7 @@ public class NotificationShadeWindowViewController { private final LockscreenShadeTransitionController mLockscreenShadeTransitionController; private final LockIconViewController mLockIconViewController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private final StatusBarWindowStateController mStatusBarWindowStateController; private GestureDetector mGestureDetector; private View mBrightnessMirror; @@ -100,6 +100,7 @@ public class NotificationShadeWindowViewController { PanelExpansionStateManager panelExpansionStateManager, NotificationStackScrollLayoutController notificationStackScrollLayoutController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, + StatusBarWindowStateController statusBarWindowStateController, LockIconViewController lockIconViewController) { mLockscreenShadeTransitionController = transitionController; mFalsingCollector = falsingCollector; @@ -112,6 +113,7 @@ public class NotificationShadeWindowViewController { mDepthController = depthController; mNotificationStackScrollLayoutController = notificationStackScrollLayoutController; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; + mStatusBarWindowStateController = statusBarWindowStateController; mLockIconViewController = lockIconViewController; // This view is not part of the newly inflated expanded status bar. @@ -248,7 +250,7 @@ public class NotificationShadeWindowViewController { float x = ev.getRawX(); float y = ev.getRawY(); if (mStatusBarViewController.touchIsWithinView(x, y)) { - if (mService.isSameStatusBarState(WINDOW_STATE_SHOWING)) { + if (mStatusBarWindowStateController.windowIsShowing()) { mIsTrackingBarGesture = true; return mStatusBarViewController.sendTouchToView(ev); } else { // it's hidden or hiding, don't send to notification shade. 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 4ecbb7c4d1ea1..6499e23ddd1e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -2111,10 +2111,6 @@ public class StatusBar extends CoreStartable implements } } - boolean isSameStatusBarState(int state) { - return mStatusBarWindowState == state; - } - public GestureRecorder getGestureRecorder() { return mGestureRec; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt index facbe8abfd138..3a1491400f387 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt @@ -61,6 +61,9 @@ class StatusBarWindowStateController @Inject constructor( listeners.add(listener) } + /** Returns true if the window is currently showing. */ + fun windowIsShowing() = windowState == WINDOW_STATE_SHOWING + private fun setWindowState( displayId: Int, @StatusBarManager.WindowType window: Int, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt index adb76e16507db..12e71af6997ed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.phone.NotificationShadeWindowView.InteractionEventHandler import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager +import com.android.systemui.statusbar.window.StatusBarWindowStateController import com.android.systemui.tuner.TunerService import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -40,7 +41,6 @@ import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.MockitoAnnotations import org.mockito.Mockito.anyFloat -import org.mockito.Mockito.anyInt import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever @@ -72,6 +72,8 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Mock private lateinit var mStatusBarKeyguardViewManager: StatusBarKeyguardViewManager @Mock + private lateinit var mStatusBarWindowStateController: StatusBarWindowStateController + @Mock private lateinit var mLockscreenShadeTransitionController: LockscreenShadeTransitionController @Mock private lateinit var mLockIconViewController: LockIconViewController @@ -98,6 +100,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { PanelExpansionStateManager(), stackScrollLayoutController, mStatusBarKeyguardViewManager, + mStatusBarWindowStateController, mLockIconViewController ) mController.setupExpandedStatusBar() @@ -155,7 +158,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Test fun handleDispatchTouchEvent_downAndPanelCollapsedAndInSbBoundAndSbWindowShow_sendsTouchToSb() { mController.setStatusBarViewController(mPhoneStatusBarViewController) - whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(true) + whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true) whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true) whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) .thenReturn(true) @@ -170,7 +173,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Test fun handleDispatchTouchEvent_panelNotCollapsed_returnsNull() { mController.setStatusBarViewController(mPhoneStatusBarViewController) - whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(true) + whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true) whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) .thenReturn(true) // Item we're testing @@ -185,7 +188,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Test fun handleDispatchTouchEvent_touchNotInSbBounds_returnsNull() { mController.setStatusBarViewController(mPhoneStatusBarViewController) - whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(true) + whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true) whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true) // Item we're testing whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) @@ -204,7 +207,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) .thenReturn(true) // Item we're testing - whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(false) + whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(false) val returnVal = mInteractionEventHandler.handleDispatchTouchEvent(downEv) @@ -215,7 +218,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Test fun handleDispatchTouchEvent_downEventSentToSbThenAnotherEvent_sendsTouchToSb() { mController.setStatusBarViewController(mPhoneStatusBarViewController) - whenever(mStatusBar.isSameStatusBarState(anyInt())).thenReturn(true) + whenever(mStatusBarWindowStateController.windowIsShowing()).thenReturn(true) whenever(mNotificationPanelViewController.isFullyCollapsed).thenReturn(true) whenever(mPhoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) .thenReturn(true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java index aaf051ca81c08..d885da8b738c3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java @@ -45,6 +45,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; +import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.tuner.TunerService; import org.junit.Before; @@ -75,6 +76,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { @Mock private NotificationShadeWindowController mNotificationShadeWindowController; @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + @Mock private StatusBarWindowStateController mStatusBarWindowStateController; @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController; @Mock private LockIconViewController mLockIconViewController; @@ -107,6 +109,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { new PanelExpansionStateManager(), mNotificationStackScrollLayoutController, mStatusBarKeyguardViewManager, + mStatusBarWindowStateController, mLockIconViewController); mController.setupExpandedStatusBar(); mController.setService(mStatusBar, mNotificationShadeWindowController); From d0a7f18b364770fd73ebb3baadcb72130a2a8822 Mon Sep 17 00:00:00 2001 From: Caitlin Cassidy Date: Wed, 29 Dec 2021 16:58:49 +0000 Subject: [PATCH 4/4] [Status Bar Refactor] Have SBHideIconsForBouncerManager listen to window state directly instead of getting it from StatusBar.java Fixes: 212424936 Test: manual Test: atest Change-Id: I594894928b27ce547c21467295c15e91f07db851 --- .../android/systemui/statusbar/phone/StatusBar.java | 8 -------- .../phone/StatusBarHideIconsForBouncerManager.kt | 13 ++++++++++--- .../window/StatusBarWindowStateListener.kt | 2 +- .../phone/StatusBarCommandQueueCallbacksTest.java | 7 ++----- .../systemui/statusbar/phone/StatusBarTest.java | 3 ++- .../fragment/CollapsedStatusBarFragmentTest.java | 8 +++----- 6 files changed, 18 insertions(+), 23 deletions(-) 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 6499e23ddd1e0..04aaff08c17fb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -341,14 +341,6 @@ public class StatusBar extends CoreStartable implements void onStatusBarWindowStateChanged(@WindowVisibleState int state) { updateBubblesVisibility(); mStatusBarWindowState = state; - mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN; - // TODO(b/212424936): Have this icon manager just implement its own listener. - mStatusBarHideIconsForBouncerManager.setStatusBarWindowHidden(mStatusBarWindowHidden); - if (mStatusBarView != null) { - // Should #updateHideIconsForBouncer always be called, regardless of whether we have a - // status bar view? If so, we can make #updateHideIconsForBouncer private. - mStatusBarHideIconsForBouncerManager.updateHideIconsForBouncer(/* animate= */ false); - } } void acquireGestureWakeLock(long time) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt index d2181d0480d26..17516e07400bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt @@ -1,10 +1,12 @@ package com.android.systemui.statusbar.phone +import android.app.StatusBarManager import com.android.systemui.Dumpable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.statusbar.window.StatusBarWindowStateController import com.android.systemui.util.concurrency.DelayableExecutor import java.io.FileDescriptor import java.io.PrintWriter @@ -25,6 +27,7 @@ import javax.inject.Inject class StatusBarHideIconsForBouncerManager @Inject constructor( private val commandQueue: CommandQueue, @Main private val mainExecutor: DelayableExecutor, + statusBarWindowStateController: StatusBarWindowStateController, dumpManager: DumpManager ) : Dumpable { // State variables set by external classes. @@ -42,6 +45,9 @@ class StatusBarHideIconsForBouncerManager @Inject constructor( init { dumpManager.registerDumpable(this) + statusBarWindowStateController.addListener { + state -> setStatusBarStateAndTriggerUpdate(state) + } } /** Returns true if the status bar icons should be hidden in the bouncer. */ @@ -49,8 +55,9 @@ class StatusBarHideIconsForBouncerManager @Inject constructor( return hideIconsForBouncer || wereIconsJustHidden } - fun setStatusBarWindowHidden(statusBarWindowHidden: Boolean) { - this.statusBarWindowHidden = statusBarWindowHidden + private fun setStatusBarStateAndTriggerUpdate(@StatusBarManager.WindowVisibleState state: Int) { + statusBarWindowHidden = state == StatusBarManager.WINDOW_STATE_HIDDEN + updateHideIconsForBouncer(animate = false) } fun setDisplayId(displayId: Int) { @@ -87,7 +94,7 @@ class StatusBarHideIconsForBouncerManager @Inject constructor( * Updates whether the status bar icons should be hidden in the bouncer. May trigger * [commandQueue.recomputeDisableFlags] if the icon visibility status changes. */ - fun updateHideIconsForBouncer(animate: Boolean) { + private fun updateHideIconsForBouncer(animate: Boolean) { val hideBecauseApp = topAppHidesStatusBar && isOccluded && diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt index 5586c1b5d291d..f3bab04d97a09 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateListener.kt @@ -19,6 +19,6 @@ package com.android.systemui.statusbar.window import android.app.StatusBarManager /** Listener interface for changes in the status bar window state. */ -interface StatusBarWindowStateListener { +fun interface StatusBarWindowStateListener { fun onStatusBarWindowStateChanged(@StatusBarManager.WindowVisibleState state: Int) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java index 0131293656e7b..aabf9235c8226 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java @@ -36,7 +36,6 @@ import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; -import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DisableFlagsLogger; @@ -46,8 +45,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.util.concurrency.FakeExecutor; -import com.android.systemui.util.time.FakeSystemClock; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import org.junit.Before; @@ -84,6 +81,7 @@ public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase { @Mock private VibratorHelper mVibratorHelper; @Mock private Vibrator mVibrator; @Mock private LightBarController mLightBarController; + @Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; StatusBarCommandQueueCallbacks mSbcqCallbacks; @@ -112,8 +110,7 @@ public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase { mStatusBarStateController, mNotificationShadeWindowView, mNotificationStackScrollLayoutController, - new StatusBarHideIconsForBouncerManager( - mCommandQueue, new FakeExecutor(new FakeSystemClock()), new DumpManager()), + mStatusBarHideIconsForBouncerManager, mPowerManager, mVibratorHelper, Optional.of(mVibrator), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index a4b64803a859f..84ddce92f4ebe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -265,6 +265,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private BrightnessSliderController.Factory mBrightnessSliderFactory; @Mock private WallpaperController mWallpaperController; @Mock private OngoingCallController mOngoingCallController; + @Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; @Mock private LockscreenShadeTransitionController mLockscreenTransitionController; @Mock private FeatureFlags mFeatureFlags; @Mock private NotificationVisibilityProvider mVisibilityProvider; @@ -452,7 +453,7 @@ public class StatusBarTest extends SysuiTestCase { mScreenOffAnimationController, mWallpaperController, mOngoingCallController, - new StatusBarHideIconsForBouncerManager(mCommandQueue, mMainExecutor, mDumpManager), + mStatusBarHideIconsForBouncerManager, mLockscreenTransitionController, mFeatureFlags, mKeyguardUnlockAnimationController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java index b97f053b24b53..a630840fab0ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java @@ -37,7 +37,6 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiBaseFragmentTest; -import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.log.LogBuffer; import com.android.systemui.log.LogcatEchoTracker; @@ -57,8 +56,6 @@ import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentCom import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.util.concurrency.FakeExecutor; -import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -96,6 +93,8 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { private HeadsUpAppearanceController mHeadsUpAppearanceController; @Mock private NotificationPanelViewController mNotificationPanelViewController; + @Mock + private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; public CollapsedStatusBarFragmentTest() { super(CollapsedStatusBarFragment.class); @@ -325,8 +324,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest { new PanelExpansionStateManager(), mock(FeatureFlags.class), mStatusBarIconController, - new StatusBarHideIconsForBouncerManager( - mCommandQueue, new FakeExecutor(new FakeSystemClock()), new DumpManager()), + mStatusBarHideIconsForBouncerManager, mKeyguardStateController, mNotificationPanelViewController, mNetworkController,