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