From 341c3fb8cf5e0b8443a4d49b9a50920038d42abd Mon Sep 17 00:00:00 2001 From: Nick Chameyev Date: Tue, 15 Feb 2022 17:22:22 +0000 Subject: [PATCH] Hide navigation bar view immediately when folding to AOD This CL addresses two problems with navbar visibility when folding a foldable device to AOD: * Hiding of navbar insets sometimes doesn't work when calling hide() immediately after creation of a window because of a race in insets controller. As a workaround added applying visibility to the view itself when doing the fold to AOD animation. * Navigation bar creation happens in onConfigChange of SysUI and it is not synchronized with starting doze mode event from DozeService. So sometimes we skipped hiding the navbar because it hasn't been created yet at the moment when we started dozing. To avoid this issue added applying of the initial visibility to navigation bar when creating. Bug: 202844967 Test: aod enabled, fold => navbar is not visible Test: aod enabled, fold, turn on => navbar is visible Test: lock/unlock using power button when aod enabled/disabled Change-Id: I2773e1eb4221e1a97860478b2d772b91803e6bf5 --- .../systemui/navigationbar/NavigationBar.java | 4 +- .../NavigationBarController.java | 7 +++- .../phone/StatusBarKeyguardViewManager.java | 42 +++++++++++++++---- .../unfold/FoldAodAnimationController.kt | 27 ++++++------ .../NavigationBarControllerTest.java | 2 + .../navigationbar/NavigationBarTest.java | 32 ++++++++++---- .../StatusBarKeyguardViewManagerTest.java | 6 +++ 7 files changed, 90 insertions(+), 30 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index d16c019769b08..8b39e5c24ded0 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -542,7 +542,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, return mNavigationBarView; } - public View createView(Bundle savedState) { + public View createView(Bundle savedState, boolean initialVisibility) { mFrame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate( R.layout.navigation_bar_window, null); View barView = LayoutInflater.from(mFrame.getContext()).inflate( @@ -550,6 +550,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener, barView.addOnAttachStateChangeListener(this); mNavigationBarView = barView.findViewById(R.id.navigation_bar_view); + mNavigationBarView.setVisibility(initialVisibility ? View.VISIBLE : View.INVISIBLE); + if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView); mWindowManager.addView(mFrame, getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index 98b49b1c48903..21eeeb34f3bbe 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -58,6 +58,7 @@ import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.pip.Pip; @@ -84,6 +85,7 @@ public class NavigationBarController implements private final NavigationBar.Factory mNavigationBarFactory; private final DisplayManager mDisplayManager; private final TaskbarDelegate mTaskbarDelegate; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private int mNavMode; @VisibleForTesting boolean mIsTablet; @@ -107,6 +109,7 @@ public class NavigationBarController implements NavBarHelper navBarHelper, TaskbarDelegate taskbarDelegate, NavigationBar.Factory navigationBarFactory, + StatusBarKeyguardViewManager statusBarKeyguardViewManager, DumpManager dumpManager, AutoHideController autoHideController, LightBarController lightBarController, @@ -121,6 +124,7 @@ public class NavigationBarController implements mConfigChanges.applyNewConfig(mContext.getResources()); mNavMode = navigationModeController.addListener(this); mTaskbarDelegate = taskbarDelegate; + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService, navBarHelper, navigationModeController, sysUiFlagsContainer, dumpManager, autoHideController, lightBarController, pipOptional, @@ -320,7 +324,8 @@ public class NavigationBarController implements mNavigationBars.put(displayId, navBar); - View navigationBarView = navBar.createView(savedState); + boolean navBarVisible = mStatusBarKeyguardViewManager.isNavBarVisible(); + View navigationBarView = navBar.createView(savedState, navBarVisible); navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index d42a42364f213..11d9c311fb6c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -68,10 +68,13 @@ import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.unfold.FoldAodAnimationController; +import com.android.systemui.unfold.SysUIUnfoldComponent; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Objects; +import java.util.Optional; import javax.inject.Inject; @@ -87,7 +90,7 @@ import dagger.Lazy; public class StatusBarKeyguardViewManager implements RemoteInputController.Callback, StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener, PanelExpansionListener, NavigationModeController.ModeChangedListener, - KeyguardViewController { + KeyguardViewController, FoldAodAnimationController.FoldAodAnimationStatus { // When hiding the Keyguard with timing supplied from WindowManager, better be early than late. private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3; @@ -113,6 +116,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private final KeyguardBouncer.Factory mKeyguardBouncerFactory; private final KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory; private final DreamOverlayStateController mDreamOverlayStateController; + @Nullable + private final FoldAodAnimationController mFoldAodAnimationController; private KeyguardMessageAreaController mKeyguardMessageAreaController; private final Lazy mShadeController; private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() { @@ -186,6 +191,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mPulsing; private boolean mGesturalNav; private boolean mIsDocked; + private boolean mScreenOffAnimationPlaying; protected boolean mFirstUpdate = true; protected boolean mLastShowing; @@ -199,6 +205,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastIsDocked; private boolean mLastPulsing; private int mLastBiometricMode; + private boolean mLastScreenOffAnimationPlaying; private boolean mQsExpanded; private OnDismissAction mAfterKeyguardGoneAction; @@ -246,6 +253,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb NotificationMediaManager notificationMediaManager, KeyguardBouncer.Factory keyguardBouncerFactory, KeyguardMessageAreaController.Factory keyguardMessageAreaFactory, + Optional sysUIUnfoldComponent, Lazy shadeController, LatencyTracker latencyTracker) { mContext = context; @@ -264,6 +272,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mKeyguardMessageAreaFactory = keyguardMessageAreaFactory; mShadeController = shadeController; mLatencyTracker = latencyTracker; + mFoldAodAnimationController = sysUIUnfoldComponent + .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null); } @Override @@ -317,6 +327,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mConfigurationController.addCallback(this); mGesturalNav = QuickStepContract.isGesturalMode( mNavigationModeController.addListener(this)); + if (mFoldAodAnimationController != null) { + mFoldAodAnimationController.addCallback(this); + } if (mDockManager != null) { mDockManager.addListener(mDockEventListener); mIsDocked = mDockManager.isDocked(); @@ -965,6 +978,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() { @Override public void run() { + NavigationBarView view = mStatusBar.getNavigationBarView(); + if (view != null) { + view.setVisibility(View.VISIBLE); + } mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() .show(navigationBars()); } @@ -1019,6 +1036,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLastRemoteInputActive = remoteInputActive; mLastDozing = mDozing; mLastPulsing = mPulsing; + mLastScreenOffAnimationPlaying = mScreenOffAnimationPlaying; mLastBiometricMode = mBiometricUnlockController.getMode(); mLastGesturalNav = mGesturalNav; mLastIsDocked = mIsDocked; @@ -1054,14 +1072,15 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb /** * @return Whether the navigation bar should be made visible based on the current state. */ - protected boolean isNavBarVisible() { - int biometricMode = mBiometricUnlockController.getMode(); + public boolean isNavBarVisible() { + boolean isWakeAndUnlockPulsing = mBiometricUnlockController != null + && mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING; boolean keyguardShowing = mShowing && !mOccluded; - boolean hideWhileDozing = mDozing && biometricMode != MODE_WAKE_AND_UNLOCK_PULSING; + boolean hideWhileDozing = mDozing && !isWakeAndUnlockPulsing; boolean keyguardWithGestureNav = (keyguardShowing && !mDozing || mPulsing && !mIsDocked) && mGesturalNav; - return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing() - || mRemoteInputActive || keyguardWithGestureNav + return (!keyguardShowing && !hideWhileDozing && !mScreenOffAnimationPlaying + || mBouncer.isShowing() || mRemoteInputActive || keyguardWithGestureNav || mGlobalActionsVisible); } @@ -1073,8 +1092,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING; boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing || mLastPulsing && !mLastIsDocked) && mLastGesturalNav; - return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing - || mLastRemoteInputActive || keyguardWithGestureNav + return (!keyguardShowing && !hideWhileDozing && !mLastScreenOffAnimationPlaying + || mLastBouncerShowing || mLastRemoteInputActive || keyguardWithGestureNav || mLastGlobalActionsVisible); } @@ -1224,6 +1243,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb setDozing(isDozing); } + @Override + public void onFoldToAodAnimationChanged() { + if (mFoldAodAnimationController != null) { + mScreenOffAnimationPlaying = mFoldAodAnimationController.shouldPlayAnimation(); + } + } + /** * Whether qs is currently expanded. */ diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt index 2e627a872c247..2a9076e8f848d 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt @@ -48,17 +48,17 @@ constructor( private var pendingScrimReadyCallback: Runnable? = null private var shouldPlayAnimation = false + private var isAnimationPlaying = false + private val statusListeners = arrayListOf() private val startAnimationRunnable = Runnable { statusBar.notificationPanelViewController.startFoldToAodAnimation { // End action - isAnimationPlaying = false + setAnimationState(playing = false) } } - private var isAnimationPlaying = false - override fun initialize(statusBar: StatusBar, lightRevealScrim: LightRevealScrim) { this.statusBar = statusBar @@ -71,17 +71,13 @@ constructor( override fun startAnimation(): Boolean = if (alwaysOnEnabled && wakefulnessLifecycle.lastSleepReason == PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD && - globalSettings.getString(Settings.Global.ANIMATOR_DURATION_SCALE) != "0") { - shouldPlayAnimation = true - - isAnimationPlaying = true + globalSettings.getString(Settings.Global.ANIMATOR_DURATION_SCALE) != "0" + ) { + setAnimationState(playing = true) statusBar.notificationPanelViewController.prepareFoldToAodAnimation() - - statusListeners.forEach(FoldAodAnimationStatus::onFoldToAodAnimationChanged) - true } else { - shouldPlayAnimation = false + setAnimationState(playing = false) false } @@ -91,8 +87,13 @@ constructor( statusBar.notificationPanelViewController.cancelFoldToAodAnimation(); } - shouldPlayAnimation = false - isAnimationPlaying = false + setAnimationState(playing = false) + } + + private fun setAnimationState(playing: Boolean) { + shouldPlayAnimation = playing + isAnimationPlaying = playing + statusListeners.forEach(FoldAodAnimationStatus::onFoldToAodAnimationChanged) } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java index 73d2b0bf1a0f9..bb42c1277b904 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java @@ -46,6 +46,7 @@ import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.pip.Pip; @@ -90,6 +91,7 @@ public class NavigationBarControllerTest extends SysuiTestCase { mock(NavBarHelper.class), mock(TaskbarDelegate.class), mNavigationBarFactory, + mock(StatusBarKeyguardViewManager.class), mock(DumpManager.class), mock(AutoHideController.class), mock(LightBarController.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java index 090ce436340bc..48d38571cf3c7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -28,6 +28,7 @@ import static android.view.WindowInsets.Type.ime; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS; import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -228,7 +229,8 @@ public class NavigationBarTest extends SysuiTestCase { @Test public void testHomeLongPress() { - mNavigationBar.onViewAttachedToWindow(mNavigationBar.createView(null)); + mNavigationBar.onViewAttachedToWindow(mNavigationBar + .createView(null, /* initialVisibility= */ true)); mNavigationBar.onHomeLongClick(mNavigationBar.getView()); verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS); @@ -241,7 +243,8 @@ public class NavigationBarTest extends SysuiTestCase { .setLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 100) .build()); when(mNavBarHelper.getLongPressHomeEnabled()).thenReturn(true); - mNavigationBar.onViewAttachedToWindow(mNavigationBar.createView(null)); + mNavigationBar.onViewAttachedToWindow(mNavigationBar + .createView(null, /* initialVisibility= */ true)); mNavigationBar.onHomeTouch(mNavigationBar.getView(), MotionEvent.obtain( /*downTime=*/SystemClock.uptimeMillis(), @@ -263,7 +266,8 @@ public class NavigationBarTest extends SysuiTestCase { @Test public void testRegisteredWithDispatcher() { - mNavigationBar.onViewAttachedToWindow(mNavigationBar.createView(null)); + mNavigationBar.onViewAttachedToWindow(mNavigationBar + .createView(null, /* initialVisibility= */ true)); verify(mBroadcastDispatcher).registerReceiverWithHandler( any(BroadcastReceiver.class), any(IntentFilter.class), @@ -283,8 +287,8 @@ public class NavigationBarTest extends SysuiTestCase { doReturn(true).when(mockShadeWindowView).isAttachedToWindow(); doNothing().when(defaultNavBar).checkNavBarModes(); doNothing().when(externalNavBar).checkNavBarModes(); - defaultNavBar.createView(null); - externalNavBar.createView(null); + defaultNavBar.createView(null, /* initialVisibility= */ true); + externalNavBar.createView(null, /* initialVisibility= */ true); defaultNavBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true); @@ -318,7 +322,7 @@ public class NavigationBarTest extends SysuiTestCase { doReturn(mockShadeWindowView).when(mStatusBar).getNotificationShadeWindowView(); doReturn(true).when(mockShadeWindowView).isAttachedToWindow(); doNothing().when(mNavigationBar).checkNavBarModes(); - mNavigationBar.createView(null); + mNavigationBar.createView(null, /* initialVisibility= */ true); WindowInsets windowInsets = new WindowInsets.Builder().setVisible(ime(), false).build(); doReturn(windowInsets).when(mockShadeWindowView).getRootWindowInsets(); @@ -354,7 +358,7 @@ public class NavigationBarTest extends SysuiTestCase { @Test public void testA11yEventAfterDetach() { - View v = mNavigationBar.createView(null); + View v = mNavigationBar.createView(null, /* initialVisibility= */ true); mNavigationBar.onViewAttachedToWindow(v); verify(mNavBarHelper).registerNavTaskStateUpdater(any( NavBarHelper.NavbarTaskbarStateUpdater.class)); @@ -366,6 +370,20 @@ public class NavigationBarTest extends SysuiTestCase { mNavigationBar.updateAccessibilityStateFlags(); } + @Test + public void testCreateView_initiallyVisible_viewIsVisible() { + mNavigationBar.createView(null, /* initialVisibility= */ true); + + assertThat(mNavigationBar.getView().getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void testCreateView_initiallyNotVisible_viewIsNotVisible() { + mNavigationBar.createView(null, /* initialVisibility= */ false); + + assertThat(mNavigationBar.getView().getVisibility()).isEqualTo(View.INVISIBLE); + } + private NavigationBar createNavBar(Context context) { DeviceProvisionedController deviceProvisionedController = mock(DeviceProvisionedController.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 107ba8130349d..8b93de571cc9a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -53,6 +53,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.unfold.SysUIUnfoldComponent; import org.junit.Before; import org.junit.Test; @@ -60,6 +61,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Optional; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -100,6 +103,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private ShadeController mShadeController; @Mock + private SysUIUnfoldComponent mSysUiUnfoldComponent; + @Mock private DreamOverlayStateController mDreamOverlayStateController; @Mock private LatencyTracker mLatencyTracker; @@ -130,6 +135,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mock(NotificationMediaManager.class), mKeyguardBouncerFactory, mKeyguardMessageAreaFactory, + Optional.of(mSysUiUnfoldComponent), () -> mShadeController, mLatencyTracker); mStatusBarKeyguardViewManager.registerStatusBar(