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