1 /* 2 * Copyright (C) 2021 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.WINDOW_NAVIGATION_BAR; 20 import static android.app.StatusBarManager.WindowVisibleState; 21 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; 22 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; 23 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS; 24 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; 25 26 import static com.android.systemui.accessibility.SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON; 27 import static com.android.systemui.accessibility.SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER; 28 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; 29 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; 30 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT; 31 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT; 32 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; 33 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; 34 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; 35 36 import android.content.ContentResolver; 37 import android.content.Context; 38 import android.content.res.Configuration; 39 import android.database.ContentObserver; 40 import android.inputmethodservice.InputMethodService; 41 import android.net.Uri; 42 import android.os.Bundle; 43 import android.os.Handler; 44 import android.os.Looper; 45 import android.os.Process; 46 import android.os.RemoteException; 47 import android.os.UserHandle; 48 import android.provider.Settings; 49 import android.provider.Settings.Secure; 50 import android.util.Log; 51 import android.view.IRotationWatcher; 52 import android.view.IWallpaperVisibilityListener; 53 import android.view.IWindowManager; 54 import android.view.View; 55 import android.view.WindowInsets; 56 import android.view.accessibility.AccessibilityManager; 57 58 import androidx.annotation.NonNull; 59 60 import com.android.internal.accessibility.common.ShortcutConstants; 61 import com.android.systemui.Dumpable; 62 import com.android.systemui.accessibility.AccessibilityButtonModeObserver; 63 import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; 64 import com.android.systemui.accessibility.SystemActions; 65 import com.android.systemui.assist.AssistManager; 66 import com.android.systemui.dagger.SysUISingleton; 67 import com.android.systemui.dagger.qualifiers.Main; 68 import com.android.systemui.dump.DumpManager; 69 import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; 70 import com.android.systemui.recents.OverviewProxyService; 71 import com.android.systemui.settings.DisplayTracker; 72 import com.android.systemui.settings.UserTracker; 73 import com.android.systemui.shared.system.QuickStepContract; 74 import com.android.systemui.statusbar.CommandQueue; 75 import com.android.systemui.statusbar.NotificationShadeWindowController; 76 import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; 77 import com.android.systemui.statusbar.phone.CentralSurfaces; 78 import com.android.systemui.statusbar.policy.ConfigurationController; 79 import com.android.systemui.statusbar.policy.KeyguardStateController; 80 81 import dagger.Lazy; 82 83 import java.io.PrintWriter; 84 import java.util.ArrayList; 85 import java.util.List; 86 import java.util.Optional; 87 import java.util.concurrent.Executor; 88 89 import javax.inject.Inject; 90 91 /** 92 * Extracts shared elements between navbar and taskbar delegate to de-dupe logic and help them 93 * experience the joys of friendship. 94 * The events are then passed through 95 * 96 * Currently consolidates 97 * * A11y 98 * * Assistant 99 */ 100 @SysUISingleton 101 public final class NavBarHelper implements 102 AccessibilityManager.AccessibilityServicesStateChangeListener, 103 AccessibilityButtonModeObserver.ModeChangedListener, 104 AccessibilityButtonTargetsObserver.TargetsChangedListener, 105 OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener, 106 Dumpable, CommandQueue.Callbacks, ConfigurationController.ConfigurationListener { 107 private static final String TAG = NavBarHelper.class.getSimpleName(); 108 109 private final Handler mHandler = new Handler(Looper.getMainLooper()); 110 private final Executor mMainExecutor; 111 private final AccessibilityManager mAccessibilityManager; 112 private final Lazy<AssistManager> mAssistManagerLazy; 113 private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; 114 private final KeyguardStateController mKeyguardStateController; 115 private final UserTracker mUserTracker; 116 private final SystemActions mSystemActions; 117 private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; 118 private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver; 119 private final List<NavbarTaskbarStateUpdater> mStateListeners = new ArrayList<>(); 120 private final Context mContext; 121 private final NotificationShadeWindowController mNotificationShadeWindowController; 122 private final CommandQueue mCommandQueue; 123 private final ContentResolver mContentResolver; 124 private final EdgeBackGestureHandler mEdgeBackGestureHandler; 125 private final IWindowManager mWm; 126 private final int mDefaultDisplayId; 127 private boolean mAssistantAvailable; 128 private boolean mLongPressHomeEnabled; 129 private boolean mAssistantTouchGestureEnabled; 130 private int mNavBarMode; 131 private long mA11yButtonState; 132 private int mRotationWatcherRotation; 133 private boolean mTogglingNavbarTaskbar; 134 private boolean mWallpaperVisible; 135 136 // Attributes used in NavBarHelper.CurrentSysuiState 137 private int mWindowStateDisplayId; 138 private @WindowVisibleState int mWindowState; 139 140 // Listens for changes to the assistant 141 private final ContentObserver mAssistContentObserver = new ContentObserver(mHandler) { 142 @Override 143 public void onChange(boolean selfChange, Uri uri) { 144 updateAssistantAvailability(); 145 } 146 }; 147 148 // Listens for changes to the wallpaper visibility 149 private final IWallpaperVisibilityListener mWallpaperVisibilityListener = 150 new IWallpaperVisibilityListener.Stub() { 151 @Override 152 public void onWallpaperVisibilityChanged(boolean visible, 153 int displayId) throws RemoteException { 154 mHandler.post(() -> { 155 mWallpaperVisible = visible; 156 dispatchWallpaperVisibilityChanged(visible, displayId); 157 }); 158 } 159 }; 160 161 // Listens for changes to display rotation 162 private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() { 163 @Override 164 public void onRotationChanged(final int rotation) { 165 // We need this to be scheduled as early as possible to beat the redrawing of 166 // window in response to the orientation change. 167 mHandler.postAtFrontOfQueue(() -> { 168 mRotationWatcherRotation = rotation; 169 dispatchRotationChanged(rotation); 170 }); 171 } 172 }; 173 174 /** 175 * @param context This is not display specific, then again neither is any of the code in 176 * this class. Once there's display specific code, we may want to create an 177 * instance of this class per navbar vs having it be a singleton. 178 */ 179 @Inject NavBarHelper(Context context, AccessibilityManager accessibilityManager, AccessibilityButtonModeObserver accessibilityButtonModeObserver, AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver, SystemActions systemActions, OverviewProxyService overviewProxyService, Lazy<AssistManager> assistManagerLazy, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, KeyguardStateController keyguardStateController, NavigationModeController navigationModeController, EdgeBackGestureHandler.Factory edgeBackGestureHandlerFactory, IWindowManager wm, UserTracker userTracker, DisplayTracker displayTracker, NotificationShadeWindowController notificationShadeWindowController, ConfigurationController configurationController, DumpManager dumpManager, CommandQueue commandQueue, @Main Executor mainExecutor)180 public NavBarHelper(Context context, AccessibilityManager accessibilityManager, 181 AccessibilityButtonModeObserver accessibilityButtonModeObserver, 182 AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver, 183 SystemActions systemActions, 184 OverviewProxyService overviewProxyService, 185 Lazy<AssistManager> assistManagerLazy, 186 Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, 187 KeyguardStateController keyguardStateController, 188 NavigationModeController navigationModeController, 189 EdgeBackGestureHandler.Factory edgeBackGestureHandlerFactory, 190 IWindowManager wm, 191 UserTracker userTracker, 192 DisplayTracker displayTracker, 193 NotificationShadeWindowController notificationShadeWindowController, 194 ConfigurationController configurationController, 195 DumpManager dumpManager, 196 CommandQueue commandQueue, 197 @Main Executor mainExecutor) { 198 // b/319489709: This component shouldn't be running for a non-primary user 199 if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) { 200 Log.wtf(TAG, "Unexpected initialization for non-primary user", new Throwable()); 201 } 202 mContext = context; 203 mNotificationShadeWindowController = notificationShadeWindowController; 204 mCommandQueue = commandQueue; 205 mContentResolver = mContext.getContentResolver(); 206 mAccessibilityManager = accessibilityManager; 207 mAssistManagerLazy = assistManagerLazy; 208 mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; 209 mKeyguardStateController = keyguardStateController; 210 mUserTracker = userTracker; 211 mSystemActions = systemActions; 212 mAccessibilityButtonModeObserver = accessibilityButtonModeObserver; 213 mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver; 214 mWm = wm; 215 mDefaultDisplayId = displayTracker.getDefaultDisplayId(); 216 mEdgeBackGestureHandler = edgeBackGestureHandlerFactory.create(context); 217 mMainExecutor = mainExecutor; 218 219 mNavBarMode = navigationModeController.addListener(this); 220 mCommandQueue.addCallback(this); 221 configurationController.addCallback(this); 222 overviewProxyService.addCallback(this); 223 dumpManager.registerDumpable(this); 224 } 225 226 /** 227 * Hints to the helper that bars are being replaced, which is a signal to potentially suppress 228 * normal setup/cleanup when no bars are present. 229 */ setTogglingNavbarTaskbar(boolean togglingNavbarTaskbar)230 public void setTogglingNavbarTaskbar(boolean togglingNavbarTaskbar) { 231 mTogglingNavbarTaskbar = togglingNavbarTaskbar; 232 } 233 234 /** 235 * Called when the first (non-replacing) bar is registered. 236 */ setupOnFirstBar()237 private void setupOnFirstBar() { 238 // Setup accessibility listeners 239 mAccessibilityManager.addAccessibilityServicesStateChangeListener(this); 240 mAccessibilityButtonModeObserver.addListener(this); 241 mAccessibilityButtonTargetsObserver.addListener(this); 242 243 // Setup assistant listener 244 mContentResolver.registerContentObserver( 245 Settings.Secure.getUriFor(Settings.Secure.ASSISTANT), 246 false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL); 247 mContentResolver.registerContentObserver( 248 Settings.Secure.getUriFor(Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED), 249 false, mAssistContentObserver, UserHandle.USER_ALL); 250 mContentResolver.registerContentObserver( 251 Settings.Secure.getUriFor(Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED), 252 false, mAssistContentObserver, UserHandle.USER_ALL); 253 mContentResolver.registerContentObserver( 254 Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED), 255 false, mAssistContentObserver, UserHandle.USER_ALL); 256 257 // Setup display rotation watcher 258 try { 259 mWm.watchRotation(mRotationWatcher, mDefaultDisplayId); 260 } catch (Exception e) { 261 Log.w(TAG, "Failed to register rotation watcher", e); 262 } 263 264 // Setup wallpaper visibility listener 265 try { 266 mWallpaperVisible = mWm.registerWallpaperVisibilityListener( 267 mWallpaperVisibilityListener, mDefaultDisplayId); 268 } catch (Exception e) { 269 Log.w(TAG, "Failed to register wallpaper visibility listener", e); 270 } 271 272 // Attach the back handler only when the first bar is registered 273 mEdgeBackGestureHandler.onNavBarAttached(); 274 } 275 276 /** 277 * Called after the last (non-replacing) bar is unregistered. 278 */ cleanupAfterLastBar()279 private void cleanupAfterLastBar() { 280 // Clean up accessibility listeners 281 mAccessibilityManager.removeAccessibilityServicesStateChangeListener(this); 282 mAccessibilityButtonModeObserver.removeListener(this); 283 mAccessibilityButtonTargetsObserver.removeListener(this); 284 285 // Clean up assistant listeners 286 mContentResolver.unregisterContentObserver(mAssistContentObserver); 287 288 // Clean up display rotation watcher 289 try { 290 mWm.removeRotationWatcher(mRotationWatcher); 291 } catch (Exception e) { 292 Log.w(TAG, "Failed to unregister rotation watcher", e); 293 } 294 295 // Clean up wallpaper visibility listener 296 try { 297 mWm.unregisterWallpaperVisibilityListener(mWallpaperVisibilityListener, 298 mDefaultDisplayId); 299 } catch (Exception e) { 300 Log.w(TAG, "Failed to register wallpaper visibility listener", e); 301 } 302 303 // No more bars, detach the back handler for now 304 mEdgeBackGestureHandler.onNavBarDetached(); 305 } 306 307 /** 308 * Registers a listener for future updates to the shared navbar/taskbar state. 309 * @param listener Will immediately get callbacks based on current state 310 */ registerNavTaskStateUpdater(NavbarTaskbarStateUpdater listener)311 public void registerNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) { 312 mStateListeners.add(listener); 313 if (!mTogglingNavbarTaskbar && mStateListeners.size() == 1) { 314 setupOnFirstBar(); 315 316 // Update the state once the first bar is registered 317 updateAssistantAvailability(); 318 updateA11yState(); 319 mCommandQueue.recomputeDisableFlags(mContext.getDisplayId(), false /* animate */); 320 } else { 321 listener.updateAccessibilityServicesState(); 322 listener.updateAssistantAvailable(mAssistantAvailable, mLongPressHomeEnabled); 323 } 324 listener.updateWallpaperVisibility(mWallpaperVisible, mDefaultDisplayId); 325 listener.updateRotationWatcherState(mRotationWatcherRotation); 326 } 327 328 /** 329 * Removes a previously registered listener. 330 */ removeNavTaskStateUpdater(NavbarTaskbarStateUpdater listener)331 public void removeNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) { 332 mStateListeners.remove(listener); 333 if (!mTogglingNavbarTaskbar && mStateListeners.isEmpty()) { 334 cleanupAfterLastBar(); 335 } 336 } 337 dispatchA11yEventUpdate()338 private void dispatchA11yEventUpdate() { 339 for (NavbarTaskbarStateUpdater listener : mStateListeners) { 340 listener.updateAccessibilityServicesState(); 341 } 342 } 343 dispatchAssistantEventUpdate(boolean assistantAvailable, boolean longPressHomeEnabled)344 private void dispatchAssistantEventUpdate(boolean assistantAvailable, 345 boolean longPressHomeEnabled) { 346 for (NavbarTaskbarStateUpdater listener : mStateListeners) { 347 listener.updateAssistantAvailable(assistantAvailable, longPressHomeEnabled); 348 } 349 } 350 351 @Override onAccessibilityServicesStateChanged(AccessibilityManager manager)352 public void onAccessibilityServicesStateChanged(AccessibilityManager manager) { 353 updateA11yState(); 354 } 355 356 @Override onAccessibilityButtonModeChanged(int mode)357 public void onAccessibilityButtonModeChanged(int mode) { 358 updateA11yState(); 359 } 360 361 @Override onAccessibilityButtonTargetsChanged(String targets)362 public void onAccessibilityButtonTargetsChanged(String targets) { 363 updateA11yState(); 364 } 365 366 @Override onConfigChanged(Configuration newConfig)367 public void onConfigChanged(Configuration newConfig) { 368 mEdgeBackGestureHandler.onConfigurationChanged(newConfig); 369 } 370 371 /** 372 * Updates the current accessibility button state. The accessibility button state is only 373 * used for {@link Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} and 374 * {@link Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE}, otherwise it is reset to 0. 375 */ updateA11yState()376 private void updateA11yState() { 377 final long prevState = mA11yButtonState; 378 final boolean clickable; 379 final boolean longClickable; 380 if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode() 381 == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) { 382 // If accessibility button is floating menu mode, click and long click state should be 383 // disabled. 384 clickable = false; 385 longClickable = false; 386 mA11yButtonState = 0; 387 } else { 388 // AccessibilityManagerService resolves services for the current user since the local 389 // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS 390 // permission 391 final List<String> a11yButtonTargets = 392 mAccessibilityManager.getAccessibilityShortcutTargets( 393 ShortcutConstants.UserShortcutType.SOFTWARE); 394 final int requestingServices = a11yButtonTargets.size(); 395 396 clickable = requestingServices >= 1; 397 398 // `longClickable` is used to determine whether to pop up the accessibility chooser 399 // dialog or not, and it’s also only for multiple services. 400 longClickable = requestingServices >= 2; 401 mA11yButtonState = (clickable ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0) 402 | (longClickable ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0); 403 } 404 405 // Update the system actions if the state has changed 406 if (prevState != mA11yButtonState) { 407 updateSystemAction(clickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON); 408 updateSystemAction(longClickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER); 409 } 410 411 dispatchA11yEventUpdate(); 412 } 413 414 /** 415 * Registers/unregisters the given system action id. 416 */ updateSystemAction(boolean register, int actionId)417 private void updateSystemAction(boolean register, int actionId) { 418 if (register) { 419 mSystemActions.register(actionId); 420 } else { 421 mSystemActions.unregister(actionId); 422 } 423 } 424 425 /** 426 * Gets the accessibility button state based on the {@link Secure#ACCESSIBILITY_BUTTON_MODE}. 427 * 428 * @return the accessibility button state: 429 * 0 = disable state 430 * 16 = {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} 431 * 48 = the combination of {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and 432 * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE} 433 */ getA11yButtonState()434 public long getA11yButtonState() { 435 return mA11yButtonState; 436 } 437 438 @Override onConnectionChanged(boolean isConnected)439 public void onConnectionChanged(boolean isConnected) { 440 if (isConnected) { 441 // We add the OPS callback during construction, so if the service is already connected 442 // then we will try to get the AssistManager dependency which itself has an indirect 443 // dependency on NavBarHelper leading to a cycle. For now, we can defer updating the 444 // assistant availability. 445 mMainExecutor.execute(this::updateAssistantAvailability); 446 } 447 } 448 updateAssistantAvailability()449 private void updateAssistantAvailability() { 450 boolean assistantAvailableForUser = mAssistManagerLazy.get() 451 .getAssistInfoForUser(mUserTracker.getUserId()) != null; 452 453 boolean overrideLongPressHome = mAssistManagerLazy.get() 454 .shouldOverrideAssist(AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS); 455 boolean longPressDefault = mContext.getResources().getBoolean(overrideLongPressHome 456 ? com.android.internal.R.bool.config_searchAllEntrypointsEnabledDefault 457 : com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault); 458 mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver, 459 overrideLongPressHome ? Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED 460 : Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0, 461 mUserTracker.getUserId()) != 0; 462 463 boolean gestureDefault = mContext.getResources().getBoolean( 464 com.android.internal.R.bool.config_assistTouchGestureEnabledDefault); 465 mAssistantTouchGestureEnabled = Settings.Secure.getIntForUser(mContentResolver, 466 Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0, 467 mUserTracker.getUserId()) != 0; 468 469 mAssistantAvailable = assistantAvailableForUser 470 && mAssistantTouchGestureEnabled 471 && QuickStepContract.isGesturalMode(mNavBarMode); 472 dispatchAssistantEventUpdate(mAssistantAvailable, mLongPressHomeEnabled); 473 } 474 getLongPressHomeEnabled()475 public boolean getLongPressHomeEnabled() { 476 return mLongPressHomeEnabled; 477 } 478 getEdgeBackGestureHandler()479 public EdgeBackGestureHandler getEdgeBackGestureHandler() { 480 return mEdgeBackGestureHandler; 481 } 482 483 @Override startAssistant(Bundle bundle)484 public void startAssistant(Bundle bundle) { 485 mAssistManagerLazy.get().startAssist(bundle); 486 } 487 488 @Override setAssistantOverridesRequested(int[] invocationTypes)489 public void setAssistantOverridesRequested(int[] invocationTypes) { 490 mAssistManagerLazy.get().setAssistantOverridesRequested(invocationTypes); 491 updateAssistantAvailability(); 492 } 493 494 @Override onNavigationModeChanged(int mode)495 public void onNavigationModeChanged(int mode) { 496 mNavBarMode = mode; 497 updateAssistantAvailability(); 498 } 499 500 /** 501 * @return Whether the IME is shown on top of the screen given the {@code vis} flag of 502 * {@link InputMethodService} and the keyguard states. 503 */ isImeShown(int vis)504 public boolean isImeShown(int vis) { 505 View shadeWindowView = mNotificationShadeWindowController.getWindowRootView(); 506 boolean isKeyguardShowing = mKeyguardStateController.isShowing(); 507 boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow() 508 && shadeWindowView.getRootWindowInsets().isVisible(WindowInsets.Type.ime()); 509 return imeVisibleOnShade 510 || (!isKeyguardShowing && (vis & InputMethodService.IME_VISIBLE) != 0); 511 } 512 513 @Override setWindowState(int displayId, int window, int state)514 public void setWindowState(int displayId, int window, int state) { 515 CommandQueue.Callbacks.super.setWindowState(displayId, window, state); 516 if (window != WINDOW_NAVIGATION_BAR) { 517 return; 518 } 519 mWindowStateDisplayId = displayId; 520 mWindowState = state; 521 } 522 dispatchWallpaperVisibilityChanged(boolean visible, int displayId)523 private void dispatchWallpaperVisibilityChanged(boolean visible, int displayId) { 524 for (NavbarTaskbarStateUpdater listener : mStateListeners) { 525 listener.updateWallpaperVisibility(visible, displayId); 526 } 527 } 528 dispatchRotationChanged(int rotation)529 private void dispatchRotationChanged(int rotation) { 530 for (NavbarTaskbarStateUpdater listener : mStateListeners) { 531 listener.updateRotationWatcherState(rotation); 532 } 533 } 534 getCurrentSysuiState()535 public CurrentSysuiState getCurrentSysuiState() { 536 return new CurrentSysuiState(); 537 } 538 539 /** 540 * Callbacks will get fired once immediately after registering via 541 * {@link #registerNavTaskStateUpdater(NavbarTaskbarStateUpdater)} 542 */ 543 public interface NavbarTaskbarStateUpdater { updateAccessibilityServicesState()544 void updateAccessibilityServicesState(); updateAssistantAvailable(boolean available, boolean longPressHomeEnabled)545 void updateAssistantAvailable(boolean available, boolean longPressHomeEnabled); updateWallpaperVisibility(boolean visible, int displayId)546 default void updateWallpaperVisibility(boolean visible, int displayId) {} updateRotationWatcherState(int rotation)547 default void updateRotationWatcherState(int rotation) {} 548 } 549 550 /** Data class to help Taskbar/Navbar initiate state correctly when switching between the two.*/ 551 public class CurrentSysuiState { 552 public final int mWindowStateDisplayId; 553 public final @WindowVisibleState int mWindowState; 554 CurrentSysuiState()555 public CurrentSysuiState() { 556 mWindowStateDisplayId = NavBarHelper.this.mWindowStateDisplayId; 557 mWindowState = NavBarHelper.this.mWindowState; 558 } 559 } 560 transitionMode(boolean isTransient, int appearance)561 static @TransitionMode int transitionMode(boolean isTransient, int appearance) { 562 final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS; 563 if (isTransient) { 564 return MODE_SEMI_TRANSPARENT; 565 } else if ((appearance & lightsOutOpaque) == lightsOutOpaque) { 566 return MODE_LIGHTS_OUT; 567 } else if ((appearance & APPEARANCE_LOW_PROFILE_BARS) != 0) { 568 return MODE_LIGHTS_OUT_TRANSPARENT; 569 } else if ((appearance & APPEARANCE_OPAQUE_NAVIGATION_BARS) != 0) { 570 return MODE_OPAQUE; 571 } else if ((appearance & APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS) != 0) { 572 return MODE_SEMI_TRANSPARENT; 573 } else { 574 return MODE_TRANSPARENT; 575 } 576 } 577 578 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)579 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 580 pw.println("NavbarTaskbarFriendster"); 581 pw.println(" longPressHomeEnabled=" + mLongPressHomeEnabled); 582 pw.println(" mAssistantTouchGestureEnabled=" + mAssistantTouchGestureEnabled); 583 pw.println(" mAssistantAvailable=" + mAssistantAvailable); 584 pw.println(" mNavBarMode=" + mNavBarMode); 585 } 586 } 587