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:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user