1 /* 2 * Copyright (C) 2017 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.recents; 18 19 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; 20 import static android.view.Display.DEFAULT_DISPLAY; 21 import static android.view.MotionEvent.ACTION_CANCEL; 22 import static android.view.MotionEvent.ACTION_DOWN; 23 import static android.view.MotionEvent.ACTION_UP; 24 import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW; 25 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; 26 27 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; 28 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS; 29 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED; 30 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP; 31 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; 32 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN; 33 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW; 34 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER; 35 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS; 36 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; 37 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS; 38 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; 39 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING; 40 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; 41 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; 42 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; 43 44 import android.annotation.FloatRange; 45 import android.app.ActivityTaskManager; 46 import android.content.BroadcastReceiver; 47 import android.content.ComponentName; 48 import android.content.Context; 49 import android.content.Intent; 50 import android.content.IntentFilter; 51 import android.content.ServiceConnection; 52 import android.graphics.Bitmap; 53 import android.graphics.Insets; 54 import android.graphics.Rect; 55 import android.graphics.Region; 56 import android.hardware.input.InputManager; 57 import android.os.Binder; 58 import android.os.Bundle; 59 import android.os.Handler; 60 import android.os.IBinder; 61 import android.os.Looper; 62 import android.os.PatternMatcher; 63 import android.os.RemoteException; 64 import android.os.SystemClock; 65 import android.os.UserHandle; 66 import android.util.Log; 67 import android.view.InputDevice; 68 import android.view.KeyCharacterMap; 69 import android.view.KeyEvent; 70 import android.view.MotionEvent; 71 import android.view.Surface; 72 import android.view.accessibility.AccessibilityManager; 73 import android.view.inputmethod.InputMethodManager; 74 75 import androidx.annotation.NonNull; 76 77 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity; 78 import com.android.internal.annotations.VisibleForTesting; 79 import com.android.internal.logging.UiEventLogger; 80 import com.android.internal.policy.ScreenDecorationsUtils; 81 import com.android.internal.util.ScreenshotHelper; 82 import com.android.systemui.Dumpable; 83 import com.android.systemui.broadcast.BroadcastDispatcher; 84 import com.android.systemui.dagger.SysUISingleton; 85 import com.android.systemui.dump.DumpManager; 86 import com.android.systemui.keyguard.ScreenLifecycle; 87 import com.android.systemui.model.SysUiState; 88 import com.android.systemui.navigationbar.NavigationBar; 89 import com.android.systemui.navigationbar.NavigationBarController; 90 import com.android.systemui.navigationbar.NavigationBarView; 91 import com.android.systemui.navigationbar.NavigationModeController; 92 import com.android.systemui.navigationbar.buttons.KeyButtonView; 93 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; 94 import com.android.systemui.settings.CurrentUserTracker; 95 import com.android.systemui.shared.recents.IOverviewProxy; 96 import com.android.systemui.shared.recents.ISystemUiProxy; 97 import com.android.systemui.shared.recents.model.Task; 98 import com.android.systemui.shared.system.ActivityManagerWrapper; 99 import com.android.systemui.shared.system.QuickStepContract; 100 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController; 101 import com.android.systemui.statusbar.CommandQueue; 102 import com.android.systemui.statusbar.NotificationShadeWindowController; 103 import com.android.systemui.statusbar.phone.NotificationPanelViewController; 104 import com.android.systemui.statusbar.phone.StatusBar; 105 import com.android.systemui.statusbar.phone.StatusBarWindowCallback; 106 import com.android.systemui.statusbar.policy.CallbackController; 107 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; 108 import com.android.wm.shell.onehanded.OneHanded; 109 import com.android.wm.shell.pip.Pip; 110 import com.android.wm.shell.pip.PipAnimationController; 111 import com.android.wm.shell.recents.RecentTasks; 112 import com.android.wm.shell.splitscreen.SplitScreen; 113 import com.android.wm.shell.startingsurface.StartingSurface; 114 import com.android.wm.shell.transition.ShellTransitions; 115 116 import java.io.FileDescriptor; 117 import java.io.PrintWriter; 118 import java.util.ArrayList; 119 import java.util.List; 120 import java.util.Optional; 121 import java.util.function.BiConsumer; 122 import java.util.function.Supplier; 123 124 import javax.inject.Inject; 125 126 import dagger.Lazy; 127 128 129 /** 130 * Class to send information from overview to launcher with a binder. 131 */ 132 @SysUISingleton 133 public class OverviewProxyService extends CurrentUserTracker implements 134 CallbackController<OverviewProxyListener>, NavigationModeController.ModeChangedListener, 135 Dumpable { 136 137 private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE"; 138 139 public static final String TAG_OPS = "OverviewProxyService"; 140 private static final long BACKOFF_MILLIS = 1000; 141 private static final long DEFERRED_CALLBACK_MILLIS = 5000; 142 143 // Max backoff caps at 5 mins 144 private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000; 145 146 private final Context mContext; 147 private final Optional<Pip> mPipOptional; 148 private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; 149 private final Optional<LegacySplitScreen> mLegacySplitScreenOptional; 150 private final Optional<SplitScreen> mSplitScreenOptional; 151 private SysUiState mSysUiState; 152 private final Handler mHandler; 153 private final Lazy<NavigationBarController> mNavBarControllerLazy; 154 private final NotificationShadeWindowController mStatusBarWinController; 155 private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser; 156 private final ComponentName mRecentsComponentName; 157 private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>(); 158 private final Intent mQuickStepIntent; 159 private final ScreenshotHelper mScreenshotHelper; 160 private final Optional<OneHanded> mOneHandedOptional; 161 private final CommandQueue mCommandQueue; 162 private final ShellTransitions mShellTransitions; 163 private final Optional<StartingSurface> mStartingSurface; 164 private final SmartspaceTransitionController mSmartspaceTransitionController; 165 private final Optional<RecentTasks> mRecentTasks; 166 private final UiEventLogger mUiEventLogger; 167 168 private Region mActiveNavBarRegion; 169 170 private IOverviewProxy mOverviewProxy; 171 private int mConnectionBackoffAttempts; 172 private boolean mBound; 173 private boolean mIsEnabled; 174 private int mCurrentBoundedUserId = -1; 175 private float mNavBarButtonAlpha; 176 private boolean mInputFocusTransferStarted; 177 private float mInputFocusTransferStartY; 178 private long mInputFocusTransferStartMillis; 179 private float mWindowCornerRadius; 180 private boolean mSupportsRoundedCornersOnWindows; 181 private int mNavBarMode = NAV_BAR_MODE_3BUTTON; 182 183 @VisibleForTesting 184 public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() { 185 @Override 186 public void startScreenPinning(int taskId) { 187 verifyCallerAndClearCallingIdentityPostMain("startScreenPinning", () -> 188 mStatusBarOptionalLazy.get().ifPresent( 189 statusBar -> statusBar.showScreenPinningRequest(taskId, 190 false /* allowCancel */))); 191 } 192 193 @Override 194 public void stopScreenPinning() { 195 verifyCallerAndClearCallingIdentityPostMain("stopScreenPinning", () -> { 196 try { 197 ActivityTaskManager.getService().stopSystemLockTaskMode(); 198 } catch (RemoteException e) { 199 Log.e(TAG_OPS, "Failed to stop screen pinning"); 200 } 201 }); 202 } 203 204 // TODO: change the method signature to use (boolean inputFocusTransferStarted) 205 @Override 206 public void onStatusBarMotionEvent(MotionEvent event) { 207 verifyCallerAndClearCallingIdentity("onStatusBarMotionEvent", () -> { 208 // TODO move this logic to message queue 209 mStatusBarOptionalLazy.get().ifPresent(statusBar -> { 210 if (event.getActionMasked() == ACTION_DOWN) { 211 statusBar.getPanelController().startExpandLatencyTracking(); 212 } 213 mHandler.post(() -> { 214 int action = event.getActionMasked(); 215 if (action == ACTION_DOWN) { 216 mInputFocusTransferStarted = true; 217 mInputFocusTransferStartY = event.getY(); 218 mInputFocusTransferStartMillis = event.getEventTime(); 219 statusBar.onInputFocusTransfer( 220 mInputFocusTransferStarted, false /* cancel */, 221 0 /* velocity */); 222 } 223 if (action == ACTION_UP || action == ACTION_CANCEL) { 224 mInputFocusTransferStarted = false; 225 float velocity = (event.getY() - mInputFocusTransferStartY) 226 / (event.getEventTime() - mInputFocusTransferStartMillis); 227 statusBar.onInputFocusTransfer(mInputFocusTransferStarted, 228 action == ACTION_CANCEL, 229 velocity); 230 } 231 event.recycle(); 232 }); 233 }); 234 }); 235 } 236 237 @Override 238 public void onBackPressed() throws RemoteException { 239 verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> { 240 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); 241 sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); 242 243 notifyBackAction(true, -1, -1, true, false); 244 }); 245 } 246 247 @Override 248 public void onImeSwitcherPressed() throws RemoteException { 249 // TODO(b/204901476) We're intentionally using DEFAULT_DISPLAY for now since 250 // Launcher/Taskbar isn't display aware. 251 mContext.getSystemService(InputMethodManager.class) 252 .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */, 253 DEFAULT_DISPLAY); 254 mUiEventLogger.log(KeyButtonView.NavBarButtonEvent.NAVBAR_IME_SWITCHER_BUTTON_TAP); 255 } 256 257 @Override 258 public void setHomeRotationEnabled(boolean enabled) { 259 verifyCallerAndClearCallingIdentityPostMain("setHomeRotationEnabled", () -> 260 mHandler.post(() -> notifyHomeRotationEnabled(enabled))); 261 } 262 263 @Override 264 public void notifyTaskbarStatus(boolean visible, boolean stashed) { 265 verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarStatus", () -> 266 onTaskbarStatusUpdated(visible, stashed)); 267 } 268 269 @Override 270 public void notifyTaskbarAutohideSuspend(boolean suspend) { 271 verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarAutohideSuspend", () -> 272 onTaskbarAutohideSuspend(suspend)); 273 } 274 275 private boolean sendEvent(int action, int code) { 276 long when = SystemClock.uptimeMillis(); 277 final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */, 278 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */, 279 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, 280 InputDevice.SOURCE_KEYBOARD); 281 282 ev.setDisplayId(mContext.getDisplay().getDisplayId()); 283 return InputManager.getInstance() 284 .injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 285 } 286 287 @Override 288 public void onOverviewShown(boolean fromHome) { 289 verifyCallerAndClearCallingIdentityPostMain("onOverviewShown", () -> { 290 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 291 mConnectionCallbacks.get(i).onOverviewShown(fromHome); 292 } 293 }); 294 } 295 296 @Override 297 public Rect getNonMinimizedSplitScreenSecondaryBounds() { 298 return verifyCallerAndClearCallingIdentity( 299 "getNonMinimizedSplitScreenSecondaryBounds", 300 () -> mLegacySplitScreenOptional.map(splitScreen -> 301 splitScreen 302 .getDividerView() 303 .getNonMinimizedSplitScreenSecondaryBounds()) 304 .orElse(null) 305 ); 306 } 307 308 @Override 309 public void setNavBarButtonAlpha(float alpha, boolean animate) { 310 verifyCallerAndClearCallingIdentityPostMain("setNavBarButtonAlpha", () -> 311 notifyNavBarButtonAlphaChanged(alpha, animate)); 312 } 313 314 @Override 315 public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) { 316 verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () -> 317 notifyAssistantProgress(progress)); 318 } 319 320 @Override 321 public void onAssistantGestureCompletion(float velocity) { 322 verifyCallerAndClearCallingIdentityPostMain("onAssistantGestureCompletion", () -> 323 notifyAssistantGestureCompletion(velocity)); 324 } 325 326 @Override 327 public void startAssistant(Bundle bundle) { 328 verifyCallerAndClearCallingIdentityPostMain("startAssistant", () -> 329 notifyStartAssistant(bundle)); 330 } 331 332 @Override 333 public void notifyAccessibilityButtonClicked(int displayId) { 334 verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonClicked", () -> 335 AccessibilityManager.getInstance(mContext) 336 .notifyAccessibilityButtonClicked(displayId)); 337 } 338 339 @Override 340 public void notifyAccessibilityButtonLongClicked() { 341 verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonLongClicked", 342 () -> { 343 final Intent intent = 344 new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON); 345 final String chooserClassName = AccessibilityButtonChooserActivity 346 .class.getName(); 347 intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName); 348 intent.addFlags( 349 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 350 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 351 }); 352 } 353 354 @Override 355 public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen, 356 Insets visibleInsets, int taskId) { 357 // Deprecated 358 } 359 360 @Override 361 public void setSplitScreenMinimized(boolean minimized) { 362 mLegacySplitScreenOptional.ifPresent( 363 splitScreen -> splitScreen.setMinimized(minimized)); 364 } 365 366 @Override 367 public void notifySwipeToHomeFinished() { 368 verifyCallerAndClearCallingIdentity("notifySwipeToHomeFinished", () -> 369 mPipOptional.ifPresent( 370 pip -> pip.setPinnedStackAnimationType( 371 PipAnimationController.ANIM_TYPE_ALPHA))); 372 } 373 374 @Override 375 public void notifySwipeUpGestureStarted() { 376 verifyCallerAndClearCallingIdentityPostMain("notifySwipeUpGestureStarted", () -> 377 notifySwipeUpGestureStartedInternal()); 378 } 379 380 @Override 381 public void notifyPrioritizedRotation(@Surface.Rotation int rotation) { 382 verifyCallerAndClearCallingIdentityPostMain("notifyPrioritizedRotation", () -> 383 notifyPrioritizedRotationInternal(rotation)); 384 } 385 386 @Override 387 public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen, 388 Insets visibleInsets, Task.TaskKey task) { 389 mScreenshotHelper.provideScreenshot( 390 screenImageBundle, 391 locationInScreen, 392 visibleInsets, 393 task.id, 394 task.userId, 395 task.sourceComponent, 396 SCREENSHOT_OVERVIEW, 397 mHandler, 398 null); 399 } 400 401 @Override 402 public void expandNotificationPanel() { 403 verifyCallerAndClearCallingIdentity("expandNotificationPanel", 404 () -> mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN)); 405 } 406 407 private boolean verifyCaller(String reason) { 408 final int callerId = Binder.getCallingUserHandle().getIdentifier(); 409 if (callerId != mCurrentBoundedUserId) { 410 Log.w(TAG_OPS, "Launcher called sysui with invalid user: " + callerId + ", reason: " 411 + reason); 412 return false; 413 } 414 return true; 415 } 416 417 private <T> T verifyCallerAndClearCallingIdentity(String reason, Supplier<T> supplier) { 418 if (!verifyCaller(reason)) { 419 return null; 420 } 421 final long token = Binder.clearCallingIdentity(); 422 try { 423 return supplier.get(); 424 } finally { 425 Binder.restoreCallingIdentity(token); 426 } 427 } 428 429 private void verifyCallerAndClearCallingIdentity(String reason, Runnable runnable) { 430 verifyCallerAndClearCallingIdentity(reason, () -> { 431 runnable.run(); 432 return null; 433 }); 434 } 435 436 private void verifyCallerAndClearCallingIdentityPostMain(String reason, Runnable runnable) { 437 verifyCallerAndClearCallingIdentity(reason, () -> mHandler.post(runnable)); 438 } 439 }; 440 441 private final Runnable mDeferredConnectionCallback = () -> { 442 Log.w(TAG_OPS, "Binder supposed established connection but actual connection to service " 443 + "timed out, trying again"); 444 retryConnectionWithBackoff(); 445 }; 446 447 private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() { 448 @Override 449 public void onReceive(Context context, Intent intent) { 450 updateEnabledState(); 451 452 // Reconnect immediately, instead of waiting for resume to arrive. 453 startConnectionToCurrentUser(); 454 } 455 }; 456 457 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() { 458 @Override 459 public void onServiceConnected(ComponentName name, IBinder service) { 460 if (SysUiState.DEBUG) { 461 Log.d(TAG_OPS, "Overview proxy service connected"); 462 } 463 mConnectionBackoffAttempts = 0; 464 mHandler.removeCallbacks(mDeferredConnectionCallback); 465 try { 466 service.linkToDeath(mOverviewServiceDeathRcpt, 0); 467 } catch (RemoteException e) { 468 // Failed to link to death (process may have died between binding and connecting), 469 // just unbind the service for now and retry again 470 Log.e(TAG_OPS, "Lost connection to launcher service", e); 471 disconnectFromLauncherService(); 472 retryConnectionWithBackoff(); 473 return; 474 } 475 476 mCurrentBoundedUserId = getCurrentUserId(); 477 mOverviewProxy = IOverviewProxy.Stub.asInterface(service); 478 479 Bundle params = new Bundle(); 480 params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder()); 481 params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius); 482 params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows); 483 484 mPipOptional.ifPresent((pip) -> params.putBinder( 485 KEY_EXTRA_SHELL_PIP, 486 pip.createExternalInterface().asBinder())); 487 mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder( 488 KEY_EXTRA_SHELL_SPLIT_SCREEN, 489 splitscreen.createExternalInterface().asBinder())); 490 mOneHandedOptional.ifPresent((onehanded) -> params.putBinder( 491 KEY_EXTRA_SHELL_ONE_HANDED, 492 onehanded.createExternalInterface().asBinder())); 493 params.putBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS, 494 mShellTransitions.createExternalInterface().asBinder()); 495 mStartingSurface.ifPresent((startingwindow) -> params.putBinder( 496 KEY_EXTRA_SHELL_STARTING_WINDOW, 497 startingwindow.createExternalInterface().asBinder())); 498 params.putBinder( 499 KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER, 500 mSmartspaceTransitionController.createExternalInterface().asBinder()); 501 mRecentTasks.ifPresent(recentTasks -> params.putBinder( 502 KEY_EXTRA_RECENT_TASKS, 503 recentTasks.createExternalInterface().asBinder())); 504 505 try { 506 mOverviewProxy.onInitialize(params); 507 } catch (RemoteException e) { 508 mCurrentBoundedUserId = -1; 509 Log.e(TAG_OPS, "Failed to call onInitialize()", e); 510 } 511 dispatchNavButtonBounds(); 512 513 // Force-update the systemui state flags 514 updateSystemUiStateFlags(); 515 notifySystemUiStateFlags(mSysUiState.getFlags()); 516 517 notifyConnectionChanged(); 518 } 519 520 @Override 521 public void onNullBinding(ComponentName name) { 522 Log.w(TAG_OPS, "Null binding of '" + name + "', try reconnecting"); 523 mCurrentBoundedUserId = -1; 524 retryConnectionWithBackoff(); 525 } 526 527 @Override 528 public void onBindingDied(ComponentName name) { 529 Log.w(TAG_OPS, "Binding died of '" + name + "', try reconnecting"); 530 mCurrentBoundedUserId = -1; 531 retryConnectionWithBackoff(); 532 } 533 534 @Override 535 public void onServiceDisconnected(ComponentName name) { 536 Log.w(TAG_OPS, "Service disconnected"); 537 // Do nothing 538 mCurrentBoundedUserId = -1; 539 } 540 }; 541 542 private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged; 543 private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener = 544 this::notifySplitScreenBoundsChanged; 545 546 // This is the death handler for the binder from the launcher service 547 private final IBinder.DeathRecipient mOverviewServiceDeathRcpt 548 = this::cleanupAfterDeath; 549 550 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") 551 @Inject OverviewProxyService(Context context, CommandQueue commandQueue, Lazy<NavigationBarController> navBarControllerLazy, Lazy<Optional<StatusBar>> statusBarOptionalLazy, NavigationModeController navModeController, NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, Optional<Pip> pipOptional, Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<SplitScreen> splitScreenOptional, Optional<OneHanded> oneHandedOptional, Optional<RecentTasks> recentTasks, Optional<StartingSurface> startingSurface, BroadcastDispatcher broadcastDispatcher, ShellTransitions shellTransitions, ScreenLifecycle screenLifecycle, SmartspaceTransitionController smartspaceTransitionController, UiEventLogger uiEventLogger, DumpManager dumpManager)552 public OverviewProxyService(Context context, CommandQueue commandQueue, 553 Lazy<NavigationBarController> navBarControllerLazy, 554 Lazy<Optional<StatusBar>> statusBarOptionalLazy, 555 NavigationModeController navModeController, 556 NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, 557 Optional<Pip> pipOptional, 558 Optional<LegacySplitScreen> legacySplitScreenOptional, 559 Optional<SplitScreen> splitScreenOptional, 560 Optional<OneHanded> oneHandedOptional, 561 Optional<RecentTasks> recentTasks, 562 Optional<StartingSurface> startingSurface, 563 BroadcastDispatcher broadcastDispatcher, 564 ShellTransitions shellTransitions, 565 ScreenLifecycle screenLifecycle, 566 SmartspaceTransitionController smartspaceTransitionController, 567 UiEventLogger uiEventLogger, 568 DumpManager dumpManager) { 569 super(broadcastDispatcher); 570 mContext = context; 571 mPipOptional = pipOptional; 572 mStatusBarOptionalLazy = statusBarOptionalLazy; 573 mHandler = new Handler(); 574 mNavBarControllerLazy = navBarControllerLazy; 575 mStatusBarWinController = statusBarWinController; 576 mConnectionBackoffAttempts = 0; 577 mRecentsComponentName = ComponentName.unflattenFromString(context.getString( 578 com.android.internal.R.string.config_recentsComponentName)); 579 mQuickStepIntent = new Intent(ACTION_QUICKSTEP) 580 .setPackage(mRecentsComponentName.getPackageName()); 581 mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext); 582 mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils 583 .supportsRoundedCornersOnWindows(mContext.getResources()); 584 mSysUiState = sysUiState; 585 mSysUiState.addCallback(this::notifySystemUiStateFlags); 586 mOneHandedOptional = oneHandedOptional; 587 mShellTransitions = shellTransitions; 588 mRecentTasks = recentTasks; 589 mUiEventLogger = uiEventLogger; 590 591 // Assumes device always starts with back button until launcher tells it that it does not 592 mNavBarButtonAlpha = 1.0f; 593 594 dumpManager.registerDumpable(getClass().getSimpleName(), this); 595 596 // Listen for nav bar mode changes 597 mNavBarMode = navModeController.addListener(this); 598 599 // Listen for launcher package changes 600 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 601 filter.addDataScheme("package"); 602 filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(), 603 PatternMatcher.PATTERN_LITERAL); 604 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 605 mContext.registerReceiver(mLauncherStateChangedReceiver, filter); 606 607 // Listen for status bar state changes 608 statusBarWinController.registerCallback(mStatusBarWindowCallback); 609 mScreenshotHelper = new ScreenshotHelper(context); 610 611 // Listen for tracing state changes 612 commandQueue.addCallback(new CommandQueue.Callbacks() { 613 @Override 614 public void onTracingStateChanged(boolean enabled) { 615 mSysUiState.setFlag(SYSUI_STATE_TRACING_ENABLED, enabled) 616 .commitUpdate(mContext.getDisplayId()); 617 } 618 }); 619 mCommandQueue = commandQueue; 620 621 mSplitScreenOptional = splitScreenOptional; 622 legacySplitScreenOptional.ifPresent(splitScreen -> 623 splitScreen.registerBoundsChangeListener(mSplitScreenBoundsChangeListener)); 624 mLegacySplitScreenOptional = legacySplitScreenOptional; 625 626 // Listen for user setup 627 startTracking(); 628 629 screenLifecycle.addObserver(new ScreenLifecycle.Observer() { 630 @Override 631 public void onScreenTurnedOn() { 632 notifyScreenTurnedOn(); 633 } 634 }); 635 636 // Connect to the service 637 updateEnabledState(); 638 startConnectionToCurrentUser(); 639 mStartingSurface = startingSurface; 640 mSmartspaceTransitionController = smartspaceTransitionController; 641 } 642 643 @Override onUserSwitched(int newUserId)644 public void onUserSwitched(int newUserId) { 645 mConnectionBackoffAttempts = 0; 646 internalConnectToCurrentUser(); 647 } 648 notifyBackAction(boolean completed, int downX, int downY, boolean isButton, boolean gestureSwipeLeft)649 public void notifyBackAction(boolean completed, int downX, int downY, boolean isButton, 650 boolean gestureSwipeLeft) { 651 try { 652 if (mOverviewProxy != null) { 653 mOverviewProxy.onBackAction(completed, downX, downY, isButton, gestureSwipeLeft); 654 } 655 } catch (RemoteException e) { 656 Log.e(TAG_OPS, "Failed to notify back action", e); 657 } 658 } 659 updateSystemUiStateFlags()660 private void updateSystemUiStateFlags() { 661 final NavigationBar navBarFragment = 662 mNavBarControllerLazy.get().getDefaultNavigationBar(); 663 final NavigationBarView navBarView = 664 mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId()); 665 final NotificationPanelViewController panelController = 666 mStatusBarOptionalLazy.get().get().getPanelController(); 667 if (SysUiState.DEBUG) { 668 Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment 669 + " navBarView=" + navBarView + " panelController=" + panelController); 670 } 671 672 if (navBarFragment != null) { 673 navBarFragment.updateSystemUiStateFlags(-1); 674 } 675 if (navBarView != null) { 676 navBarView.updateDisabledSystemUiStateFlags(); 677 } 678 if (panelController != null) { 679 panelController.updateSystemUiStateFlags(); 680 } 681 if (mStatusBarWinController != null) { 682 mStatusBarWinController.notifyStateChangedCallbacks(); 683 } 684 } 685 notifySystemUiStateFlags(int flags)686 private void notifySystemUiStateFlags(int flags) { 687 if (SysUiState.DEBUG) { 688 Log.d(TAG_OPS, "Notifying sysui state change to overview service: proxy=" 689 + mOverviewProxy + " flags=" + flags); 690 } 691 try { 692 if (mOverviewProxy != null) { 693 mOverviewProxy.onSystemUiStateChanged(flags); 694 } 695 } catch (RemoteException e) { 696 Log.e(TAG_OPS, "Failed to notify sysui state change", e); 697 } 698 } 699 onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing, boolean isDozing)700 private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded, 701 boolean bouncerShowing, boolean isDozing) { 702 mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING, 703 keyguardShowing && !keyguardOccluded) 704 .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED, 705 keyguardShowing && keyguardOccluded) 706 .setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing) 707 .setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing) 708 .commitUpdate(mContext.getDisplayId()); 709 } 710 711 /** 712 * Sets the navbar region which can receive touch inputs 713 */ onActiveNavBarRegionChanges(Region activeRegion)714 public void onActiveNavBarRegionChanges(Region activeRegion) { 715 mActiveNavBarRegion = activeRegion; 716 dispatchNavButtonBounds(); 717 } 718 dispatchNavButtonBounds()719 private void dispatchNavButtonBounds() { 720 if (mOverviewProxy != null && mActiveNavBarRegion != null) { 721 try { 722 mOverviewProxy.onActiveNavBarRegionChanges(mActiveNavBarRegion); 723 } catch (RemoteException e) { 724 Log.e(TAG_OPS, "Failed to call onActiveNavBarRegionChanges()", e); 725 } 726 } 727 } 728 cleanupAfterDeath()729 public void cleanupAfterDeath() { 730 if (mInputFocusTransferStarted) { 731 mHandler.post(() -> { 732 mStatusBarOptionalLazy.get().ifPresent(statusBar -> { 733 mInputFocusTransferStarted = false; 734 statusBar.onInputFocusTransfer(false, true /* cancel */, 0 /* velocity */); 735 }); 736 }); 737 } 738 startConnectionToCurrentUser(); 739 740 // Clean up the minimized state if launcher dies 741 mLegacySplitScreenOptional.ifPresent( 742 splitScreen -> splitScreen.setMinimized(false)); 743 } 744 startConnectionToCurrentUser()745 public void startConnectionToCurrentUser() { 746 if (mHandler.getLooper() != Looper.myLooper()) { 747 mHandler.post(mConnectionRunnable); 748 } else { 749 internalConnectToCurrentUser(); 750 } 751 } 752 internalConnectToCurrentUser()753 private void internalConnectToCurrentUser() { 754 disconnectFromLauncherService(); 755 756 // If user has not setup yet or already connected, do not try to connect 757 if (!isEnabled()) { 758 Log.v(TAG_OPS, "Cannot attempt connection, is enabled " + isEnabled()); 759 return; 760 } 761 mHandler.removeCallbacks(mConnectionRunnable); 762 Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP) 763 .setPackage(mRecentsComponentName.getPackageName()); 764 try { 765 mBound = mContext.bindServiceAsUser(launcherServiceIntent, 766 mOverviewServiceConnection, 767 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, 768 UserHandle.of(getCurrentUserId())); 769 } catch (SecurityException e) { 770 Log.e(TAG_OPS, "Unable to bind because of security error", e); 771 } 772 if (mBound) { 773 // Ensure that connection has been established even if it thinks it is bound 774 mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS); 775 } else { 776 // Retry after exponential backoff timeout 777 retryConnectionWithBackoff(); 778 } 779 } 780 retryConnectionWithBackoff()781 private void retryConnectionWithBackoff() { 782 if (mHandler.hasCallbacks(mConnectionRunnable)) { 783 return; 784 } 785 final long timeoutMs = (long) Math.min( 786 Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts), MAX_BACKOFF_MILLIS); 787 mHandler.postDelayed(mConnectionRunnable, timeoutMs); 788 mConnectionBackoffAttempts++; 789 Log.w(TAG_OPS, "Failed to connect on attempt " + mConnectionBackoffAttempts 790 + " will try again in " + timeoutMs + "ms"); 791 } 792 793 @Override addCallback(@onNull OverviewProxyListener listener)794 public void addCallback(@NonNull OverviewProxyListener listener) { 795 if (!mConnectionCallbacks.contains(listener)) { 796 mConnectionCallbacks.add(listener); 797 } 798 listener.onConnectionChanged(mOverviewProxy != null); 799 listener.onNavBarButtonAlphaChanged(mNavBarButtonAlpha, false); 800 } 801 802 @Override removeCallback(@onNull OverviewProxyListener listener)803 public void removeCallback(@NonNull OverviewProxyListener listener) { 804 mConnectionCallbacks.remove(listener); 805 } 806 shouldShowSwipeUpUI()807 public boolean shouldShowSwipeUpUI() { 808 return isEnabled() && !QuickStepContract.isLegacyMode(mNavBarMode); 809 } 810 isEnabled()811 public boolean isEnabled() { 812 return mIsEnabled; 813 } 814 getProxy()815 public IOverviewProxy getProxy() { 816 return mOverviewProxy; 817 } 818 disconnectFromLauncherService()819 private void disconnectFromLauncherService() { 820 if (mBound) { 821 // Always unbind the service (ie. if called through onNullBinding or onBindingDied) 822 mContext.unbindService(mOverviewServiceConnection); 823 mBound = false; 824 } 825 826 if (mOverviewProxy != null) { 827 mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0); 828 mOverviewProxy = null; 829 notifyNavBarButtonAlphaChanged(1f, false /* animate */); 830 notifyConnectionChanged(); 831 } 832 } 833 notifyNavBarButtonAlphaChanged(float alpha, boolean animate)834 private void notifyNavBarButtonAlphaChanged(float alpha, boolean animate) { 835 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 836 mConnectionCallbacks.get(i).onNavBarButtonAlphaChanged(alpha, animate); 837 } 838 } 839 notifyHomeRotationEnabled(boolean enabled)840 private void notifyHomeRotationEnabled(boolean enabled) { 841 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 842 mConnectionCallbacks.get(i).onHomeRotationEnabled(enabled); 843 } 844 } 845 onTaskbarStatusUpdated(boolean visible, boolean stashed)846 private void onTaskbarStatusUpdated(boolean visible, boolean stashed) { 847 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 848 mConnectionCallbacks.get(i).onTaskbarStatusUpdated(visible, stashed); 849 } 850 } 851 onTaskbarAutohideSuspend(boolean suspend)852 private void onTaskbarAutohideSuspend(boolean suspend) { 853 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 854 mConnectionCallbacks.get(i).onTaskbarAutohideSuspend(suspend); 855 } 856 } 857 notifyConnectionChanged()858 private void notifyConnectionChanged() { 859 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 860 mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null); 861 } 862 } 863 notifyQuickStepStarted()864 public void notifyQuickStepStarted() { 865 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 866 mConnectionCallbacks.get(i).onQuickStepStarted(); 867 } 868 } 869 notifyPrioritizedRotationInternal(@urface.Rotation int rotation)870 private void notifyPrioritizedRotationInternal(@Surface.Rotation int rotation) { 871 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 872 mConnectionCallbacks.get(i).onPrioritizedRotation(rotation); 873 } 874 } 875 notifyQuickScrubStarted()876 public void notifyQuickScrubStarted() { 877 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 878 mConnectionCallbacks.get(i).onQuickScrubStarted(); 879 } 880 } 881 notifyAssistantProgress(@loatRangefrom = 0.0, to = 1.0) float progress)882 private void notifyAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) { 883 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 884 mConnectionCallbacks.get(i).onAssistantProgress(progress); 885 } 886 } 887 notifyAssistantGestureCompletion(float velocity)888 private void notifyAssistantGestureCompletion(float velocity) { 889 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 890 mConnectionCallbacks.get(i).onAssistantGestureCompletion(velocity); 891 } 892 } 893 notifyStartAssistant(Bundle bundle)894 private void notifyStartAssistant(Bundle bundle) { 895 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 896 mConnectionCallbacks.get(i).startAssistant(bundle); 897 } 898 } 899 notifySwipeUpGestureStartedInternal()900 private void notifySwipeUpGestureStartedInternal() { 901 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 902 mConnectionCallbacks.get(i).onSwipeUpGestureStarted(); 903 } 904 } 905 notifyAssistantVisibilityChanged(float visibility)906 public void notifyAssistantVisibilityChanged(float visibility) { 907 try { 908 if (mOverviewProxy != null) { 909 mOverviewProxy.onAssistantVisibilityChanged(visibility); 910 } else { 911 Log.e(TAG_OPS, "Failed to get overview proxy for assistant visibility."); 912 } 913 } catch (RemoteException e) { 914 Log.e(TAG_OPS, "Failed to call notifyAssistantVisibilityChanged()", e); 915 } 916 } 917 918 /** 919 * Notifies the Launcher of split screen size changes 920 * 921 * @param secondaryWindowBounds Bounds of the secondary window including the insets 922 * @param secondaryWindowInsets stable insets received by the secondary window 923 */ notifySplitScreenBoundsChanged( Rect secondaryWindowBounds, Rect secondaryWindowInsets)924 public void notifySplitScreenBoundsChanged( 925 Rect secondaryWindowBounds, Rect secondaryWindowInsets) { 926 try { 927 if (mOverviewProxy != null) { 928 mOverviewProxy.onSplitScreenSecondaryBoundsChanged( 929 secondaryWindowBounds, secondaryWindowInsets); 930 } else { 931 Log.e(TAG_OPS, "Failed to get overview proxy for split screen bounds."); 932 } 933 } catch (RemoteException e) { 934 Log.e(TAG_OPS, "Failed to call onSplitScreenSecondaryBoundsChanged()", e); 935 } 936 } 937 938 /** 939 * Notifies the Launcher that screen turned on and ready to use 940 */ notifyScreenTurnedOn()941 public void notifyScreenTurnedOn() { 942 try { 943 if (mOverviewProxy != null) { 944 mOverviewProxy.onScreenTurnedOn(); 945 } else { 946 Log.e(TAG_OPS, "Failed to get overview proxy for screen turned on event."); 947 } 948 } catch (RemoteException e) { 949 Log.e(TAG_OPS, "Failed to call notifyScreenTurnedOn()", e); 950 } 951 } 952 notifyToggleRecentApps()953 void notifyToggleRecentApps() { 954 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 955 mConnectionCallbacks.get(i).onToggleRecentApps(); 956 } 957 } 958 disable(int displayId, int state1, int state2, boolean animate)959 public void disable(int displayId, int state1, int state2, boolean animate) { 960 try { 961 if (mOverviewProxy != null) { 962 mOverviewProxy.disable(displayId, state1, state2, animate); 963 } else { 964 Log.e(TAG_OPS, "Failed to get overview proxy for disable flags."); 965 } 966 } catch (RemoteException e) { 967 Log.e(TAG_OPS, "Failed to call disable()", e); 968 } 969 } 970 onRotationProposal(int rotation, boolean isValid)971 public void onRotationProposal(int rotation, boolean isValid) { 972 try { 973 if (mOverviewProxy != null) { 974 mOverviewProxy.onRotationProposal(rotation, isValid); 975 } else { 976 Log.e(TAG_OPS, "Failed to get overview proxy for proposing rotation."); 977 } 978 } catch (RemoteException e) { 979 Log.e(TAG_OPS, "Failed to call onRotationProposal()", e); 980 } 981 } 982 onSystemBarAttributesChanged(int displayId, int behavior)983 public void onSystemBarAttributesChanged(int displayId, int behavior) { 984 try { 985 if (mOverviewProxy != null) { 986 mOverviewProxy.onSystemBarAttributesChanged(displayId, behavior); 987 } else { 988 Log.e(TAG_OPS, "Failed to get overview proxy for system bar attr change."); 989 } 990 } catch (RemoteException e) { 991 Log.e(TAG_OPS, "Failed to call onSystemBarAttributesChanged()", e); 992 } 993 } 994 onNavButtonsDarkIntensityChanged(float darkIntensity)995 public void onNavButtonsDarkIntensityChanged(float darkIntensity) { 996 try { 997 if (mOverviewProxy != null) { 998 mOverviewProxy.onNavButtonsDarkIntensityChanged(darkIntensity); 999 } else { 1000 Log.e(TAG_OPS, "Failed to get overview proxy to update nav buttons dark intensity"); 1001 } 1002 } catch (RemoteException e) { 1003 Log.e(TAG_OPS, "Failed to call onNavButtonsDarkIntensityChanged()", e); 1004 } 1005 } 1006 updateEnabledState()1007 private void updateEnabledState() { 1008 final int currentUser = ActivityManagerWrapper.getInstance().getCurrentUserId(); 1009 mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent, 1010 MATCH_SYSTEM_ONLY, currentUser) != null; 1011 } 1012 1013 @Override onNavigationModeChanged(int mode)1014 public void onNavigationModeChanged(int mode) { 1015 mNavBarMode = mode; 1016 } 1017 1018 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1019 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1020 pw.println(TAG_OPS + " state:"); 1021 pw.print(" isConnected="); pw.println(mOverviewProxy != null); 1022 pw.print(" mIsEnabled="); pw.println(isEnabled()); 1023 pw.print(" mRecentsComponentName="); pw.println(mRecentsComponentName); 1024 pw.print(" mQuickStepIntent="); pw.println(mQuickStepIntent); 1025 pw.print(" mBound="); pw.println(mBound); 1026 pw.print(" mCurrentBoundedUserId="); pw.println(mCurrentBoundedUserId); 1027 pw.print(" mConnectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts); 1028 pw.print(" mInputFocusTransferStarted="); pw.println(mInputFocusTransferStarted); 1029 pw.print(" mInputFocusTransferStartY="); pw.println(mInputFocusTransferStartY); 1030 pw.print(" mInputFocusTransferStartMillis="); pw.println(mInputFocusTransferStartMillis); 1031 pw.print(" mWindowCornerRadius="); pw.println(mWindowCornerRadius); 1032 pw.print(" mSupportsRoundedCornersOnWindows="); pw.println(mSupportsRoundedCornersOnWindows); 1033 pw.print(" mNavBarButtonAlpha="); pw.println(mNavBarButtonAlpha); 1034 pw.print(" mActiveNavBarRegion="); pw.println(mActiveNavBarRegion); 1035 pw.print(" mNavBarMode="); pw.println(mNavBarMode); 1036 mSysUiState.dump(fd, pw, args); 1037 } 1038 1039 public interface OverviewProxyListener { onConnectionChanged(boolean isConnected)1040 default void onConnectionChanged(boolean isConnected) {} onQuickStepStarted()1041 default void onQuickStepStarted() {} onSwipeUpGestureStarted()1042 default void onSwipeUpGestureStarted() {} onPrioritizedRotation(@urface.Rotation int rotation)1043 default void onPrioritizedRotation(@Surface.Rotation int rotation) {} onOverviewShown(boolean fromHome)1044 default void onOverviewShown(boolean fromHome) {} onQuickScrubStarted()1045 default void onQuickScrubStarted() {} 1046 /** Notify the recents app (overview) is started by 3-button navigation. */ onToggleRecentApps()1047 default void onToggleRecentApps() {} 1048 /** Notify changes in the nav bar button alpha */ onNavBarButtonAlphaChanged(float alpha, boolean animate)1049 default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {} onHomeRotationEnabled(boolean enabled)1050 default void onHomeRotationEnabled(boolean enabled) {} onTaskbarStatusUpdated(boolean visible, boolean stashed)1051 default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {} onTaskbarAutohideSuspend(boolean suspend)1052 default void onTaskbarAutohideSuspend(boolean suspend) {} onSystemUiStateChanged(int sysuiStateFlags)1053 default void onSystemUiStateChanged(int sysuiStateFlags) {} onAssistantProgress(@loatRangefrom = 0.0, to = 1.0) float progress)1054 default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {} onAssistantGestureCompletion(float velocity)1055 default void onAssistantGestureCompletion(float velocity) {} startAssistant(Bundle bundle)1056 default void startAssistant(Bundle bundle) {} 1057 } 1058 } 1059