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
This commit is contained in:
Nick Chameyev
2022-02-15 17:22:22 +00:00
parent 0d5f2aedf3
commit 341c3fb8cf
7 changed files with 90 additions and 30 deletions

View File

@@ -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

View File

@@ -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) {

View File

@@ -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<ShadeController> 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> sysUIUnfoldComponent,
Lazy<ShadeController> 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.
*/

View File

@@ -48,17 +48,17 @@ constructor(
private var pendingScrimReadyCallback: Runnable? = null
private var shouldPlayAnimation = false
private var isAnimationPlaying = false
private val statusListeners = arrayListOf<FoldAodAnimationStatus>()
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)
}
/**

View File

@@ -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),

View File

@@ -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);

View File

@@ -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(