1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.navigationbar; 18 19 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; 20 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; 21 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN; 22 import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT; 23 import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; 24 import static android.inputmethodservice.InputMethodService.IME_VISIBLE; 25 import static android.view.Display.DEFAULT_DISPLAY; 26 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; 27 import static android.view.WindowInsets.Type.ime; 28 29 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS; 30 import static com.android.systemui.assist.AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS; 31 import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS; 32 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; 33 34 import static com.google.common.truth.Truth.assertThat; 35 36 import static org.junit.Assert.assertEquals; 37 import static org.junit.Assert.assertFalse; 38 import static org.junit.Assert.assertTrue; 39 import static org.mockito.ArgumentMatchers.any; 40 import static org.mockito.ArgumentMatchers.anyBoolean; 41 import static org.mockito.ArgumentMatchers.anyLong; 42 import static org.mockito.Matchers.eq; 43 import static org.mockito.Mockito.doNothing; 44 import static org.mockito.Mockito.doReturn; 45 import static org.mockito.Mockito.mock; 46 import static org.mockito.Mockito.never; 47 import static org.mockito.Mockito.spy; 48 import static org.mockito.Mockito.times; 49 import static org.mockito.Mockito.verify; 50 import static org.mockito.Mockito.when; 51 52 import android.app.ActivityManager; 53 import android.content.Context; 54 import android.content.res.Resources; 55 import android.hardware.display.DisplayManagerGlobal; 56 import android.os.Handler; 57 import android.os.SystemClock; 58 import android.provider.DeviceConfig; 59 import android.telecom.TelecomManager; 60 import android.testing.TestableLooper; 61 import android.testing.TestableLooper.RunWithLooper; 62 import android.view.Display; 63 import android.view.DisplayInfo; 64 import android.view.IWindowManager; 65 import android.view.MotionEvent; 66 import android.view.View; 67 import android.view.ViewRootImpl; 68 import android.view.ViewTreeObserver; 69 import android.view.WindowInsets; 70 import android.view.WindowManager; 71 import android.view.WindowMetrics; 72 import android.view.accessibility.AccessibilityManager; 73 import android.view.inputmethod.InputMethodManager; 74 75 import androidx.test.ext.junit.runners.AndroidJUnit4; 76 import androidx.test.filters.SmallTest; 77 78 import com.android.internal.logging.MetricsLogger; 79 import com.android.internal.logging.UiEventLogger; 80 import com.android.systemui.SysuiTestCase; 81 import com.android.systemui.SysuiTestableContext; 82 import com.android.systemui.accessibility.AccessibilityButtonModeObserver; 83 import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; 84 import com.android.systemui.accessibility.SystemActions; 85 import com.android.systemui.assist.AssistManager; 86 import com.android.systemui.dump.DumpManager; 87 import com.android.systemui.keyguard.WakefulnessLifecycle; 88 import com.android.systemui.model.SysUiState; 89 import com.android.systemui.navigationbar.buttons.ButtonDispatcher; 90 import com.android.systemui.navigationbar.buttons.DeadZone; 91 import com.android.systemui.navigationbar.buttons.KeyButtonView; 92 import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; 93 import com.android.systemui.plugins.statusbar.StatusBarStateController; 94 import com.android.systemui.recents.OverviewProxyService; 95 import com.android.systemui.recents.Recents; 96 import com.android.systemui.settings.DisplayTracker; 97 import com.android.systemui.settings.FakeDisplayTracker; 98 import com.android.systemui.settings.UserContextProvider; 99 import com.android.systemui.settings.UserTracker; 100 import com.android.systemui.shade.NotificationShadeWindowView; 101 import com.android.systemui.shade.ShadeViewController; 102 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; 103 import com.android.systemui.shared.rotation.RotationButtonController; 104 import com.android.systemui.shared.system.TaskStackChangeListeners; 105 import com.android.systemui.statusbar.CommandQueue; 106 import com.android.systemui.statusbar.NotificationRemoteInputManager; 107 import com.android.systemui.statusbar.NotificationShadeDepthController; 108 import com.android.systemui.statusbar.NotificationShadeWindowController; 109 import com.android.systemui.statusbar.phone.AutoHideController; 110 import com.android.systemui.statusbar.phone.CentralSurfaces; 111 import com.android.systemui.statusbar.phone.LightBarController; 112 import com.android.systemui.statusbar.phone.LightBarTransitionsController; 113 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; 114 import com.android.systemui.statusbar.policy.ConfigurationController; 115 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 116 import com.android.systemui.statusbar.policy.KeyguardStateController; 117 import com.android.systemui.util.DeviceConfigProxyFake; 118 import com.android.systemui.util.concurrency.FakeExecutor; 119 import com.android.systemui.util.time.FakeSystemClock; 120 import com.android.systemui.utils.leaks.LeakCheckedTest; 121 import com.android.wm.shell.back.BackAnimation; 122 import com.android.wm.shell.pip.Pip; 123 124 import org.junit.Before; 125 import org.junit.Rule; 126 import org.junit.Test; 127 import org.junit.runner.RunWith; 128 import org.mockito.ArgumentCaptor; 129 import org.mockito.Mock; 130 import org.mockito.MockitoAnnotations; 131 132 import java.util.Optional; 133 import java.util.concurrent.Executor; 134 135 @RunWith(AndroidJUnit4.class) 136 @RunWithLooper(setAsMainLooper = true) 137 @SmallTest 138 public class NavigationBarTest extends SysuiTestCase { 139 private static final int EXTERNAL_DISPLAY_ID = 2; 140 141 private NavigationBar mNavigationBar; 142 private NavigationBar mExternalDisplayNavigationBar; 143 144 private SysuiTestableContext mSysuiTestableContextExternal; 145 @Mock 146 NavigationBarView mNavigationBarView; 147 @Mock 148 NavigationBarFrame mNavigationBarFrame; 149 @Mock 150 ButtonDispatcher mHomeButton; 151 @Mock 152 KeyButtonView mHomeButtonView; 153 @Mock 154 ButtonDispatcher mRecentsButton; 155 @Mock 156 ButtonDispatcher mAccessibilityButton; 157 @Mock 158 ButtonDispatcher mImeSwitchButton; 159 @Mock 160 ButtonDispatcher mBackButton; 161 @Mock 162 NavigationBarTransitions mNavigationBarTransitions; 163 @Mock 164 RotationButtonController mRotationButtonController; 165 @Mock 166 LightBarTransitionsController mLightBarTransitionsController; 167 @Mock 168 private SystemActions mSystemActions; 169 @Mock 170 private OverviewProxyService mOverviewProxyService; 171 @Mock 172 private StatusBarStateController mStatusBarStateController; 173 @Mock 174 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 175 @Mock 176 private NavigationModeController mNavigationModeController; 177 @Mock 178 private CommandQueue mCommandQueue; 179 private SysUiState mMockSysUiState; 180 @Mock 181 private Handler mHandler; 182 @Mock 183 private UserTracker mUserTracker; 184 @Mock 185 private UiEventLogger mUiEventLogger; 186 @Mock 187 private NavBarButtonClickLogger mNavBarButtonClickLogger; 188 @Mock 189 private NavbarOrientationTrackingLogger mNavbarOrientationTrackingLogger; 190 @Mock 191 private ViewTreeObserver mViewTreeObserver; 192 NavBarHelper mNavBarHelper; 193 @Mock 194 private LightBarController mLightBarController; 195 @Mock 196 private LightBarController.Factory mLightBarcontrollerFactory; 197 @Mock 198 private AutoHideController mAutoHideController; 199 @Mock 200 private AutoHideController.Factory mAutoHideControllerFactory; 201 @Mock 202 private WindowManager mWindowManager; 203 @Mock 204 private TelecomManager mTelecomManager; 205 @Mock 206 private InputMethodManager mInputMethodManager; 207 @Mock 208 private AssistManager mAssistManager; 209 @Mock 210 private DeadZone mDeadZone; 211 @Mock 212 private CentralSurfaces mCentralSurfaces; 213 @Mock 214 private KeyguardStateController mKeyguardStateController; 215 @Mock 216 private UserContextProvider mUserContextProvider; 217 @Mock 218 private WakefulnessLifecycle mWakefulnessLifecycle; 219 @Mock 220 private Resources mResources; 221 @Mock 222 private ViewRootImpl mViewRootImpl; 223 @Mock 224 private EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory; 225 @Mock 226 private EdgeBackGestureHandler mEdgeBackGestureHandler; 227 @Mock 228 private NotificationShadeWindowController mNotificationShadeWindowController; 229 private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); 230 private DeviceConfigProxyFake mDeviceConfigProxyFake = new DeviceConfigProxyFake(); 231 private TaskStackChangeListeners mTaskStackChangeListeners = 232 TaskStackChangeListeners.getTestInstance(); 233 234 @Rule 235 public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck(); 236 237 private final Executor mSynchronousExecutor = runnable -> runnable.run(); 238 239 @Before setup()240 public void setup() throws Exception { 241 MockitoAnnotations.initMocks(this); 242 243 when(mLightBarcontrollerFactory.create(any(Context.class))).thenReturn(mLightBarController); 244 when(mAutoHideControllerFactory.create(any(Context.class))).thenReturn(mAutoHideController); 245 when(mNavigationBarView.getHomeButton()).thenReturn(mHomeButton); 246 when(mNavigationBarView.getRecentsButton()).thenReturn(mRecentsButton); 247 when(mNavigationBarView.getAccessibilityButton()).thenReturn(mAccessibilityButton); 248 when(mNavigationBarView.getImeSwitchButton()).thenReturn(mImeSwitchButton); 249 when(mNavigationBarView.getBackButton()).thenReturn(mBackButton); 250 when(mNavigationBarView.getRotationButtonController()) 251 .thenReturn(mRotationButtonController); 252 when(mNavigationBarTransitions.getLightTransitionsController()) 253 .thenReturn(mLightBarTransitionsController); 254 when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(true); 255 when(mNavigationBarView.getViewTreeObserver()).thenReturn(mViewTreeObserver); 256 when(mUserContextProvider.createCurrentUserContext(any(Context.class))) 257 .thenReturn(mContext); 258 when(mNavigationBarView.getResources()).thenReturn(mResources); 259 when(mNavigationBarView.getViewRootImpl()).thenReturn(mViewRootImpl); 260 when(mEdgeBackGestureHandlerFactory.create(any())).thenReturn(mEdgeBackGestureHandler); 261 setupSysuiDependency(); 262 // This class inflates views that call Dependency.get, thus these injections are still 263 // necessary. 264 mDependency.injectTestDependency(AssistManager.class, mAssistManager); 265 mDependency.injectMockDependency(KeyguardStateController.class); 266 mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController); 267 mDependency.injectMockDependency(NavigationBarController.class); 268 mDependency.injectTestDependency(OverviewProxyService.class, mOverviewProxyService); 269 mDependency.injectTestDependency(NavigationModeController.class, mNavigationModeController); 270 TestableLooper.get(this).runWithLooper(() -> { 271 mNavBarHelper = spy(new NavBarHelper(mContext, mock(AccessibilityManager.class), 272 mock(AccessibilityButtonModeObserver.class), 273 mock(AccessibilityButtonTargetsObserver.class), 274 mSystemActions, mOverviewProxyService, 275 () -> mock(AssistManager.class), () -> Optional.of(mCentralSurfaces), 276 mKeyguardStateController, mock(NavigationModeController.class), 277 mEdgeBackGestureHandlerFactory, mock(IWindowManager.class), 278 mock(UserTracker.class), mock(DisplayTracker.class), 279 mNotificationShadeWindowController, mock(ConfigurationController.class), 280 mock(DumpManager.class), mock(CommandQueue.class), mSynchronousExecutor)); 281 mNavigationBar = createNavBar(mContext); 282 mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal); 283 }); 284 } 285 setupSysuiDependency()286 private void setupSysuiDependency() { 287 Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY_ID, 288 new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS); 289 mSysuiTestableContextExternal = (SysuiTestableContext) getContext().createDisplayContext( 290 display); 291 292 Display defaultDisplay = mContext.getDisplay(); 293 when(mWindowManager.getDefaultDisplay()).thenReturn(defaultDisplay); 294 WindowMetrics metrics = mContext.getSystemService(WindowManager.class) 295 .getMaximumWindowMetrics(); 296 when(mWindowManager.getMaximumWindowMetrics()).thenReturn(metrics); 297 WindowMetrics currentWindowMetrics = mContext.getSystemService(WindowManager.class) 298 .getCurrentWindowMetrics(); 299 when(mWindowManager.getCurrentWindowMetrics()).thenReturn(currentWindowMetrics); 300 doNothing().when(mWindowManager).addView(any(), any()); 301 doNothing().when(mWindowManager).removeViewImmediate(any()); 302 mMockSysUiState = mock(SysUiState.class); 303 when(mMockSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mMockSysUiState); 304 305 mContext.addMockSystemService(WindowManager.class, mWindowManager); 306 mSysuiTestableContextExternal.addMockSystemService(WindowManager.class, mWindowManager); 307 } 308 309 @Test testHomeLongPress()310 public void testHomeLongPress() { 311 when(mAssistManager.shouldOverrideAssist(INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS)) 312 .thenReturn(false); 313 314 mNavigationBar.init(); 315 mNavigationBar.onViewAttached(); 316 mNavigationBar.onHomeLongClick(mHomeButtonView); 317 318 verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS); 319 verify(mAssistManager).startAssist(any()); 320 } 321 322 @Test testHomeLongPressOverride()323 public void testHomeLongPressOverride() { 324 when(mAssistManager.shouldOverrideAssist(INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS)) 325 .thenReturn(true); 326 327 mNavigationBar.init(); 328 mNavigationBar.onViewAttached(); 329 mNavigationBar.onHomeLongClick(mHomeButtonView); 330 331 verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS); 332 333 ArgumentCaptor<Runnable> onRippleInvisibleRunnableCaptor = ArgumentCaptor.forClass( 334 Runnable.class); 335 // startAssist is not called initially 336 verify(mAssistManager, never()).startAssist(any()); 337 // but a Runnable is added for when the ripple is invisible 338 verify(mHomeButtonView).setOnRippleInvisibleRunnable( 339 onRippleInvisibleRunnableCaptor.capture()); 340 // and when that runs, startAssist is called 341 onRippleInvisibleRunnableCaptor.getValue().run(); 342 verify(mAssistManager).startAssist(any()); 343 } 344 345 @Test testHomeLongPressWithCustomDuration()346 public void testHomeLongPressWithCustomDuration() throws Exception { 347 mDeviceConfigProxyFake.setProperty( 348 DeviceConfig.NAMESPACE_SYSTEMUI, 349 HOME_BUTTON_LONG_PRESS_DURATION_MS, 350 "100", 351 false); 352 when(mNavBarHelper.getLongPressHomeEnabled()).thenReturn(true); 353 mNavigationBar.init(); 354 mNavigationBar.onViewAttached(); 355 356 mNavigationBar.onHomeTouch(mNavigationBar.getView(), MotionEvent.obtain( 357 /*downTime=*/SystemClock.uptimeMillis(), 358 /*eventTime=*/SystemClock.uptimeMillis(), 359 /*action=*/MotionEvent.ACTION_DOWN, 360 0, 0, 0 361 )); 362 verify(mHandler, times(1)).postDelayed(any(), eq(100L)); 363 364 mNavigationBar.onHomeTouch(mNavigationBar.getView(), MotionEvent.obtain( 365 /*downTime=*/SystemClock.uptimeMillis(), 366 /*eventTime=*/SystemClock.uptimeMillis(), 367 /*action=*/MotionEvent.ACTION_UP, 368 0, 0, 0 369 )); 370 371 verify(mHandler, times(1)).removeCallbacks(any()); 372 } 373 374 @Test onHomeTouch_isRinging_keyguardShowing_touchBlocked()375 public void onHomeTouch_isRinging_keyguardShowing_touchBlocked() { 376 when(mTelecomManager.isRinging()).thenReturn(true); 377 when(mKeyguardStateController.isShowing()).thenReturn(true); 378 379 boolean result = mNavigationBar.onHomeTouch( 380 mNavigationBar.getView(), 381 MotionEvent.obtain( 382 /*downTime=*/SystemClock.uptimeMillis(), 383 /*eventTime=*/SystemClock.uptimeMillis(), 384 /*action=*/MotionEvent.ACTION_DOWN, 385 0, 0, 0)); 386 387 assertThat(result).isTrue(); 388 389 // Verify subsequent touches are also blocked 390 boolean nextTouchEvent = mNavigationBar.onHomeTouch( 391 mNavigationBar.getView(), 392 MotionEvent.obtain( 393 /*downTime=*/SystemClock.uptimeMillis(), 394 /*eventTime=*/SystemClock.uptimeMillis(), 395 /*action=*/MotionEvent.ACTION_MOVE, 396 0, 0, 0)); 397 assertThat(nextTouchEvent).isTrue(); 398 } 399 400 @Test onHomeTouch_isRinging_keyguardNotShowing_touchNotBlocked()401 public void onHomeTouch_isRinging_keyguardNotShowing_touchNotBlocked() { 402 when(mTelecomManager.isRinging()).thenReturn(true); 403 when(mKeyguardStateController.isShowing()).thenReturn(false); 404 405 boolean result = mNavigationBar.onHomeTouch( 406 mNavigationBar.getView(), 407 MotionEvent.obtain( 408 /*downTime=*/SystemClock.uptimeMillis(), 409 /*eventTime=*/SystemClock.uptimeMillis(), 410 /*action=*/MotionEvent.ACTION_DOWN, 411 0, 0, 0)); 412 413 assertThat(result).isFalse(); 414 415 // Verify subsequent touches are also not blocked 416 boolean nextTouchEvent = mNavigationBar.onHomeTouch( 417 mNavigationBar.getView(), 418 MotionEvent.obtain( 419 /*downTime=*/SystemClock.uptimeMillis(), 420 /*eventTime=*/SystemClock.uptimeMillis(), 421 /*action=*/MotionEvent.ACTION_MOVE, 422 0, 0, 0)); 423 assertThat(nextTouchEvent).isFalse(); 424 } 425 426 @Test testRegisteredWithUserTracker()427 public void testRegisteredWithUserTracker() { 428 mNavigationBar.init(); 429 mNavigationBar.onViewAttached(); 430 verify(mUserTracker).addCallback(any(UserTracker.Callback.class), any(Executor.class)); 431 } 432 433 @Test testSetImeWindowStatusWhenImeSwitchOnDisplay()434 public void testSetImeWindowStatusWhenImeSwitchOnDisplay() { 435 // Create default & external NavBar fragment. 436 NavigationBar defaultNavBar = mNavigationBar; 437 NavigationBar externalNavBar = mExternalDisplayNavigationBar; 438 NotificationShadeWindowView mockShadeWindowView = mock(NotificationShadeWindowView.class); 439 WindowInsets windowInsets = new WindowInsets.Builder().setVisible(ime(), false).build(); 440 doReturn(windowInsets).when(mockShadeWindowView).getRootWindowInsets(); 441 doReturn(true).when(mockShadeWindowView).isAttachedToWindow(); 442 doNothing().when(defaultNavBar).checkNavBarModes(); 443 doNothing().when(externalNavBar).checkNavBarModes(); 444 defaultNavBar.init(); 445 externalNavBar.init(); 446 447 defaultNavBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, 448 BACK_DISPOSITION_DEFAULT, true); 449 450 // Verify IME window state will be updated in default NavBar & external NavBar state reset. 451 assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN 452 | NAVIGATION_HINT_IME_SWITCHER_SHOWN, 453 defaultNavBar.getNavigationIconHints()); 454 assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); 455 assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); 456 assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) 457 != 0); 458 459 externalNavBar.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, IME_VISIBLE, 460 BACK_DISPOSITION_DEFAULT, true); 461 defaultNavBar.setImeWindowStatus( 462 DEFAULT_DISPLAY, null, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT, false); 463 // Verify IME window state will be updated in external NavBar & default NavBar state reset. 464 assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN 465 | NAVIGATION_HINT_IME_SWITCHER_SHOWN, 466 externalNavBar.getNavigationIconHints()); 467 assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); 468 assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); 469 assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) 470 != 0); 471 } 472 473 @Test testSetImeWindowStatusWhenKeyguardLockingAndImeInsetsChange()474 public void testSetImeWindowStatusWhenKeyguardLockingAndImeInsetsChange() { 475 NotificationShadeWindowView mockShadeWindowView = mock(NotificationShadeWindowView.class); 476 doReturn(mockShadeWindowView).when(mNotificationShadeWindowController).getWindowRootView(); 477 doReturn(true).when(mockShadeWindowView).isAttachedToWindow(); 478 doNothing().when(mNavigationBar).checkNavBarModes(); 479 mNavigationBar.init(); 480 WindowInsets windowInsets = new WindowInsets.Builder().setVisible(ime(), false).build(); 481 doReturn(windowInsets).when(mockShadeWindowView).getRootWindowInsets(); 482 483 // Verify navbar altered back icon when an app is showing IME 484 mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, 485 BACK_DISPOSITION_DEFAULT, true); 486 assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); 487 assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); 488 assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) 489 != 0); 490 491 // Verify navbar didn't alter and showing back icon when the keyguard is showing without 492 // requesting IME insets visible. 493 doReturn(true).when(mKeyguardStateController).isShowing(); 494 mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, 495 BACK_DISPOSITION_DEFAULT, true); 496 assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); 497 assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); 498 assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) 499 != 0); 500 501 // Verify navbar altered and showing back icon when the keyguard is showing and 502 // requesting IME insets visible. 503 windowInsets = new WindowInsets.Builder().setVisible(ime(), true).build(); 504 doReturn(windowInsets).when(mockShadeWindowView).getRootWindowInsets(); 505 mNavigationBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, 506 BACK_DISPOSITION_DEFAULT, true); 507 assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); 508 assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); 509 assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN) 510 != 0); 511 } 512 513 @Test testA11yEventAfterDetach()514 public void testA11yEventAfterDetach() { 515 mNavigationBar.init(); 516 mNavigationBar.onViewAttached(); 517 verify(mNavBarHelper).registerNavTaskStateUpdater(any( 518 NavBarHelper.NavbarTaskbarStateUpdater.class)); 519 mNavigationBar.onViewDetached(); 520 verify(mNavBarHelper).removeNavTaskStateUpdater(any( 521 NavBarHelper.NavbarTaskbarStateUpdater.class)); 522 523 // Should be safe even though the internal view is now null. 524 mNavigationBar.updateAccessibilityStateFlags(); 525 } 526 527 @Test testCreateView_initiallyVisible_viewIsVisible()528 public void testCreateView_initiallyVisible_viewIsVisible() { 529 when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(true); 530 mNavigationBar.init(); 531 mNavigationBar.onViewAttached(); 532 533 verify(mNavigationBarView).setVisibility(View.VISIBLE); 534 } 535 536 @Test testCreateView_initiallyNotVisible_viewIsNotVisible()537 public void testCreateView_initiallyNotVisible_viewIsNotVisible() { 538 when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(false); 539 mNavigationBar.init(); 540 mNavigationBar.onViewAttached(); 541 542 verify(mNavigationBarView).setVisibility(View.INVISIBLE); 543 } 544 545 @Test testOnInit_readCurrentSysuiState()546 public void testOnInit_readCurrentSysuiState() { 547 mNavigationBar.init(); 548 verify(mNavBarHelper, times(1)).getCurrentSysuiState(); 549 } 550 551 @Test testScreenPinningEnabled_updatesSysuiState()552 public void testScreenPinningEnabled_updatesSysuiState() { 553 mNavigationBar.init(); 554 mTaskStackChangeListeners.getListenerImpl().onLockTaskModeChanged( 555 ActivityManager.LOCK_TASK_MODE_PINNED); 556 verify(mMockSysUiState).setFlag(eq(SYSUI_STATE_SCREEN_PINNING), eq(true)); 557 } 558 createNavBar(Context context)559 private NavigationBar createNavBar(Context context) { 560 DeviceProvisionedController deviceProvisionedController = 561 mock(DeviceProvisionedController.class); 562 when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true); 563 return spy(new NavigationBar( 564 mNavigationBarView, 565 mNavigationBarFrame, 566 null, 567 context, 568 mWindowManager, 569 () -> mAssistManager, 570 mock(AccessibilityManager.class), 571 deviceProvisionedController, 572 new MetricsLogger(), 573 mOverviewProxyService, 574 mNavigationModeController, 575 mStatusBarStateController, 576 mStatusBarKeyguardViewManager, 577 mMockSysUiState, 578 mUserTracker, 579 mCommandQueue, 580 Optional.of(mock(Pip.class)), 581 Optional.of(mock(Recents.class)), 582 () -> Optional.of(mCentralSurfaces), 583 mKeyguardStateController, 584 mock(ShadeViewController.class), 585 mock(PanelExpansionInteractor.class), 586 mock(NotificationRemoteInputManager.class), 587 mock(NotificationShadeDepthController.class), 588 mHandler, 589 mFakeExecutor, 590 mFakeExecutor, 591 mUiEventLogger, 592 mNavBarHelper, 593 mLightBarController, 594 mLightBarcontrollerFactory, 595 mAutoHideController, 596 mAutoHideControllerFactory, 597 Optional.of(mTelecomManager), 598 mInputMethodManager, 599 mDeadZone, 600 mDeviceConfigProxyFake, 601 mNavigationBarTransitions, 602 Optional.of(mock(BackAnimation.class)), 603 mUserContextProvider, 604 mWakefulnessLifecycle, 605 mTaskStackChangeListeners, 606 new FakeDisplayTracker(mContext), 607 mNavBarButtonClickLogger, 608 mNavbarOrientationTrackingLogger)); 609 } 610 processAllMessages()611 private void processAllMessages() { 612 TestableLooper.get(this).processAllMessages(); 613 } 614 } 615