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