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