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.app.Flags.keyguardPrivateNotifications; 20 import static android.content.Intent.ACTION_PACKAGE_ADDED; 21 import static android.content.Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST; 22 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; 23 import static android.view.MotionEvent.ACTION_CANCEL; 24 import static android.view.MotionEvent.ACTION_DOWN; 25 import static android.view.MotionEvent.ACTION_UP; 26 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; 27 import static android.window.BackEvent.EDGE_NONE; 28 29 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_AWAKE; 30 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; 31 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING; 32 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING; 33 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING; 34 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE; 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_VOICE_INTERACTION_WINDOW_SHOWING; 39 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_TRANSITION; 40 import static com.android.systemui.shared.system.QuickStepContract.addInterface; 41 import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi; 42 import static com.android.window.flags.Flags.predictiveBackThreeButtonNav; 43 44 import android.annotation.FloatRange; 45 import android.annotation.Nullable; 46 import android.app.ActivityTaskManager; 47 import android.content.BroadcastReceiver; 48 import android.content.ComponentName; 49 import android.content.Context; 50 import android.content.Intent; 51 import android.content.IntentFilter; 52 import android.content.ServiceConnection; 53 import android.content.pm.ResolveInfo; 54 import android.graphics.Region; 55 import android.hardware.input.InputManager; 56 import android.hardware.input.InputManagerGlobal; 57 import android.os.Binder; 58 import android.os.Bundle; 59 import android.os.Handler; 60 import android.os.IBinder; 61 import android.os.IRemoteCallback; 62 import android.os.Looper; 63 import android.os.PatternMatcher; 64 import android.os.RemoteException; 65 import android.os.SystemClock; 66 import android.os.UserHandle; 67 import android.os.UserManager; 68 import android.util.Log; 69 import android.view.Display; 70 import android.view.InputDevice; 71 import android.view.KeyCharacterMap; 72 import android.view.KeyEvent; 73 import android.view.MotionEvent; 74 import android.view.Surface; 75 import android.view.accessibility.AccessibilityManager; 76 import android.view.inputmethod.Flags; 77 import android.view.inputmethod.InputMethodManager; 78 79 import androidx.annotation.NonNull; 80 81 import com.android.app.displaylib.PerDisplayRepository; 82 import com.android.internal.annotations.VisibleForTesting; 83 import com.android.internal.app.AssistUtils; 84 import com.android.internal.app.IVoiceInteractionSessionListener; 85 import com.android.internal.logging.UiEventLogger; 86 import com.android.internal.util.ScreenshotHelper; 87 import com.android.internal.util.ScreenshotRequest; 88 import com.android.systemui.Dumpable; 89 import com.android.systemui.broadcast.BroadcastDispatcher; 90 import com.android.systemui.contextualeducation.GestureType; 91 import com.android.systemui.dagger.SysUISingleton; 92 import com.android.systemui.dagger.qualifiers.Main; 93 import com.android.systemui.display.data.repository.DisplayRepository; 94 import com.android.systemui.dump.DumpManager; 95 import com.android.systemui.keyguard.KeyguardUnlockAnimationController; 96 import com.android.systemui.keyguard.KeyguardWmStateRefactor; 97 import com.android.systemui.keyguard.WakefulnessLifecycle; 98 import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager; 99 import com.android.systemui.model.SysUiState; 100 import com.android.systemui.model.SysUiState.SysUiStateCallback; 101 import com.android.systemui.navigationbar.NavigationBarController; 102 import com.android.systemui.navigationbar.NavigationModeController; 103 import com.android.systemui.navigationbar.views.NavigationBar; 104 import com.android.systemui.navigationbar.views.NavigationBarView; 105 import com.android.systemui.navigationbar.views.buttons.KeyButtonView; 106 import com.android.systemui.process.ProcessWrapper; 107 import com.android.systemui.recents.LauncherProxyService.LauncherProxyListener; 108 import com.android.systemui.scene.domain.interactor.SceneInteractor; 109 import com.android.systemui.scene.shared.flag.SceneContainerFlag; 110 import com.android.systemui.settings.DisplayTracker; 111 import com.android.systemui.settings.UserTracker; 112 import com.android.systemui.shade.ShadeViewController; 113 import com.android.systemui.shade.domain.interactor.ShadeInteractor; 114 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround; 115 import com.android.systemui.shared.recents.ILauncherProxy; 116 import com.android.systemui.shared.recents.ISystemUiProxy; 117 import com.android.systemui.shared.system.QuickStepContract; 118 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; 119 import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController; 120 import com.android.systemui.statusbar.CommandQueue; 121 import com.android.systemui.statusbar.NotificationShadeWindowController; 122 import com.android.systemui.statusbar.phone.StatusBarWindowCallback; 123 import com.android.systemui.statusbar.policy.CallbackController; 124 import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder; 125 import com.android.wm.shell.back.BackAnimation; 126 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; 127 import com.android.wm.shell.sysui.ShellInterface; 128 129 import java.io.PrintWriter; 130 import java.util.ArrayList; 131 import java.util.List; 132 import java.util.Objects; 133 import java.util.Optional; 134 import java.util.concurrent.Executor; 135 import java.util.function.Supplier; 136 137 import javax.inject.Inject; 138 import javax.inject.Provider; 139 140 import dagger.Lazy; 141 142 /** 143 * Class to send information from SysUI to Launcher with a binder. 144 */ 145 @SysUISingleton 146 public class LauncherProxyService implements CallbackController<LauncherProxyListener>, 147 NavigationModeController.ModeChangedListener, Dumpable { 148 149 @VisibleForTesting 150 static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE"; 151 152 public static final String TAG_OPS = "LauncherProxyService"; 153 private static final long BACKOFF_MILLIS = 1000; 154 private static final long DEFERRED_CALLBACK_MILLIS = 5000; 155 // Max backoff caps at 5 mins 156 private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000; 157 158 private final Context mContext; 159 private final Executor mMainExecutor; 160 private final ShellInterface mShellInterface; 161 private final Lazy<ShadeViewController> mShadeViewControllerLazy; 162 private final PerDisplayRepository<SysUiState> mPerDisplaySysUiStateRepository; 163 private final DisplayRepository mDisplayRepository; 164 private SysUiState mDefaultDisplaySysUIState; 165 private final Handler mHandler; 166 private final Lazy<NavigationBarController> mNavBarControllerLazy; 167 private final ScreenPinningRequest mScreenPinningRequest; 168 private final NotificationShadeWindowController mStatusBarWinController; 169 private final Provider<SceneInteractor> mSceneInteractor; 170 private final Provider<ShadeInteractor> mShadeInteractor; 171 172 private final Runnable mConnectionRunnable = () -> 173 internalConnectToCurrentUser("runnable: startConnectionToCurrentUser"); 174 private final ComponentName mRecentsComponentName; 175 private final List<LauncherProxyListener> mConnectionCallbacks = new ArrayList<>(); 176 private final Intent mQuickStepIntent; 177 private final ScreenshotHelper mScreenshotHelper; 178 private final CommandQueue mCommandQueue; 179 private final UserTracker mUserTracker; 180 private final ISysuiUnlockAnimationController mSysuiUnlockAnimationController; 181 private final Optional<UnfoldTransitionProgressForwarder> mUnfoldTransitionProgressForwarder; 182 private final UiEventLogger mUiEventLogger; 183 private final DisplayTracker mDisplayTracker; 184 private Region mActiveNavBarRegion; 185 186 private final BroadcastDispatcher mBroadcastDispatcher; 187 private final BackAnimation mBackAnimation; 188 189 private ILauncherProxy mLauncherProxy; 190 private int mConnectionBackoffAttempts; 191 private boolean mBound; 192 private boolean mIsEnabled; 193 // This is set to false when the launcher service is requested to be bound until it is notified 194 // that the previous service has been cleaned up in ILauncherProxy#onUnbind(). It is also set to 195 // true after a 1000ms timeout by mDeferredBindAfterTimedOutCleanup. 196 private boolean mIsPrevServiceCleanedUp = true; 197 198 private boolean mIsSystemOrVisibleBgUser; 199 private int mCurrentBoundedUserId = -1; 200 private boolean mInputFocusTransferStarted; 201 private float mInputFocusTransferStartY; 202 private long mInputFocusTransferStartMillis; 203 private int mNavBarMode = NAV_BAR_MODE_3BUTTON; 204 205 @VisibleForTesting 206 public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() { 207 @Override 208 public void startScreenPinning(int taskId) { 209 verifyCallerAndClearCallingIdentityPostMain("startScreenPinning", () -> 210 mScreenPinningRequest.showPrompt(taskId, false /* allowCancel */)); 211 } 212 213 @Override 214 public void stopScreenPinning() { 215 verifyCallerAndClearCallingIdentityPostMain("stopScreenPinning", () -> { 216 try { 217 ActivityTaskManager.getService().stopSystemLockTaskMode(); 218 } catch (RemoteException e) { 219 Log.e(TAG_OPS, "Failed to stop screen pinning"); 220 } 221 }); 222 } 223 224 // TODO: change the method signature to use (boolean inputFocusTransferStarted) 225 @Override 226 public void onStatusBarTouchEvent(MotionEvent event) { 227 verifyCallerAndClearCallingIdentity("onStatusBarTouchEvent", () -> { 228 if (SceneContainerFlag.isEnabled()) { 229 //TODO(b/329863123) implement latency tracking for shade scene 230 Log.i(TAG_OPS, "Scene container enabled. Latency tracking not started."); 231 } else if (event.getActionMasked() == ACTION_DOWN) { 232 mShadeViewControllerLazy.get().startExpandLatencyTracking(); 233 } 234 mHandler.post(() -> { 235 int action = event.getActionMasked(); 236 if (action == ACTION_DOWN) { 237 mInputFocusTransferStarted = true; 238 mInputFocusTransferStartY = event.getY(); 239 mInputFocusTransferStartMillis = event.getEventTime(); 240 241 // If scene framework is enabled, set the scene container window to 242 // visible and let the touch "slip" into that window. 243 if (SceneContainerFlag.isEnabled()) { 244 mSceneInteractor.get().onRemoteUserInputStarted("launcher swipe"); 245 } else { 246 mShadeViewControllerLazy.get().startInputFocusTransfer(); 247 } 248 } 249 if (action == ACTION_UP || action == ACTION_CANCEL) { 250 mInputFocusTransferStarted = false; 251 252 if (!SceneContainerFlag.isEnabled()) { 253 float velocity = (event.getY() - mInputFocusTransferStartY) 254 / (event.getEventTime() - mInputFocusTransferStartMillis); 255 if (action == ACTION_CANCEL) { 256 mShadeViewControllerLazy.get().cancelInputFocusTransfer(); 257 } else { 258 mShadeViewControllerLazy.get().finishInputFocusTransfer(velocity); 259 } 260 } else if (action == ACTION_UP) { 261 // Gesture was too short to be picked up by scene container touch 262 // handling; programmatically start the transition to the shade. 263 mShadeInteractor.get() 264 .expandNotificationsShade("short launcher swipe", null); 265 } 266 } 267 event.recycle(); 268 }); 269 }); 270 } 271 272 @Override 273 public void onStatusBarTrackpadEvent(MotionEvent event) { 274 verifyCallerAndClearCallingIdentityPostMain("onStatusBarTrackpadEvent", () -> { 275 if (SceneContainerFlag.isEnabled()) { 276 int action = event.getActionMasked(); 277 if (action == ACTION_DOWN) { 278 mSceneInteractor.get().onRemoteUserInputStarted( 279 "trackpad swipe"); 280 } else if (action == ACTION_UP) { 281 mShadeInteractor.get() 282 .expandNotificationsShade("short trackpad swipe", null); 283 } 284 mStatusBarWinController.getWindowRootView().dispatchTouchEvent(event); 285 } else { 286 mShadeViewControllerLazy.get().handleExternalTouch(event); 287 } 288 }); 289 } 290 291 @Override 292 public void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) { 293 verifyCallerAndClearCallingIdentityPostMain("animateNavBarLongPress", () -> 294 notifyAnimateNavBarLongPress(isTouchDown, shrink, durationMs)); 295 } 296 297 @Override 298 public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier, 299 boolean haptic) { 300 verifyCallerAndClearCallingIdentityPostMain("setOverrideHomeButtonLongPress", 301 () -> notifySetOverrideHomeButtonLongPress(duration, slopMultiplier, haptic)); 302 } 303 304 @Override 305 public void onBackEvent(@Nullable KeyEvent keyEvent) throws RemoteException { 306 if (predictiveBackThreeButtonNav() && predictiveBackSwipeEdgeNoneApi() 307 && mBackAnimation != null && keyEvent != null) { 308 mBackAnimation.setTriggerBack(!keyEvent.isCanceled()); 309 mBackAnimation.onBackMotion(/* touchX */ 0, /* touchY */ 0, keyEvent.getAction(), 310 EDGE_NONE); 311 } else { 312 verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> { 313 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); 314 sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); 315 }); 316 } 317 } 318 319 @Override 320 public void onImeSwitcherPressed() { 321 // TODO(b/204901476) We're intentionally using the default display for now since 322 // Launcher/Taskbar isn't display aware. 323 if (Flags.imeSwitcherRevamp()) { 324 mContext.getSystemService(InputMethodManager.class) 325 .onImeSwitchButtonClickFromSystem(mDisplayTracker.getDefaultDisplayId()); 326 } else { 327 mContext.getSystemService(InputMethodManager.class) 328 .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */, 329 mDisplayTracker.getDefaultDisplayId()); 330 } 331 mUiEventLogger.log(KeyButtonView.NavBarButtonEvent.NAVBAR_IME_SWITCHER_BUTTON_TAP); 332 } 333 334 @Override 335 public void onImeSwitcherLongPress() { 336 if (!Flags.imeSwitcherRevamp()) { 337 return; 338 } 339 // TODO(b/204901476) We're intentionally using the default display for now since 340 // Launcher/Taskbar isn't display aware. 341 mContext.getSystemService(InputMethodManager.class) 342 .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */, 343 mDisplayTracker.getDefaultDisplayId()); 344 mUiEventLogger.log( 345 KeyButtonView.NavBarButtonEvent.NAVBAR_IME_SWITCHER_BUTTON_LONGPRESS); 346 } 347 348 @Override 349 public void updateContextualEduStats(boolean isTrackpadGesture, String gestureType) { 350 verifyCallerAndClearCallingIdentityPostMain("updateContextualEduStats", 351 () -> mHandler.post(() -> LauncherProxyService.this.updateContextualEduStats( 352 isTrackpadGesture, GestureType.valueOf(gestureType)))); 353 } 354 355 @Override 356 public void setHomeRotationEnabled(boolean enabled) { 357 verifyCallerAndClearCallingIdentityPostMain("setHomeRotationEnabled", () -> 358 mHandler.post(() -> notifyHomeRotationEnabled(enabled))); 359 } 360 361 @Override 362 public void notifyTaskbarStatus(boolean visible, boolean stashed) { 363 verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarStatus", () -> 364 onTaskbarStatusUpdated(visible, stashed)); 365 } 366 367 @Override 368 public void notifyTaskbarAutohideSuspend(boolean suspend) { 369 verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarAutohideSuspend", () -> 370 onTaskbarAutohideSuspend(suspend)); 371 } 372 373 private boolean sendEvent(int action, int code) { 374 long when = SystemClock.uptimeMillis(); 375 final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */, 376 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */, 377 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, 378 InputDevice.SOURCE_KEYBOARD); 379 380 ev.setDisplayId(mContext.getDisplay().getDisplayId()); 381 return InputManagerGlobal.getInstance() 382 .injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 383 } 384 385 @Override 386 public void onOverviewShown(boolean fromHome) { 387 verifyCallerAndClearCallingIdentityPostMain("onOverviewShown", () -> { 388 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 389 mConnectionCallbacks.get(i).onOverviewShown(fromHome); 390 } 391 }); 392 } 393 394 @Override 395 public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) { 396 verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () -> 397 notifyAssistantProgress(progress)); 398 } 399 400 @Override 401 public void onAssistantGestureCompletion(float velocity) { 402 verifyCallerAndClearCallingIdentityPostMain("onAssistantGestureCompletion", () -> 403 notifyAssistantGestureCompletion(velocity)); 404 } 405 406 @Override 407 public void startAssistant(Bundle bundle) { 408 verifyCallerAndClearCallingIdentityPostMain("startAssistant", () -> 409 notifyStartAssistant(bundle)); 410 } 411 412 @Override 413 public void setAssistantOverridesRequested(int[] invocationTypes) { 414 verifyCallerAndClearCallingIdentityPostMain("setAssistantOverridesRequested", () -> 415 notifyAssistantOverrideRequested(invocationTypes)); 416 } 417 418 @Override 419 public void notifyAccessibilityButtonClicked(int displayId) { 420 verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonClicked", () -> 421 AccessibilityManager.getInstance(mContext).notifyAccessibilityButtonClicked( 422 displayId)); 423 } 424 425 @Override 426 public void notifyAccessibilityButtonLongClicked() { 427 verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonLongClicked", () -> 428 AccessibilityManager.getInstance(mContext) 429 .notifyAccessibilityButtonLongClicked( 430 mDisplayTracker.getDefaultDisplayId())); 431 } 432 433 @Override 434 public void notifyPrioritizedRotation(@Surface.Rotation int rotation) { 435 verifyCallerAndClearCallingIdentityPostMain("notifyPrioritizedRotation", () -> 436 notifyPrioritizedRotationInternal(rotation)); 437 } 438 439 @Override 440 public void takeScreenshot(ScreenshotRequest request) { 441 mScreenshotHelper.takeScreenshot(request, mHandler, null); 442 } 443 444 @Override 445 public void expandNotificationPanel() { 446 verifyCallerAndClearCallingIdentityPostMain("expandNotificationPanel", 447 () -> mCommandQueue.handleSystemKey(new KeyEvent(KeyEvent.ACTION_DOWN, 448 KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN))); 449 } 450 451 @Override 452 public void toggleNotificationPanel() { 453 verifyCallerAndClearCallingIdentityPostMain("toggleNotificationPanel", () -> 454 mCommandQueue.toggleNotificationsPanel()); 455 } 456 457 @Override 458 public void toggleQuickSettingsPanel() { 459 verifyCallerAndClearCallingIdentityPostMain("toggleQuickSettingsPanel", () -> 460 mCommandQueue.toggleQuickSettingsPanel()); 461 } 462 463 private boolean verifyCaller(String reason) { 464 final int callerId = Binder.getCallingUserHandle().getIdentifier(); 465 if (callerId != mCurrentBoundedUserId) { 466 Log.w(TAG_OPS, "Launcher called sysui with invalid user: " + callerId + ", reason: " 467 + reason); 468 return false; 469 } 470 return true; 471 } 472 473 private <T> T verifyCallerAndClearCallingIdentity(String reason, Supplier<T> supplier) { 474 if (!verifyCaller(reason)) { 475 return null; 476 } 477 final long token = Binder.clearCallingIdentity(); 478 try { 479 return supplier.get(); 480 } finally { 481 Binder.restoreCallingIdentity(token); 482 } 483 } 484 485 private void verifyCallerAndClearCallingIdentity(String reason, Runnable runnable) { 486 verifyCallerAndClearCallingIdentity(reason, () -> { 487 runnable.run(); 488 return null; 489 }); 490 } 491 492 private void verifyCallerAndClearCallingIdentityPostMain(String reason, Runnable runnable) { 493 verifyCallerAndClearCallingIdentity(reason, () -> mHandler.post(runnable)); 494 } 495 }; 496 497 private final Runnable mDeferredConnectionCallback = () -> { 498 Log.w(TAG_OPS, "Binder supposed established connection but actual connection to service " 499 + "timed out, trying again"); 500 retryConnectionWithBackoff(); 501 }; 502 503 private final Runnable mDeferredBindAfterTimedOutCleanup = () -> { 504 Log.w(TAG_OPS, "Timed out waiting for previous service to clean up, binding to new one"); 505 mIsPrevServiceCleanedUp = true; 506 maybeBindService(); 507 }; 508 509 private final BroadcastReceiver mUserEventReceiver = new BroadcastReceiver() { 510 @Override 511 public void onReceive(Context context, Intent intent) { 512 if (Objects.equals(intent.getAction(), Intent.ACTION_USER_UNLOCKED)) { 513 if (keyguardPrivateNotifications()) { 514 // Start the launcher connection to the launcher service 515 // Connect if user hasn't connected yet 516 if (getProxy() == null) { 517 startConnectionToCurrentUser(); 518 } 519 } 520 } 521 } 522 }; 523 524 private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() { 525 @Override 526 public void onReceive(Context context, Intent intent) { 527 // If adding, bind immediately 528 if (Objects.equals(intent.getAction(), ACTION_PACKAGE_ADDED)) { 529 updateEnabledAndBinding(); 530 return; 531 } 532 533 // ACTION_PACKAGE_CHANGED 534 String[] compsList = intent.getStringArrayExtra(EXTRA_CHANGED_COMPONENT_NAME_LIST); 535 if (compsList == null) { 536 return; 537 } 538 539 // Only rebind for TouchInteractionService component from launcher 540 ResolveInfo ri = context.getPackageManager() 541 .resolveService(new Intent(ACTION_QUICKSTEP), 0); 542 if (ri == null) { 543 return; 544 } 545 String interestingComponent = ri.serviceInfo.name; 546 for (String component : compsList) { 547 if (interestingComponent.equals(component)) { 548 Log.i(TAG_OPS, "Rebinding for component [" + component + "] change"); 549 updateEnabledAndBinding(); 550 return; 551 } 552 } 553 } 554 }; 555 556 private final ServiceConnection mLauncherServiceConnection = new ServiceConnection() { 557 @Override 558 public void onServiceConnected(ComponentName name, IBinder service) { 559 Log.d(TAG_OPS, "Launcher proxy service connected"); 560 mConnectionBackoffAttempts = 0; 561 mHandler.removeCallbacks(mDeferredConnectionCallback); 562 try { 563 service.linkToDeath(mLauncherServiceDeathRcpt, 0); 564 } catch (RemoteException e) { 565 // Failed to link to death (process may have died between binding and connecting), 566 // just unbind the service for now and retry again 567 Log.e(TAG_OPS, "Lost connection to launcher service", e); 568 disconnectFromLauncherService("Lost connection to launcher service"); 569 retryConnectionWithBackoff(); 570 return; 571 } 572 573 mCurrentBoundedUserId = mUserTracker.getUserId(); 574 mLauncherProxy = ILauncherProxy.Stub.asInterface(service); 575 576 Bundle params = new Bundle(); 577 addInterface(mSysUiProxy, params); 578 addInterface(mSysuiUnlockAnimationController, params); 579 addInterface(mUnfoldTransitionProgressForwarder.orElse(null), params); 580 // Add all the interfaces exposed by the shell 581 mShellInterface.createExternalInterfaces(params); 582 583 try { 584 Log.d(TAG_OPS, "LauncherProxyService connected, initializing launcher proxy"); 585 mLauncherProxy.onInitialize(params); 586 } catch (RemoteException e) { 587 mCurrentBoundedUserId = -1; 588 Log.e(TAG_OPS, "Failed to call onInitialize()", e); 589 } 590 dispatchNavButtonBounds(); 591 592 // Force-update the systemui state flags 593 updateSystemUiStateFlags(); 594 if (ShadeWindowGoesAround.isEnabled()) { 595 notifySysUiStateFlagsForAllDisplays(); 596 } else { 597 notifySystemUiStateFlags(mDefaultDisplaySysUIState.getFlags(), 598 Display.DEFAULT_DISPLAY); 599 } 600 notifyConnectionChanged(); 601 } 602 603 @Override 604 public void onNullBinding(ComponentName name) { 605 Log.w(TAG_OPS, "Null binding of '" + name + "', try reconnecting"); 606 mCurrentBoundedUserId = -1; 607 retryConnectionWithBackoff(); 608 } 609 610 @Override 611 public void onBindingDied(ComponentName name) { 612 Log.w(TAG_OPS, "Binding died of '" + name + "', try reconnecting"); 613 mCurrentBoundedUserId = -1; 614 retryConnectionWithBackoff(); 615 } 616 617 @Override 618 public void onServiceDisconnected(ComponentName name) { 619 Log.w(TAG_OPS, "Service disconnected"); 620 // Do nothing 621 mCurrentBoundedUserId = -1; 622 } 623 }; 624 625 /** Propagates the flags for all displays to be notified to Launcher. */ 626 @VisibleForTesting notifySysUiStateFlagsForAllDisplays()627 public void notifySysUiStateFlagsForAllDisplays() { 628 var displays = mDisplayRepository.getDisplayIds().getValue(); 629 for (int displayId : displays) { 630 var state = mPerDisplaySysUiStateRepository.get(displayId); 631 if (state != null) { 632 notifySystemUiStateFlags(state.getFlags(), displayId); 633 } 634 } 635 } 636 637 private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged; 638 639 // This is the death handler for the binder from the launcher service 640 private final IBinder.DeathRecipient mLauncherServiceDeathRcpt 641 = this::cleanupAfterDeath; 642 643 private final IVoiceInteractionSessionListener mVoiceInteractionSessionListener = 644 new IVoiceInteractionSessionListener.Stub() { 645 @Override 646 public void onVoiceSessionShown() { 647 // Do nothing 648 } 649 650 @Override 651 public void onVoiceSessionHidden() { 652 // Do nothing 653 } 654 655 @Override 656 public void onVoiceSessionWindowVisibilityChanged(boolean visible) { 657 mContext.getMainExecutor().execute(() -> 658 LauncherProxyService.this.onVoiceSessionWindowVisibilityChanged(visible)); 659 } 660 661 @Override 662 public void onSetUiHints(Bundle hints) { 663 // Do nothing 664 } 665 }; 666 667 private final UserTracker.Callback mUserChangedCallback = 668 new UserTracker.Callback() { 669 @Override 670 public void onUserChanged(int newUser, @NonNull Context userContext) { 671 mConnectionBackoffAttempts = 0; 672 internalConnectToCurrentUser("User changed"); 673 } 674 }; 675 676 private final SysUiStateCallback mSysUiStateCallback = 677 new SysUiStateCallback() { 678 @Override 679 public void onSystemUiStateChanged(long sysUiFlags, int displayId) { 680 notifySystemUiStateFlags(sysUiFlags, displayId); 681 } 682 }; 683 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") 684 @Inject LauncherProxyService(Context context, @Main Executor mainExecutor, CommandQueue commandQueue, ShellInterface shellInterface, Lazy<NavigationBarController> navBarControllerLazy, Lazy<ShadeViewController> shadeViewControllerLazy, ScreenPinningRequest screenPinningRequest, NavigationModeController navModeController, NotificationShadeWindowController statusBarWinController, PerDisplayRepository<SysUiState> perDisplaySysUiStateRepository, Provider<SceneInteractor> sceneInteractor, Provider<ShadeInteractor> shadeInteractor, UserTracker userTracker, UserManager userManager, WakefulnessLifecycle wakefulnessLifecycle, UiEventLogger uiEventLogger, DisplayTracker displayTracker, KeyguardUnlockAnimationController sysuiUnlockAnimationController, InWindowLauncherUnlockAnimationManager inWindowLauncherUnlockAnimationManager, AssistUtils assistUtils, DumpManager dumpManager, Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder, BroadcastDispatcher broadcastDispatcher, Optional<BackAnimation> backAnimation, ProcessWrapper processWrapper, DisplayRepository displayRepository )685 public LauncherProxyService(Context context, 686 @Main Executor mainExecutor, 687 CommandQueue commandQueue, 688 ShellInterface shellInterface, 689 Lazy<NavigationBarController> navBarControllerLazy, 690 Lazy<ShadeViewController> shadeViewControllerLazy, 691 ScreenPinningRequest screenPinningRequest, 692 NavigationModeController navModeController, 693 NotificationShadeWindowController statusBarWinController, 694 PerDisplayRepository<SysUiState> perDisplaySysUiStateRepository, 695 Provider<SceneInteractor> sceneInteractor, 696 Provider<ShadeInteractor> shadeInteractor, 697 UserTracker userTracker, 698 UserManager userManager, 699 WakefulnessLifecycle wakefulnessLifecycle, 700 UiEventLogger uiEventLogger, 701 DisplayTracker displayTracker, 702 KeyguardUnlockAnimationController sysuiUnlockAnimationController, 703 InWindowLauncherUnlockAnimationManager inWindowLauncherUnlockAnimationManager, 704 AssistUtils assistUtils, 705 DumpManager dumpManager, 706 Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder, 707 BroadcastDispatcher broadcastDispatcher, 708 Optional<BackAnimation> backAnimation, 709 ProcessWrapper processWrapper, 710 DisplayRepository displayRepository 711 ) { 712 // b/241601880: This component should only be running for primary users or 713 // secondaryUsers when visibleBackgroundUsers are supported. 714 boolean isSystemUser = processWrapper.isSystemUser(); 715 boolean isVisibleBackgroundUser = 716 userManager.isVisibleBackgroundUsersSupported() && !userManager.isUserForeground(); 717 if (!isSystemUser && isVisibleBackgroundUser) { 718 Log.d(TAG_OPS, "Initialization for visibleBackgroundUser"); 719 } 720 mIsSystemOrVisibleBgUser = isSystemUser || isVisibleBackgroundUser; 721 if (!mIsSystemOrVisibleBgUser) { 722 Log.wtf(TAG_OPS, "Unexpected initialization for non-system foreground user", 723 new Throwable()); 724 } 725 726 mContext = context; 727 mMainExecutor = mainExecutor; 728 mShellInterface = shellInterface; 729 mShadeViewControllerLazy = shadeViewControllerLazy; 730 mHandler = new Handler(); 731 mNavBarControllerLazy = navBarControllerLazy; 732 mScreenPinningRequest = screenPinningRequest; 733 mStatusBarWinController = statusBarWinController; 734 mSceneInteractor = sceneInteractor; 735 mShadeInteractor = shadeInteractor; 736 mUserTracker = userTracker; 737 mConnectionBackoffAttempts = 0; 738 mRecentsComponentName = ComponentName.unflattenFromString(context.getString( 739 com.android.internal.R.string.config_recentsComponentName)); 740 mQuickStepIntent = new Intent(ACTION_QUICKSTEP) 741 .setPackage(mRecentsComponentName.getPackageName()); 742 mPerDisplaySysUiStateRepository = perDisplaySysUiStateRepository; 743 mDisplayRepository = displayRepository; 744 mDefaultDisplaySysUIState = perDisplaySysUiStateRepository.get(Display.DEFAULT_DISPLAY); 745 mDefaultDisplaySysUIState.addCallback(mSysUiStateCallback); 746 mUiEventLogger = uiEventLogger; 747 mDisplayTracker = displayTracker; 748 mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder; 749 mBroadcastDispatcher = broadcastDispatcher; 750 mBackAnimation = backAnimation.orElse(null); 751 752 if (!KeyguardWmStateRefactor.isEnabled()) { 753 mSysuiUnlockAnimationController = sysuiUnlockAnimationController; 754 } else { 755 mSysuiUnlockAnimationController = inWindowLauncherUnlockAnimationManager; 756 } 757 758 dumpManager.registerDumpable(getClass().getSimpleName(), this); 759 760 // Listen for nav bar mode changes 761 mNavBarMode = navModeController.addListener(this); 762 763 // Listen for launcher package changes 764 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 765 filter.addDataScheme("package"); 766 filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(), 767 PatternMatcher.PATTERN_LITERAL); 768 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 769 mContext.registerReceiver(mLauncherStateChangedReceiver, filter); 770 771 if (keyguardPrivateNotifications()) { 772 mBroadcastDispatcher.registerReceiver(mUserEventReceiver, 773 new IntentFilter(Intent.ACTION_USER_UNLOCKED), 774 null /* executor */, UserHandle.ALL); 775 } 776 777 // Listen for status bar state changes 778 statusBarWinController.registerCallback(mStatusBarWindowCallback); 779 mScreenshotHelper = new ScreenshotHelper(context); 780 781 commandQueue.addCallback(new CommandQueue.Callbacks() { 782 783 // Listen for tracing state changes 784 @Override 785 public void onTracingStateChanged(boolean enabled) { 786 // TODO(b/286509643) Cleanup callers of this; Unused downstream 787 } 788 789 @Override 790 public void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop) { 791 if (mLauncherProxy != null) { 792 try { 793 if (DesktopModeStatus.canEnterDesktopMode(mContext) 794 && (mDefaultDisplaySysUIState.getFlags() 795 & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0) { 796 return; 797 } 798 mLauncherProxy.enterStageSplitFromRunningApp(leftOrTop); 799 } catch (RemoteException e) { 800 Log.w(TAG_OPS, "Unable to enter stage split from the current running app"); 801 } 802 } 803 } 804 }); 805 mCommandQueue = commandQueue; 806 807 // Listen for user setup 808 mUserTracker.addCallback(mUserChangedCallback, mMainExecutor); 809 810 wakefulnessLifecycle.addObserver(mWakefulnessLifecycleObserver); 811 // Connect to the service 812 updateEnabledAndBinding(); 813 814 // Listen for assistant changes 815 assistUtils.registerVoiceInteractionSessionListener(mVoiceInteractionSessionListener); 816 } 817 onVoiceSessionWindowVisibilityChanged(boolean visible)818 public void onVoiceSessionWindowVisibilityChanged(boolean visible) { 819 mDefaultDisplaySysUIState.setFlag(SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING, visible) 820 .commitUpdate(mContext.getDisplayId()); 821 } 822 updateEnabledAndBinding()823 private void updateEnabledAndBinding() { 824 updateEnabledState(); 825 startConnectionToCurrentUser(); 826 } 827 updateSysUIStateForNavbars()828 private void updateSysUIStateForNavbars() { 829 if (ShadeWindowGoesAround.isEnabled()) { 830 var displays = mDisplayRepository.getDisplayIds().getValue(); 831 for (int displayId : displays) { 832 updateSysUIStateForNavbarWithDisplayId(displayId); 833 } 834 } else { 835 updateSysUIStateForNavbarWithDisplayId(Display.DEFAULT_DISPLAY); 836 } 837 } 838 updateSysUIStateForNavbarWithDisplayId(int displayId)839 private void updateSysUIStateForNavbarWithDisplayId(int displayId) { 840 final NavigationBar navBarFragment = 841 mNavBarControllerLazy.get().getNavigationBar(displayId); 842 final NavigationBarView navBarView = 843 mNavBarControllerLazy.get().getNavigationBarView(displayId); 844 if (SysUiState.DEBUG) { 845 Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment 846 + " navBarView=" + navBarView 847 + " shadeViewController=" + mShadeViewControllerLazy.get()); 848 } 849 850 final SysUiState displaySysuiState = mPerDisplaySysUiStateRepository.get(displayId); 851 if (displaySysuiState == null) return; 852 853 if (navBarFragment != null) { 854 navBarFragment.updateSystemUiStateFlags(); 855 } 856 if (navBarView != null) { 857 navBarView.updateDisabledSystemUiStateFlags(displaySysuiState); 858 } 859 } 860 861 /** Force updates SystemUI state flags prior to sending them to Launcher. */ updateSystemUiStateFlags()862 public void updateSystemUiStateFlags() { 863 updateSysUIStateForNavbars(); 864 mShadeViewControllerLazy.get().updateSystemUiStateFlags(); 865 if (mStatusBarWinController != null) { 866 mStatusBarWinController.notifyStateChangedCallbacks(); 867 } 868 } 869 notifySystemUiStateFlags(@ystemUiStateFlags long flags, int displayId)870 private void notifySystemUiStateFlags(@SystemUiStateFlags long flags, int displayId) { 871 if (SysUiState.DEBUG) { 872 Log.d(TAG_OPS, "Notifying sysui state change to launcher service: proxy=" 873 + mLauncherProxy + " display=" + displayId + " flags=" 874 + QuickStepContract.getSystemUiStateString(flags) + " displayId=" + displayId); 875 } 876 try { 877 if (mLauncherProxy != null) { 878 mLauncherProxy.onSystemUiStateChanged(flags, displayId); 879 } 880 } catch (RemoteException e) { 881 Log.e(TAG_OPS, "Failed to notify sysui state change", e); 882 } 883 } 884 onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean keyguardGoingAway, boolean bouncerShowing, boolean isDozing, boolean panelExpanded, boolean isDreaming, boolean communalShowing)885 private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded, 886 boolean keyguardGoingAway, boolean bouncerShowing, boolean isDozing, 887 boolean panelExpanded, boolean isDreaming, boolean communalShowing) { 888 mDefaultDisplaySysUIState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING, 889 keyguardShowing && !keyguardOccluded) 890 .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED, 891 keyguardShowing && keyguardOccluded) 892 .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY, 893 keyguardGoingAway) 894 .setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing) 895 .setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing) 896 .setFlag(SYSUI_STATE_DEVICE_DREAMING, isDreaming) 897 .setFlag(SYSUI_STATE_COMMUNAL_HUB_SHOWING, communalShowing) 898 .commitUpdate(mContext.getDisplayId()); 899 } 900 901 /** 902 * Sets the navbar region which can receive touch inputs 903 */ onActiveNavBarRegionChanges(Region activeRegion)904 public void onActiveNavBarRegionChanges(Region activeRegion) { 905 mActiveNavBarRegion = activeRegion; 906 dispatchNavButtonBounds(); 907 } 908 dispatchNavButtonBounds()909 private void dispatchNavButtonBounds() { 910 if (mLauncherProxy != null && mActiveNavBarRegion != null) { 911 try { 912 mLauncherProxy.onActiveNavBarRegionChanges(mActiveNavBarRegion); 913 } catch (RemoteException e) { 914 Log.e(TAG_OPS, "Failed to call onActiveNavBarRegionChanges()", e); 915 } 916 } 917 } 918 cleanupAfterDeath()919 public void cleanupAfterDeath() { 920 if (mInputFocusTransferStarted) { 921 mHandler.post(() -> { 922 mInputFocusTransferStarted = false; 923 mShadeViewControllerLazy.get().cancelInputFocusTransfer(); 924 }); 925 } 926 mIsPrevServiceCleanedUp = true; 927 startConnectionToCurrentUser(); 928 } 929 startConnectionToCurrentUser()930 public void startConnectionToCurrentUser() { 931 Log.v(TAG_OPS, "startConnectionToCurrentUser: connection is restarted"); 932 if (mHandler.getLooper() != Looper.myLooper()) { 933 mHandler.post(mConnectionRunnable); 934 } else { 935 internalConnectToCurrentUser("startConnectionToCurrentUser"); 936 } 937 } 938 internalConnectToCurrentUser(String reason)939 private void internalConnectToCurrentUser(String reason) { 940 if (!mIsSystemOrVisibleBgUser) { 941 // This should not happen, but if any per-user SysUI component has a dependency on OPS, 942 // then this could get triggered 943 Log.w(TAG_OPS, 944 "Skipping connection to launcher service due to non-system foreground user " 945 + "caller"); 946 return; 947 } 948 disconnectFromLauncherService(reason); 949 950 // If user has not setup yet or already connected, do not try to connect 951 if (!isEnabled()) { 952 Log.v(TAG_OPS, "Cannot attempt connection, is enabled " + isEnabled()); 953 return; 954 } 955 mHandler.removeCallbacks(mConnectionRunnable); 956 957 maybeBindService(); 958 } 959 maybeBindService()960 private void maybeBindService() { 961 if (!mIsPrevServiceCleanedUp) { 962 Log.w(TAG_OPS, "Skipping connection to TouchInteractionService until previous" 963 + " instance is cleaned up."); 964 if (!mHandler.hasCallbacks(mDeferredConnectionCallback)) { 965 mHandler.postDelayed(mDeferredBindAfterTimedOutCleanup, BACKOFF_MILLIS); 966 } 967 return; 968 } 969 970 // Avoid creating TouchInteractionService because the System user in HSUM mode does not 971 // interact with UI elements 972 UserHandle currentUser = UserHandle.of(mUserTracker.getUserId()); 973 if (UserManager.isHeadlessSystemUserMode() && currentUser.isSystem()) { 974 Log.w(TAG_OPS, 975 "Skipping connection to TouchInteractionService for the System user in HSUM " 976 + "mode."); 977 return; 978 } 979 try { 980 mBound = mContext.bindServiceAsUser(mQuickStepIntent, 981 mLauncherServiceConnection, 982 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, 983 currentUser); 984 } catch (SecurityException e) { 985 Log.e(TAG_OPS, "Unable to bind because of security error", e); 986 } 987 if (mBound) { 988 mIsPrevServiceCleanedUp = false; 989 // Ensure that connection has been established even if it thinks it is bound 990 mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS); 991 } else { 992 // Retry after exponential backoff timeout 993 retryConnectionWithBackoff(); 994 } 995 } 996 retryConnectionWithBackoff()997 private void retryConnectionWithBackoff() { 998 if (mHandler.hasCallbacks(mConnectionRunnable)) { 999 return; 1000 } 1001 final long timeoutMs = (long) Math.min( 1002 Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts), MAX_BACKOFF_MILLIS); 1003 mHandler.postDelayed(mConnectionRunnable, timeoutMs); 1004 mConnectionBackoffAttempts++; 1005 Log.w(TAG_OPS, "Failed to connect on attempt " + mConnectionBackoffAttempts 1006 + " will try again in " + timeoutMs + "ms"); 1007 } 1008 1009 @Override addCallback(@onNull LauncherProxyListener listener)1010 public void addCallback(@NonNull LauncherProxyListener listener) { 1011 if (!mConnectionCallbacks.contains(listener)) { 1012 mConnectionCallbacks.add(listener); 1013 } 1014 listener.onConnectionChanged(mLauncherProxy != null); 1015 } 1016 1017 @Override removeCallback(@onNull LauncherProxyListener listener)1018 public void removeCallback(@NonNull LauncherProxyListener listener) { 1019 mConnectionCallbacks.remove(listener); 1020 } 1021 shouldShowSwipeUpUI()1022 public boolean shouldShowSwipeUpUI() { 1023 return isEnabled() && !QuickStepContract.isLegacyMode(mNavBarMode); 1024 } 1025 isEnabled()1026 public boolean isEnabled() { 1027 return mIsEnabled; 1028 } 1029 getProxy()1030 public ILauncherProxy getProxy() { 1031 return mLauncherProxy; 1032 } 1033 disconnectFromLauncherService(String disconnectReason)1034 private void disconnectFromLauncherService(String disconnectReason) { 1035 Log.d(TAG_OPS, "disconnectFromLauncherService bound?: " + mBound + 1036 " currentProxy: " + mLauncherProxy + " disconnectReason: " + disconnectReason, 1037 new Throwable()); 1038 if (mBound) { 1039 // Always unbind the service (ie. if called through onNullBinding or onBindingDied) 1040 mContext.unbindService(mLauncherServiceConnection); 1041 mBound = false; 1042 if (mLauncherProxy != null) { 1043 try { 1044 mLauncherProxy.onUnbind(new IRemoteCallback.Stub() { 1045 @Override 1046 public void sendResult(Bundle data) throws RemoteException { 1047 // Received Launcher reply, try to bind anew. 1048 mIsPrevServiceCleanedUp = true; 1049 if (mHandler.hasCallbacks(mDeferredBindAfterTimedOutCleanup)) { 1050 mHandler.removeCallbacks(mDeferredBindAfterTimedOutCleanup); 1051 maybeBindService(); 1052 } 1053 } 1054 }); 1055 } catch (RemoteException e) { 1056 Log.w(TAG_OPS, "disconnectFromLauncherService failed to notify Launcher"); 1057 mIsPrevServiceCleanedUp = true; 1058 } 1059 } 1060 } 1061 1062 if (mLauncherProxy != null) { 1063 mLauncherProxy.asBinder().unlinkToDeath(mLauncherServiceDeathRcpt, 0); 1064 mLauncherProxy = null; 1065 notifyConnectionChanged(); 1066 } 1067 } 1068 1069 /** 1070 * Updates contextual education stats when a gesture is triggered 1071 * @param isTrackpadGesture indicates if the gesture is triggered by trackpad 1072 * @param gestureType type of gesture triggered 1073 */ updateContextualEduStats(boolean isTrackpadGesture, GestureType gestureType)1074 public void updateContextualEduStats(boolean isTrackpadGesture, GestureType gestureType) { 1075 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1076 mConnectionCallbacks.get(i).updateContextualEduStats(isTrackpadGesture, gestureType); 1077 } 1078 } 1079 notifyHomeRotationEnabled(boolean enabled)1080 private void notifyHomeRotationEnabled(boolean enabled) { 1081 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1082 mConnectionCallbacks.get(i).onHomeRotationEnabled(enabled); 1083 } 1084 } 1085 onTaskbarStatusUpdated(boolean visible, boolean stashed)1086 private void onTaskbarStatusUpdated(boolean visible, boolean stashed) { 1087 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1088 mConnectionCallbacks.get(i).onTaskbarStatusUpdated(visible, stashed); 1089 } 1090 } 1091 onTaskbarAutohideSuspend(boolean suspend)1092 private void onTaskbarAutohideSuspend(boolean suspend) { 1093 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1094 mConnectionCallbacks.get(i).onTaskbarAutohideSuspend(suspend); 1095 } 1096 } 1097 notifyConnectionChanged()1098 private void notifyConnectionChanged() { 1099 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1100 mConnectionCallbacks.get(i).onConnectionChanged(mLauncherProxy != null); 1101 } 1102 } 1103 notifyPrioritizedRotationInternal(@urface.Rotation int rotation)1104 private void notifyPrioritizedRotationInternal(@Surface.Rotation int rotation) { 1105 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1106 mConnectionCallbacks.get(i).onPrioritizedRotation(rotation); 1107 } 1108 } 1109 notifyAssistantProgress(@loatRangefrom = 0.0, to = 1.0) float progress)1110 private void notifyAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) { 1111 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1112 mConnectionCallbacks.get(i).onAssistantProgress(progress); 1113 } 1114 } 1115 notifyAssistantGestureCompletion(float velocity)1116 private void notifyAssistantGestureCompletion(float velocity) { 1117 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1118 mConnectionCallbacks.get(i).onAssistantGestureCompletion(velocity); 1119 } 1120 } 1121 notifyStartAssistant(Bundle bundle)1122 private void notifyStartAssistant(Bundle bundle) { 1123 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1124 mConnectionCallbacks.get(i).startAssistant(bundle); 1125 } 1126 } 1127 notifyAssistantOverrideRequested(int[] invocationTypes)1128 private void notifyAssistantOverrideRequested(int[] invocationTypes) { 1129 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1130 mConnectionCallbacks.get(i).setAssistantOverridesRequested(invocationTypes); 1131 } 1132 } 1133 notifyAnimateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs)1134 private void notifyAnimateNavBarLongPress(boolean isTouchDown, boolean shrink, 1135 long durationMs) { 1136 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1137 mConnectionCallbacks.get(i).animateNavBarLongPress(isTouchDown, shrink, durationMs); 1138 } 1139 } 1140 notifySetOverrideHomeButtonLongPress(long duration, float slopMultiplier, boolean haptic)1141 private void notifySetOverrideHomeButtonLongPress(long duration, float slopMultiplier, 1142 boolean haptic) { 1143 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1144 mConnectionCallbacks.get(i) 1145 .setOverrideHomeButtonLongPress(duration, slopMultiplier, haptic); 1146 } 1147 } 1148 notifyAssistantVisibilityChanged(float visibility)1149 public void notifyAssistantVisibilityChanged(float visibility) { 1150 try { 1151 if (mLauncherProxy != null) { 1152 mLauncherProxy.onAssistantVisibilityChanged(visibility); 1153 } else { 1154 Log.e(TAG_OPS, "Failed to get launcher proxy for assistant visibility."); 1155 } 1156 } catch (RemoteException e) { 1157 Log.e(TAG_OPS, "Failed to call notifyAssistantVisibilityChanged()", e); 1158 } 1159 } 1160 1161 private final WakefulnessLifecycle.Observer mWakefulnessLifecycleObserver = 1162 new WakefulnessLifecycle.Observer() { 1163 @Override 1164 public void onStartedWakingUp() { 1165 mDefaultDisplaySysUIState 1166 .setFlag(SYSUI_STATE_AWAKE, true) 1167 .setFlag(SYSUI_STATE_WAKEFULNESS_TRANSITION, true) 1168 .commitUpdate(mContext.getDisplayId()); 1169 } 1170 1171 @Override 1172 public void onFinishedWakingUp() { 1173 mDefaultDisplaySysUIState 1174 .setFlag(SYSUI_STATE_AWAKE, true) 1175 .setFlag(SYSUI_STATE_WAKEFULNESS_TRANSITION, false) 1176 .commitUpdate(mContext.getDisplayId()); 1177 } 1178 1179 @Override 1180 public void onStartedGoingToSleep() { 1181 mDefaultDisplaySysUIState 1182 .setFlag(SYSUI_STATE_AWAKE, false) 1183 .setFlag(SYSUI_STATE_WAKEFULNESS_TRANSITION, true) 1184 .commitUpdate(mContext.getDisplayId()); 1185 } 1186 1187 @Override 1188 public void onFinishedGoingToSleep() { 1189 mDefaultDisplaySysUIState 1190 .setFlag(SYSUI_STATE_AWAKE, false) 1191 .setFlag(SYSUI_STATE_WAKEFULNESS_TRANSITION, false) 1192 .commitUpdate(mContext.getDisplayId()); 1193 } 1194 }; 1195 notifyToggleRecentApps()1196 void notifyToggleRecentApps() { 1197 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { 1198 mConnectionCallbacks.get(i).onToggleRecentApps(); 1199 } 1200 } 1201 disable(int displayId, int state1, int state2, boolean animate)1202 public void disable(int displayId, int state1, int state2, boolean animate) { 1203 try { 1204 if (mLauncherProxy != null) { 1205 mLauncherProxy.disable(displayId, state1, state2, animate); 1206 } else { 1207 Log.e(TAG_OPS, "Failed to get launcher proxy for disable flags."); 1208 } 1209 } catch (RemoteException e) { 1210 Log.e(TAG_OPS, "Failed to call disable()", e); 1211 } 1212 } 1213 onRotationProposal(int rotation, boolean isValid)1214 public void onRotationProposal(int rotation, boolean isValid) { 1215 try { 1216 if (mLauncherProxy != null) { 1217 mLauncherProxy.onRotationProposal(rotation, isValid); 1218 } else { 1219 Log.e(TAG_OPS, "Failed to get launcher proxy for proposing rotation."); 1220 } 1221 } catch (RemoteException e) { 1222 Log.e(TAG_OPS, "Failed to call onRotationProposal()", e); 1223 } 1224 } 1225 onSystemBarAttributesChanged(int displayId, int behavior)1226 public void onSystemBarAttributesChanged(int displayId, int behavior) { 1227 try { 1228 if (mLauncherProxy != null) { 1229 mLauncherProxy.onSystemBarAttributesChanged(displayId, behavior); 1230 } else { 1231 Log.e(TAG_OPS, "Failed to get launcher proxy for system bar attr change."); 1232 } 1233 } catch (RemoteException e) { 1234 Log.e(TAG_OPS, "Failed to call onSystemBarAttributesChanged()", e); 1235 } 1236 } 1237 onNavButtonsDarkIntensityChanged(float darkIntensity)1238 public void onNavButtonsDarkIntensityChanged(float darkIntensity) { 1239 try { 1240 if (mLauncherProxy != null) { 1241 mLauncherProxy.onNavButtonsDarkIntensityChanged(darkIntensity); 1242 } else { 1243 Log.e(TAG_OPS, "Failed to get launcher proxy to update nav buttons dark intensity"); 1244 } 1245 } catch (RemoteException e) { 1246 Log.e(TAG_OPS, "Failed to call onNavButtonsDarkIntensityChanged()", e); 1247 } 1248 } 1249 onNavigationBarLumaSamplingEnabled(int displayId, boolean enable)1250 public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { 1251 try { 1252 if (mLauncherProxy != null) { 1253 mLauncherProxy.onNavigationBarLumaSamplingEnabled(displayId, enable); 1254 } else { 1255 Log.e(TAG_OPS, "Failed to get launcher proxy to enable/disable nav bar luma" 1256 + "sampling"); 1257 } 1258 } catch (RemoteException e) { 1259 Log.e(TAG_OPS, "Failed to call onNavigationBarLumaSamplingEnabled()", e); 1260 } 1261 } 1262 updateEnabledState()1263 private void updateEnabledState() { 1264 final int currentUser = mUserTracker.getUserId(); 1265 mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent, 1266 MATCH_SYSTEM_ONLY, currentUser) != null; 1267 } 1268 1269 @Override onNavigationModeChanged(int mode)1270 public void onNavigationModeChanged(int mode) { 1271 mNavBarMode = mode; 1272 } 1273 1274 @Override dump(PrintWriter pw, String[] args)1275 public void dump(PrintWriter pw, String[] args) { 1276 pw.println(TAG_OPS + " state:"); 1277 pw.print(" isConnected="); pw.println(mLauncherProxy != null); 1278 pw.print(" mIsEnabled="); pw.println(isEnabled()); 1279 pw.print(" mRecentsComponentName="); pw.println(mRecentsComponentName); 1280 pw.print(" mQuickStepIntent="); pw.println(mQuickStepIntent); 1281 pw.print(" mBound="); pw.println(mBound); 1282 pw.print(" mCurrentBoundedUserId="); pw.println(mCurrentBoundedUserId); 1283 pw.print(" mConnectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts); 1284 pw.print(" mInputFocusTransferStarted="); pw.println(mInputFocusTransferStarted); 1285 pw.print(" mInputFocusTransferStartY="); pw.println(mInputFocusTransferStartY); 1286 pw.print(" mInputFocusTransferStartMillis="); pw.println(mInputFocusTransferStartMillis); 1287 pw.print(" mActiveNavBarRegion="); pw.println(mActiveNavBarRegion); 1288 pw.print(" mNavBarMode="); pw.println(mNavBarMode); 1289 pw.print(" mIsPrevServiceCleanedUp="); pw.println(mIsPrevServiceCleanedUp); 1290 mDefaultDisplaySysUIState.dump(pw, args); 1291 } 1292 1293 public interface LauncherProxyListener { onConnectionChanged(boolean isConnected)1294 default void onConnectionChanged(boolean isConnected) {} onPrioritizedRotation(@urface.Rotation int rotation)1295 default void onPrioritizedRotation(@Surface.Rotation int rotation) {} onOverviewShown(boolean fromHome)1296 default void onOverviewShown(boolean fromHome) {} 1297 /** Notify the recents app (overview) is started by 3-button navigation. */ onToggleRecentApps()1298 default void onToggleRecentApps() {} onHomeRotationEnabled(boolean enabled)1299 default void onHomeRotationEnabled(boolean enabled) {} onTaskbarStatusUpdated(boolean visible, boolean stashed)1300 default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {} onTaskbarAutohideSuspend(boolean suspend)1301 default void onTaskbarAutohideSuspend(boolean suspend) {} onAssistantProgress(@loatRangefrom = 0.0, to = 1.0) float progress)1302 default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {} onAssistantGestureCompletion(float velocity)1303 default void onAssistantGestureCompletion(float velocity) {} startAssistant(Bundle bundle)1304 default void startAssistant(Bundle bundle) {} setAssistantOverridesRequested(int[] invocationTypes)1305 default void setAssistantOverridesRequested(int[] invocationTypes) {} animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs)1306 default void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) {} 1307 /** Set override of home button long press duration, touch slop multiplier, and haptic. */ setOverrideHomeButtonLongPress( long override, float slopMultiplier, boolean haptic)1308 default void setOverrideHomeButtonLongPress( 1309 long override, float slopMultiplier, boolean haptic) {} 1310 /** Updates contextual education stats when target gesture type is triggered. */ updateContextualEduStats( boolean isTrackpadGesture, GestureType gestureType)1311 default void updateContextualEduStats( 1312 boolean isTrackpadGesture, GestureType gestureType) {} 1313 } 1314 1315 /** 1316 * Shuts down this service at the end of a testcase. 1317 * <p> 1318 * The in-production service is never shuts down, and it was not designed with testing in mind. 1319 * This unregisters the mechanisms by which the service will be revived after a testcase. 1320 * <p> 1321 * NOTE: This is a stop-gap introduced when first added some tests to this class. It should 1322 * probably be replaced by proper lifecycle management on this class. 1323 */ 1324 @VisibleForTesting() shutdownForTest()1325 void shutdownForTest() { 1326 mContext.unregisterReceiver(mLauncherStateChangedReceiver); 1327 mIsEnabled = false; 1328 mHandler.removeCallbacks(mConnectionRunnable); 1329 disconnectFromLauncherService("Shutdown for test"); 1330 } 1331 } 1332