1 /* <lambda>null2 * Copyright (C) 2019 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 package com.android.quickstep 17 18 import android.app.ActivityManager 19 import android.app.ActivityManager.RunningTaskInfo 20 import android.app.ActivityOptions 21 import android.app.PendingIntent 22 import android.content.ComponentName 23 import android.content.Context 24 import android.content.Intent 25 import android.content.pm.ShortcutInfo 26 import android.graphics.Point 27 import android.graphics.Rect 28 import android.os.Bundle 29 import android.os.Handler 30 import android.os.IBinder 31 import android.os.Message 32 import android.os.RemoteException 33 import android.os.UserHandle 34 import android.util.Log 35 import android.view.IRemoteAnimationRunner 36 import android.view.KeyEvent 37 import android.view.MotionEvent 38 import android.view.RemoteAnimationTarget 39 import android.view.SurfaceControl 40 import android.view.SurfaceControl.Transaction 41 import android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS 42 import android.window.IOnBackInvokedCallback 43 import android.window.RemoteTransition 44 import android.window.TaskSnapshot 45 import android.window.TransitionFilter 46 import android.window.TransitionInfo 47 import androidx.annotation.MainThread 48 import androidx.annotation.VisibleForTesting 49 import androidx.annotation.WorkerThread 50 import com.android.internal.logging.InstanceId 51 import com.android.internal.util.ScreenshotRequest 52 import com.android.internal.view.AppearanceRegion 53 import com.android.launcher3.Flags 54 import com.android.launcher3.dagger.ApplicationContext 55 import com.android.launcher3.dagger.LauncherAppComponent 56 import com.android.launcher3.dagger.LauncherAppSingleton 57 import com.android.launcher3.util.DaggerSingletonObject 58 import com.android.launcher3.util.Executors 59 import com.android.launcher3.util.Preconditions 60 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition 61 import com.android.quickstep.util.ActiveGestureProtoLogProxy 62 import com.android.quickstep.util.ContextualSearchInvoker 63 import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider 64 import com.android.systemui.contextualeducation.GestureType 65 import com.android.systemui.shared.recents.ISystemUiProxy 66 import com.android.systemui.shared.recents.model.ThumbnailData.Companion.wrap 67 import com.android.systemui.shared.system.QuickStepContract 68 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags 69 import com.android.systemui.shared.system.RecentsAnimationControllerCompat 70 import com.android.systemui.shared.system.RecentsAnimationListener 71 import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController 72 import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController 73 import com.android.systemui.shared.system.smartspace.SmartspaceState 74 import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig 75 import com.android.systemui.unfold.progress.IUnfoldAnimation 76 import com.android.systemui.unfold.progress.IUnfoldTransitionListener 77 import com.android.wm.shell.back.IBackAnimation 78 import com.android.wm.shell.bubbles.IBubbles 79 import com.android.wm.shell.bubbles.IBubblesListener 80 import com.android.wm.shell.common.pip.IPip 81 import com.android.wm.shell.common.pip.IPipAnimationListener 82 import com.android.wm.shell.desktopmode.IDesktopMode 83 import com.android.wm.shell.desktopmode.IDesktopTaskListener 84 import com.android.wm.shell.desktopmode.IMoveToDesktopCallback 85 import com.android.wm.shell.draganddrop.IDragAndDrop 86 import com.android.wm.shell.onehanded.IOneHanded 87 import com.android.wm.shell.recents.IRecentTasks 88 import com.android.wm.shell.recents.IRecentTasksListener 89 import com.android.wm.shell.recents.IRecentsAnimationController 90 import com.android.wm.shell.recents.IRecentsAnimationRunner 91 import com.android.wm.shell.shared.GroupedTaskInfo 92 import com.android.wm.shell.shared.IShellTransitions 93 import com.android.wm.shell.shared.bubbles.BubbleBarLocation 94 import com.android.wm.shell.shared.bubbles.BubbleBarLocation.UpdateSource 95 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus 96 import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource 97 import com.android.wm.shell.shared.desktopmode.DesktopTaskToFrontReason 98 import com.android.wm.shell.shared.split.SplitBounds 99 import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition 100 import com.android.wm.shell.splitscreen.ISplitScreen 101 import com.android.wm.shell.splitscreen.ISplitScreenListener 102 import com.android.wm.shell.splitscreen.ISplitSelectListener 103 import com.android.wm.shell.startingsurface.IStartingWindow 104 import com.android.wm.shell.startingsurface.IStartingWindowListener 105 import java.io.PrintWriter 106 import javax.inject.Inject 107 108 /** Holds the reference to SystemUI. */ 109 @LauncherAppSingleton 110 class SystemUiProxy @Inject constructor(@ApplicationContext private val context: Context) : 111 NavHandle { 112 113 private var systemUiProxy: ISystemUiProxy? = null 114 private var pip: IPip? = null 115 private var bubbles: IBubbles? = null 116 private var sysuiUnlockAnimationController: ISysuiUnlockAnimationController? = null 117 private var splitScreen: ISplitScreen? = null 118 private var oneHanded: IOneHanded? = null 119 private var shellTransitions: IShellTransitions? = null 120 private var startingWindow: IStartingWindow? = null 121 private var recentTasks: IRecentTasks? = null 122 private var backAnimation: IBackAnimation? = null 123 private var desktopMode: IDesktopMode? = null 124 private var unfoldAnimation: IUnfoldAnimation? = null 125 126 private val systemUiProxyDeathRecipient = 127 IBinder.DeathRecipient { Executors.MAIN_EXECUTOR.execute { clearProxy() } } 128 129 // Save the listeners passed into the proxy since LauncherProxyService may not have been bound 130 // yet, and we'll need to set/register these listeners with SysUI when they do. Note that it is 131 // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely 132 // in case SysUI needs to rebind. 133 private var pipAnimationListener: IPipAnimationListener? = null 134 private var bubblesListener: IBubblesListener? = null 135 private var splitScreenListener: ISplitScreenListener? = null 136 private var splitSelectListener: ISplitSelectListener? = null 137 private var startingWindowListener: IStartingWindowListener? = null 138 private var launcherUnlockAnimationController: ILauncherUnlockAnimationController? = null 139 private var launcherActivityClass: String? = null 140 private var recentTasksListener: IRecentTasksListener? = null 141 private var unfoldAnimationListener: IUnfoldTransitionListener? = null 142 private var desktopTaskListener: IDesktopTaskListener? = null 143 private val remoteTransitions = LinkedHashMap<RemoteTransition, TransitionFilter>() 144 145 private val stateChangeCallbacks: MutableList<Runnable> = ArrayList() 146 147 private var originalTransactionToken: IBinder? = null 148 private var backToLauncherCallback: IOnBackInvokedCallback? = null 149 private var backToLauncherRunner: IRemoteAnimationRunner? = null 150 private var dragAndDrop: IDragAndDrop? = null 151 val homeVisibilityState = HomeVisibilityState() 152 val focusState = FocusState() 153 154 // Used to dedupe calls to SystemUI 155 private var lastShelfHeight = 0 156 private var lastShelfVisible = false 157 158 // Used to dedupe calls to SystemUI 159 private var lastLauncherKeepClearAreaHeight = 0 160 private var lastLauncherKeepClearAreaHeightVisible = false 161 162 private val asyncHandler = 163 Handler(Executors.UI_HELPER_EXECUTOR.looper) { handleMessageAsync(it) } 164 165 // TODO(141886704): Find a way to remove this 166 @SystemUiStateFlags var lastSystemUiStateFlags: Long = 0 167 168 /** 169 * This is a singleton pending intent that is used to start recents via Shell (which is a 170 * different process). It is bare-bones, so it's expected that the component and options will be 171 * provided via fill-in intent. 172 */ 173 private val recentsPendingIntent by lazy { 174 PendingIntent.getActivity( 175 context, 176 0, 177 Intent().setPackage(context.packageName), 178 PendingIntent.FLAG_MUTABLE or 179 PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT or 180 Intent.FILL_IN_COMPONENT, 181 ActivityOptions.makeBasic() 182 .setPendingIntentCreatorBackgroundActivityStartMode( 183 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED 184 ) 185 .toBundle(), 186 ) 187 } 188 189 val unfoldTransitionProvider: ProxyUnfoldTransitionProvider? = 190 if ((Flags.enableUnfoldStateAnimation() && ResourceUnfoldTransitionConfig().isEnabled)) 191 ProxyUnfoldTransitionProvider() 192 else null 193 194 private inline fun executeWithErrorLog( 195 errorMsg: () -> String, 196 tag: String = TAG, 197 callback: () -> Any?, 198 ) { 199 try { 200 callback.invoke() 201 } catch (e: RemoteException) { 202 Log.w(tag, errorMsg.invoke(), e) 203 } 204 } 205 206 fun onBackEvent(backEvent: KeyEvent?) = 207 executeWithErrorLog({ "Failed call onBackPressed" }) { 208 systemUiProxy?.onBackEvent(backEvent) 209 } 210 211 fun onImeSwitcherPressed() = 212 executeWithErrorLog({ "Failed call onImeSwitcherPressed" }) { 213 systemUiProxy?.onImeSwitcherPressed() 214 } 215 216 fun onImeSwitcherLongPress() = 217 executeWithErrorLog({ "Failed call onImeSwitcherLongPress" }) { 218 systemUiProxy?.onImeSwitcherLongPress() 219 } 220 221 fun updateContextualEduStats(isTrackpadGesture: Boolean, gestureType: GestureType) = 222 executeWithErrorLog({ "Failed call updateContextualEduStats" }) { 223 systemUiProxy?.updateContextualEduStats(isTrackpadGesture, gestureType.name) 224 } 225 226 fun setHomeRotationEnabled(enabled: Boolean) = 227 executeWithErrorLog({ "Failed call setHomeRotationEnabled" }) { 228 systemUiProxy?.setHomeRotationEnabled(enabled) 229 } 230 231 /** 232 * Sets proxy state, including death linkage, various listeners, and other configuration objects 233 */ 234 @MainThread 235 fun setProxy( 236 proxy: ISystemUiProxy?, 237 pip: IPip?, 238 bubbles: IBubbles?, 239 splitScreen: ISplitScreen?, 240 oneHanded: IOneHanded?, 241 shellTransitions: IShellTransitions?, 242 startingWindow: IStartingWindow?, 243 recentTasks: IRecentTasks?, 244 sysuiUnlockAnimationController: ISysuiUnlockAnimationController?, 245 backAnimation: IBackAnimation?, 246 desktopMode: IDesktopMode?, 247 unfoldAnimation: IUnfoldAnimation?, 248 dragAndDrop: IDragAndDrop?, 249 ) { 250 Preconditions.assertUIThread() 251 unlinkToDeath() 252 systemUiProxy = proxy 253 this.pip = pip 254 this.bubbles = bubbles 255 this.splitScreen = splitScreen 256 this.oneHanded = oneHanded 257 this.shellTransitions = shellTransitions 258 this.startingWindow = startingWindow 259 this.sysuiUnlockAnimationController = sysuiUnlockAnimationController 260 this.recentTasks = recentTasks 261 this.backAnimation = backAnimation 262 this.desktopMode = desktopMode 263 this.unfoldAnimation = if (Flags.enableUnfoldStateAnimation()) null else unfoldAnimation 264 this.dragAndDrop = dragAndDrop 265 linkToDeath() 266 // re-attach the listeners once missing due to setProxy has not been initialized yet. 267 setPipAnimationListener(pipAnimationListener) 268 setBubblesListener(bubblesListener) 269 registerSplitScreenListener(splitScreenListener) 270 registerSplitSelectListener(splitSelectListener) 271 homeVisibilityState.init(this.shellTransitions) 272 focusState.init(this.shellTransitions) 273 setStartingWindowListener(startingWindowListener) 274 setLauncherUnlockAnimationController( 275 launcherActivityClass, 276 launcherUnlockAnimationController, 277 ) 278 LinkedHashMap(remoteTransitions).forEach { (remoteTransition, filter) -> 279 registerRemoteTransition(remoteTransition, filter) 280 } 281 setupTransactionQueue() 282 registerRecentTasksListener(recentTasksListener) 283 setBackToLauncherCallback(backToLauncherCallback, backToLauncherRunner) 284 setUnfoldAnimationListener(unfoldAnimationListener) 285 setDesktopTaskListener(desktopTaskListener) 286 setAssistantOverridesRequested( 287 ContextualSearchInvoker(context).getSysUiAssistOverrideInvocationTypes() 288 ) 289 stateChangeCallbacks.forEach { it.run() } 290 291 if (unfoldTransitionProvider != null) { 292 if (unfoldAnimation != null) { 293 try { 294 unfoldAnimation.setListener(unfoldTransitionProvider) 295 unfoldTransitionProvider.isActive = true 296 } catch (e: RemoteException) { 297 // Ignore 298 } 299 } else { 300 unfoldTransitionProvider.isActive = false 301 } 302 } 303 } 304 305 /** 306 * Clear the proxy to release held resources and turn the majority of its operations into no-ops 307 */ 308 @MainThread 309 fun clearProxy() = 310 setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null) 311 312 /** Adds a callback to be notified whenever the active state changes */ 313 fun addOnStateChangeListener(callback: Runnable) = stateChangeCallbacks.add(callback) 314 315 /** Removes a previously added state change callback */ 316 fun removeOnStateChangeListener(callback: Runnable) = stateChangeCallbacks.remove(callback) 317 318 fun isActive() = systemUiProxy != null 319 320 private fun linkToDeath() = 321 executeWithErrorLog({ "Failed to link sysui proxy death recipient" }) { 322 systemUiProxy?.asBinder()?.linkToDeath(systemUiProxyDeathRecipient, 0 /* flags */) 323 } 324 325 private fun unlinkToDeath() = 326 systemUiProxy?.asBinder()?.unlinkToDeath(systemUiProxyDeathRecipient, 0 /* flags */) 327 328 fun startScreenPinning(taskId: Int) = 329 executeWithErrorLog({ "Failed call startScreenPinning" }) { 330 systemUiProxy?.startScreenPinning(taskId) 331 } 332 333 fun onOverviewShown(fromHome: Boolean, tag: String = TAG) = 334 executeWithErrorLog( 335 { "Failed call onOverviewShown from: ${(if (fromHome) "home" else "app")}" }, 336 tag = tag, 337 ) { 338 systemUiProxy?.onOverviewShown(fromHome) 339 } 340 341 @MainThread 342 fun onStatusBarTouchEvent(event: MotionEvent) { 343 Preconditions.assertUIThread() 344 executeWithErrorLog({ "Failed call onStatusBarTouchEvent with arg: $event" }) { 345 systemUiProxy?.onStatusBarTouchEvent(event) 346 } 347 } 348 349 fun onStatusBarTrackpadEvent(event: MotionEvent) = 350 executeWithErrorLog({ "Failed call onStatusBarTrackpadEvent with arg: $event" }) { 351 systemUiProxy?.onStatusBarTrackpadEvent(event) 352 } 353 354 fun onAssistantProgress(progress: Float) = 355 executeWithErrorLog({ "Failed call onAssistantProgress with progress: $progress" }) { 356 systemUiProxy?.onAssistantProgress(progress) 357 } 358 359 fun onAssistantGestureCompletion(velocity: Float) = 360 executeWithErrorLog({ "Failed call onAssistantGestureCompletion" }) { 361 systemUiProxy?.onAssistantGestureCompletion(velocity) 362 } 363 364 fun startAssistant(args: Bundle) = 365 executeWithErrorLog({ "Failed call startAssistant" }) { 366 systemUiProxy?.startAssistant(args) 367 } 368 369 fun setAssistantOverridesRequested(invocationTypes: IntArray) = 370 executeWithErrorLog({ "Failed call setAssistantOverridesRequested" }) { 371 systemUiProxy?.setAssistantOverridesRequested(invocationTypes) 372 } 373 374 override fun animateNavBarLongPress(isTouchDown: Boolean, shrink: Boolean, durationMs: Long) = 375 executeWithErrorLog({ "Failed call animateNavBarLongPress" }) { 376 systemUiProxy?.animateNavBarLongPress(isTouchDown, shrink, durationMs) 377 } 378 379 fun setOverrideHomeButtonLongPress(duration: Long, slopMultiplier: Float, haptic: Boolean) = 380 executeWithErrorLog({ "Failed call setOverrideHomeButtonLongPress" }) { 381 systemUiProxy?.setOverrideHomeButtonLongPress(duration, slopMultiplier, haptic) 382 } 383 384 fun notifyAccessibilityButtonClicked(displayId: Int) = 385 executeWithErrorLog({ "Failed call notifyAccessibilityButtonClicked" }) { 386 systemUiProxy?.notifyAccessibilityButtonClicked(displayId) 387 } 388 389 fun notifyAccessibilityButtonLongClicked() = 390 executeWithErrorLog({ "Failed call notifyAccessibilityButtonLongClicked" }) { 391 systemUiProxy?.notifyAccessibilityButtonLongClicked() 392 } 393 394 fun stopScreenPinning() = 395 executeWithErrorLog({ "Failed call stopScreenPinning" }) { 396 systemUiProxy?.stopScreenPinning() 397 } 398 399 fun notifyPrioritizedRotation(rotation: Int) = 400 executeWithErrorLog({ "Failed call notifyPrioritizedRotation with arg: $rotation" }) { 401 systemUiProxy?.notifyPrioritizedRotation(rotation) 402 } 403 404 fun notifyTaskbarStatus(visible: Boolean, stashed: Boolean) = 405 executeWithErrorLog({ "Failed call notifyTaskbarStatus with arg: $visible, $stashed" }) { 406 systemUiProxy?.notifyTaskbarStatus(visible, stashed) 407 } 408 409 /** 410 * NOTE: If called to suspend, caller MUST call this method to also un-suspend. [suspend] should 411 * be `true` to stop auto-hide, `false` to resume normal behavior 412 */ 413 fun notifyTaskbarAutohideSuspend(suspend: Boolean) = 414 executeWithErrorLog({ "Failed call notifyTaskbarAutohideSuspend with arg: $suspend" }) { 415 systemUiProxy?.notifyTaskbarAutohideSuspend(suspend) 416 } 417 418 fun takeScreenshot(request: ScreenshotRequest) = 419 executeWithErrorLog({ "Failed call takeScreenshot" }) { 420 systemUiProxy?.takeScreenshot(request) 421 } 422 423 fun expandNotificationPanel() = 424 executeWithErrorLog({ "Failed call expandNotificationPanel" }) { 425 systemUiProxy?.expandNotificationPanel() 426 } 427 428 fun toggleNotificationPanel() = 429 executeWithErrorLog({ "Failed call toggleNotificationPanel" }) { 430 systemUiProxy?.toggleNotificationPanel() 431 } 432 433 fun toggleQuickSettingsPanel() = 434 executeWithErrorLog({ "Failed call toggleQuickSettingsPanel" }) { 435 systemUiProxy?.toggleQuickSettingsPanel() 436 } 437 438 // 439 // Pip 440 // 441 /** Sets the shelf height. */ 442 fun setShelfHeight(visible: Boolean, shelfHeight: Int) = 443 Message.obtain(asyncHandler, MSG_SET_SHELF_HEIGHT, if (visible) 1 else 0, shelfHeight) 444 .sendToTarget() 445 446 @WorkerThread 447 private fun setShelfHeightAsync(visibleInt: Int, shelfHeight: Int) { 448 val visible = visibleInt != 0 449 val changed = visible != lastShelfVisible || shelfHeight != lastShelfHeight 450 val pip = pip 451 if (pip != null && changed) { 452 lastShelfVisible = visible 453 lastShelfHeight = shelfHeight 454 executeWithErrorLog({ 455 "Failed call setShelfHeight visible: $visible height: $shelfHeight" 456 }) { 457 pip.setShelfHeight(visible, shelfHeight) 458 } 459 } 460 } 461 462 /** 463 * Sets the height of the keep clear area that is going to be reported by the Launcher for the 464 * Hotseat. 465 */ 466 fun setLauncherKeepClearAreaHeight(visible: Boolean, height: Int) = 467 Message.obtain( 468 asyncHandler, 469 MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT, 470 if (visible) 1 else 0, 471 height, 472 ) 473 .sendToTarget() 474 475 @WorkerThread 476 private fun setLauncherKeepClearAreaHeight(visibleInt: Int, height: Int) { 477 val visible = visibleInt != 0 478 val changed = 479 visible != lastLauncherKeepClearAreaHeightVisible || 480 height != lastLauncherKeepClearAreaHeight 481 val pip = pip 482 if (pip != null && changed) { 483 lastLauncherKeepClearAreaHeightVisible = visible 484 lastLauncherKeepClearAreaHeight = height 485 executeWithErrorLog({ 486 "Failed call setLauncherKeepClearAreaHeight visible: $visible height: $height" 487 }) { 488 pip.setLauncherKeepClearAreaHeight(visible, height) 489 } 490 } 491 } 492 493 /** Sets listener to get pip animation callbacks. */ 494 fun setPipAnimationListener(listener: IPipAnimationListener?) { 495 executeWithErrorLog({ "Failed call setPinnedStackAnimationListener" }) { 496 pip?.setPipAnimationListener(listener) 497 } 498 pipAnimationListener = listener 499 } 500 501 /** @return Destination bounds of auto-pip animation, `null` if the animation is not ready. */ 502 fun startSwipePipToHome( 503 taskInfo: RunningTaskInfo, 504 launcherRotation: Int, 505 hotseatKeepClearArea: Rect?, 506 ): Rect? { 507 executeWithErrorLog({ "Failed call startSwipePipToHome" }) { 508 return pip?.startSwipePipToHome(taskInfo, launcherRotation, hotseatKeepClearArea) 509 } 510 return null 511 } 512 513 /** 514 * Notifies WM Shell that launcher has finished the preparation of the animation for swipe to 515 * home. WM Shell can choose to fade out the overlay when entering PIP is finished, and WM Shell 516 * should be responsible for cleaning up the overlay. 517 */ 518 fun stopSwipePipToHome( 519 taskId: Int, 520 componentName: ComponentName?, 521 destinationBounds: Rect?, 522 overlay: SurfaceControl?, 523 appBounds: Rect?, 524 sourceRectHint: Rect?, 525 ) = 526 executeWithErrorLog({ "Failed call stopSwipePipToHome" }) { 527 pip?.stopSwipePipToHome( 528 taskId, 529 componentName, 530 destinationBounds, 531 overlay, 532 appBounds, 533 sourceRectHint, 534 ) 535 } 536 537 /** 538 * Notifies WM Shell that launcher has aborted all the animation for swipe to home. WM Shell can 539 * use this callback to clean up its internal states. 540 */ 541 fun abortSwipePipToHome(taskId: Int, componentName: ComponentName?) = 542 executeWithErrorLog({ "Failed call abortSwipePipToHome" }) { 543 pip?.abortSwipePipToHome(taskId, componentName) 544 } 545 546 /** Sets the next pip animation type to be the alpha animation. */ 547 fun setPipAnimationTypeToAlpha() = 548 executeWithErrorLog({ "Failed call setPipAnimationTypeToAlpha" }) { 549 pip?.setPipAnimationTypeToAlpha() 550 } 551 552 /** Sets the app icon size in pixel used by Launcher all apps. */ 553 fun setLauncherAppIconSize(iconSizePx: Int) = 554 executeWithErrorLog({ "Failed call setLauncherAppIconSize" }) { 555 pip?.setLauncherAppIconSize(iconSizePx) 556 } 557 558 // 559 // Bubbles 560 // 561 /** Sets the listener to be notified of bubble state changes. */ 562 fun setBubblesListener(listener: IBubblesListener?) { 563 executeWithErrorLog({ "Failed call registerBubblesListener" }) { 564 bubbles?.apply { 565 bubblesListener?.let { unregisterBubbleListener(it) } 566 listener?.let { registerBubbleListener(it) } 567 } 568 } 569 bubblesListener = listener 570 } 571 572 /** 573 * Tells SysUI to show the bubble with the provided key. 574 * 575 * @param key the key of the bubble to show. 576 * @param top top coordinate of bubble bar on screen 577 */ 578 fun showBubble(key: String?, top: Int) = 579 executeWithErrorLog({ "Failed call showBubble" }) { bubbles?.showBubble(key, top) } 580 581 /** Tells SysUI to remove all bubbles. */ 582 fun removeAllBubbles() = 583 executeWithErrorLog({ "Failed call removeAllBubbles" }) { bubbles?.removeAllBubbles() } 584 585 /** Tells SysUI to collapse the bubbles. */ 586 fun collapseBubbles() = 587 executeWithErrorLog({ "Failed call collapseBubbles" }) { bubbles?.collapseBubbles() } 588 589 /** 590 * Tells SysUI when the bubble is being dragged. Should be called only when the bubble bar is 591 * expanded. 592 * 593 * @param bubbleKey key of the bubble being dragged 594 */ 595 fun startBubbleDrag(bubbleKey: String?) = 596 executeWithErrorLog({ "Failed call startBubbleDrag" }) { 597 bubbles?.startBubbleDrag(bubbleKey) 598 } 599 600 /** 601 * Tells SysUI when the bubble stops being dragged. Should be called only when the bubble bar is 602 * expanded. 603 * 604 * @param location location of the bubble bar 605 * @param top new top coordinate for bubble bar on screen 606 */ 607 fun stopBubbleDrag(location: BubbleBarLocation?, top: Int) = 608 executeWithErrorLog({ "Failed call stopBubbleDrag" }) { 609 bubbles?.stopBubbleDrag(location, top) 610 } 611 612 /** 613 * Tells SysUI to dismiss the bubble with the provided key. 614 * 615 * @param key the key of the bubble to dismiss. 616 * @param timestamp the timestamp when the removal happened. 617 */ 618 fun dragBubbleToDismiss(key: String?, timestamp: Long) = 619 executeWithErrorLog({ "Failed call dragBubbleToDismiss" }) { 620 bubbles?.dragBubbleToDismiss(key, timestamp) 621 } 622 623 /** 624 * Tells SysUI to show user education relative to the reference point provided. 625 * 626 * @param position the bubble bar top center position in Screen coordinates. 627 */ 628 fun showUserEducation(position: Point) = 629 executeWithErrorLog({ "Failed call showUserEducation" }) { 630 bubbles?.showUserEducation(position.x, position.y) 631 } 632 633 /** 634 * Tells SysUI to update the bubble bar location to the new location. 635 * 636 * @param location new location for the bubble bar 637 * @param source what triggered the location update 638 */ 639 fun setBubbleBarLocation(location: BubbleBarLocation?, @UpdateSource source: Int) = 640 executeWithErrorLog({ "Failed call setBubbleBarLocation" }) { 641 bubbles?.setBubbleBarLocation(location, source) 642 } 643 644 /** 645 * Tells SysUI the top coordinate of bubble bar on screen 646 * 647 * @param topOnScreen top coordinate for bubble bar on screen 648 */ 649 fun updateBubbleBarTopOnScreen(topOnScreen: Int) = 650 executeWithErrorLog({ "Failed call updateBubbleBarTopOnScreen" }) { 651 bubbles?.updateBubbleBarTopOnScreen(topOnScreen) 652 } 653 654 /** 655 * Tells SysUI to show a shortcut bubble. 656 * 657 * @param info the shortcut info used to create or identify the bubble. 658 * @param bubbleBarLocation the optional location of the bubble bar. 659 */ 660 @JvmOverloads 661 fun showShortcutBubble(info: ShortcutInfo?, bubbleBarLocation: BubbleBarLocation? = null) = 662 executeWithErrorLog({ "Failed call showShortcutBubble" }) { 663 bubbles?.showShortcutBubble(info, bubbleBarLocation) 664 } 665 666 /** 667 * Tells SysUI to show a bubble of an app. 668 * 669 * @param intent the intent used to create the bubble. 670 * @param bubbleBarLocation the optional location of the bubble bar. 671 */ 672 @JvmOverloads 673 fun showAppBubble( 674 intent: Intent?, 675 user: UserHandle, 676 bubbleBarLocation: BubbleBarLocation? = null, 677 ) = 678 executeWithErrorLog({ "Failed call showAppBubble" }) { 679 bubbles?.showAppBubble(intent, user, bubbleBarLocation) 680 } 681 682 /** Tells SysUI to show the expanded view. */ 683 fun showExpandedView() = 684 executeWithErrorLog({ "Failed call showExpandedView" }) { bubbles?.showExpandedView() } 685 686 /** Tells SysUI to show the bubble drop target. */ 687 @JvmOverloads 688 fun showBubbleDropTarget(show: Boolean, bubbleBarLocation: BubbleBarLocation? = null) = 689 executeWithErrorLog({ "Failed call showDropTarget" }) { 690 bubbles?.showDropTarget(show, bubbleBarLocation) 691 } 692 693 /** Tells SysUI to move the dragged bubble to full screen. */ 694 fun moveDraggedBubbleToFullscreen(key: String, dropLocation: Point) { 695 executeWithErrorLog({ "Failed to call moveDraggedBubbleToFullscreen"}) { 696 bubbles?.moveDraggedBubbleToFullscreen(key, dropLocation) 697 } 698 } 699 700 // 701 // Splitscreen 702 // 703 fun registerSplitScreenListener(listener: ISplitScreenListener?) { 704 executeWithErrorLog({ "Failed call registerSplitScreenListener" }) { 705 splitScreen?.registerSplitScreenListener(listener) 706 } 707 splitScreenListener = listener 708 } 709 710 fun unregisterSplitScreenListener(listener: ISplitScreenListener?) { 711 executeWithErrorLog({ "Failed call unregisterSplitScreenListener" }) { 712 splitScreen?.unregisterSplitScreenListener(listener) 713 } 714 splitScreenListener = null 715 } 716 717 fun registerSplitSelectListener(listener: ISplitSelectListener?) { 718 executeWithErrorLog({ "Failed call registerSplitSelectListener" }) { 719 splitScreen?.registerSplitSelectListener(listener) 720 } 721 splitSelectListener = listener 722 } 723 724 fun unregisterSplitSelectListener(listener: ISplitSelectListener?) { 725 executeWithErrorLog({ "Failed call unregisterSplitSelectListener" }) { 726 splitScreen?.unregisterSplitSelectListener(listener) 727 } 728 splitSelectListener = null 729 } 730 731 /** Start multiple tasks in split-screen simultaneously. */ 732 fun startTasks( 733 taskId1: Int, 734 options1: Bundle?, 735 taskId2: Int, 736 options2: Bundle?, 737 @StagePosition splitPosition: Int, 738 @PersistentSnapPosition snapPosition: Int, 739 remoteTransition: RemoteTransition?, 740 instanceId: InstanceId?, 741 ) = 742 executeWithErrorLog({ "Failed call startTasks" }) { 743 splitScreen?.startTasks( 744 taskId1, 745 options1, 746 taskId2, 747 options2, 748 splitPosition, 749 snapPosition, 750 remoteTransition, 751 instanceId, 752 ) 753 } 754 755 fun startIntentAndTask( 756 pendingIntent: PendingIntent?, 757 userId1: Int, 758 options1: Bundle?, 759 taskId: Int, 760 options2: Bundle?, 761 @StagePosition splitPosition: Int, 762 @PersistentSnapPosition snapPosition: Int, 763 remoteTransition: RemoteTransition?, 764 instanceId: InstanceId?, 765 ) = 766 executeWithErrorLog({ "Failed call startIntentAndTask" }) { 767 splitScreen?.startIntentAndTask( 768 pendingIntent, 769 userId1, 770 options1, 771 taskId, 772 options2, 773 splitPosition, 774 snapPosition, 775 remoteTransition, 776 instanceId, 777 ) 778 } 779 780 fun startIntents( 781 pendingIntent1: PendingIntent?, 782 userId1: Int, 783 shortcutInfo1: ShortcutInfo?, 784 options1: Bundle?, 785 pendingIntent2: PendingIntent?, 786 userId2: Int, 787 shortcutInfo2: ShortcutInfo?, 788 options2: Bundle?, 789 @StagePosition splitPosition: Int, 790 @PersistentSnapPosition snapPosition: Int, 791 remoteTransition: RemoteTransition?, 792 instanceId: InstanceId?, 793 ) = 794 executeWithErrorLog({ "Failed call startIntents" }) { 795 splitScreen?.startIntents( 796 pendingIntent1, 797 userId1, 798 shortcutInfo1, 799 options1, 800 pendingIntent2, 801 userId2, 802 shortcutInfo2, 803 options2, 804 splitPosition, 805 snapPosition, 806 remoteTransition, 807 instanceId, 808 ) 809 } 810 811 fun startShortcutAndTask( 812 shortcutInfo: ShortcutInfo?, 813 options1: Bundle?, 814 taskId: Int, 815 options2: Bundle?, 816 @StagePosition splitPosition: Int, 817 @PersistentSnapPosition snapPosition: Int, 818 remoteTransition: RemoteTransition?, 819 instanceId: InstanceId?, 820 ) = 821 executeWithErrorLog({ "Failed call startShortcutAndTask" }) { 822 splitScreen?.startShortcutAndTask( 823 shortcutInfo, 824 options1, 825 taskId, 826 options2, 827 splitPosition, 828 snapPosition, 829 remoteTransition, 830 instanceId, 831 ) 832 } 833 834 fun startShortcut( 835 packageName: String?, 836 shortcutId: String?, 837 position: Int, 838 options: Bundle?, 839 user: UserHandle?, 840 instanceId: InstanceId?, 841 ) = 842 executeWithErrorLog({ "Failed call startShortcut" }) { 843 splitScreen?.startShortcut(packageName, shortcutId, position, options, user, instanceId) 844 } 845 846 fun startIntent( 847 intent: PendingIntent?, 848 userId: Int, 849 fillInIntent: Intent?, 850 position: Int, 851 options: Bundle?, 852 instanceId: InstanceId?, 853 ) = 854 executeWithErrorLog({ "Failed call startIntent" }) { 855 splitScreen?.startIntent(intent, userId, fillInIntent, position, options, instanceId) 856 } 857 858 /** 859 * Call the desktop mode interface to start a TRANSIT_OPEN transition when launching an intent 860 * from the taskbar so that it can be handled in desktop mode. 861 */ 862 fun startLaunchIntentTransition(intent: Intent, options: Bundle, displayId: Int) = 863 executeWithErrorLog({ "Failed call startLaunchIntentTransition" }) { 864 desktopMode?.startLaunchIntentTransition(intent, options, displayId) 865 } 866 867 // 868 // One handed 869 // 870 fun startOneHandedMode() = 871 executeWithErrorLog({ "Failed call startOneHandedMode" }) { oneHanded?.startOneHanded() } 872 873 fun stopOneHandedMode() = 874 executeWithErrorLog({ "Failed call stopOneHandedMode" }) { oneHanded?.stopOneHanded() } 875 876 // 877 // Remote transitions 878 // 879 fun registerRemoteTransition(remoteTransition: RemoteTransition?, filter: TransitionFilter) { 880 remoteTransition ?: return 881 executeWithErrorLog({ "Failed call registerRemoteTransition" }) { 882 shellTransitions?.registerRemote(filter, remoteTransition) 883 } 884 remoteTransitions.putIfAbsent(remoteTransition, filter) 885 } 886 887 fun unregisterRemoteTransition(remoteTransition: RemoteTransition?) { 888 executeWithErrorLog({ "Failed call unregisterRemoteTransition" }) { 889 shellTransitions?.unregisterRemote(remoteTransition) 890 } 891 remoteTransitions.remove(remoteTransition) 892 } 893 894 /** 895 * Returns a surface which can be used to attach overlays to home task or null if the task 896 * doesn't exist or sysui is not connected 897 */ 898 fun getHomeTaskOverlayContainer(): SurfaceControl? { 899 executeWithErrorLog({ "Failed call getHomeTaskOverlayContainer" }) { 900 return shellTransitions?.homeTaskOverlayContainer 901 } 902 return null 903 } 904 905 /** 906 * Use SystemUI's transaction-queue instead of Launcher's independent one. This is necessary if 907 * Launcher and SystemUI need to coordinate transactions (eg. for shell transitions). 908 */ 909 fun shareTransactionQueue() { 910 if (originalTransactionToken == null) { 911 originalTransactionToken = Transaction.getDefaultApplyToken() 912 } 913 setupTransactionQueue() 914 } 915 916 /** Switch back to using Launcher's independent transaction queue. */ 917 fun unshareTransactionQueue() { 918 if (originalTransactionToken == null) { 919 return 920 } 921 Transaction.setDefaultApplyToken(originalTransactionToken) 922 originalTransactionToken = null 923 } 924 925 private fun setupTransactionQueue() = 926 executeWithErrorLog({ "Error getting Shell's apply token" }) { 927 val token: IBinder = 928 shellTransitions?.shellApplyToken ?: originalTransactionToken ?: return 929 Transaction.setDefaultApplyToken(token) 930 } 931 932 // 933 // Starting window 934 // 935 /** Sets listener to get callbacks when launching a task. */ 936 fun setStartingWindowListener(listener: IStartingWindowListener?) { 937 executeWithErrorLog({ "Failed call setStartingWindowListener" }) { 938 startingWindow?.setStartingWindowListener(listener) 939 } 940 startingWindowListener = listener 941 } 942 943 // 944 // SmartSpace transitions 945 // 946 /** 947 * Sets the instance of [ILauncherUnlockAnimationController] that System UI should use to 948 * control the launcher side of the unlock animation. This will also cause us to dispatch the 949 * current state of the smartspace to System UI (this will subsequently happen if the state 950 * changes). 951 */ 952 fun setLauncherUnlockAnimationController( 953 activityClass: String?, 954 controller: ILauncherUnlockAnimationController?, 955 ) { 956 executeWithErrorLog({ "Failed call setLauncherUnlockAnimationController" }) { 957 sysuiUnlockAnimationController?.apply { 958 setLauncherUnlockController(activityClass, controller) 959 controller?.dispatchSmartspaceStateToSysui() 960 } 961 } 962 launcherActivityClass = activityClass 963 launcherUnlockAnimationController = controller 964 } 965 966 /** 967 * Tells System UI that the Launcher's smartspace state has been updated, so that it can prepare 968 * the unlock animation accordingly. 969 */ 970 fun notifySysuiSmartspaceStateUpdated(state: SmartspaceState?) = 971 executeWithErrorLog({ "Failed call notifySysuiSmartspaceStateUpdated" }) { 972 sysuiUnlockAnimationController?.onLauncherSmartspaceStateUpdated(state) 973 } 974 975 // 976 // Recents 977 // 978 fun registerRecentTasksListener(listener: IRecentTasksListener?) { 979 executeWithErrorLog({ "Failed call registerRecentTasksListener" }) { 980 recentTasks?.registerRecentTasksListener(listener) 981 } 982 recentTasksListener = listener 983 } 984 985 fun unregisterRecentTasksListener(listener: IRecentTasksListener?) { 986 executeWithErrorLog({ "Failed call unregisterRecentTasksListener" }) { 987 recentTasks?.unregisterRecentTasksListener(listener) 988 } 989 recentTasksListener = null 990 } 991 992 // 993 // Back navigation transitions 994 // 995 /** Sets the launcher [android.window.IOnBackInvokedCallback] to shell */ 996 fun setBackToLauncherCallback( 997 callback: IOnBackInvokedCallback?, 998 runner: IRemoteAnimationRunner?, 999 ) { 1000 backToLauncherCallback = callback 1001 backToLauncherRunner = runner 1002 if (callback == null) return 1003 try { 1004 backAnimation?.setBackToLauncherCallback(callback, runner) 1005 } catch (e: RemoteException) { 1006 Log.e(TAG, "Failed call setBackToLauncherCallback", e) 1007 } catch (e: SecurityException) { 1008 Log.e(TAG, "Failed call setBackToLauncherCallback", e) 1009 } 1010 } 1011 1012 /** 1013 * Clears the previously registered [IOnBackInvokedCallback]. 1014 * 1015 * @param callback The previously registered callback instance. 1016 */ 1017 fun clearBackToLauncherCallback(callback: IOnBackInvokedCallback) { 1018 if (backToLauncherCallback !== callback) { 1019 return 1020 } 1021 backToLauncherCallback = null 1022 backToLauncherRunner = null 1023 executeWithErrorLog({ "Failed call clearBackToLauncherCallback" }) { 1024 backAnimation?.clearBackToLauncherCallback() 1025 } 1026 } 1027 1028 /** Called when the status bar color needs to be customized when back navigation. */ 1029 fun customizeStatusBarAppearance(appearance: AppearanceRegion?) = 1030 executeWithErrorLog({ "Failed call customizeStatusBarAppearance" }) { 1031 backAnimation?.customizeStatusBarAppearance(appearance) 1032 } 1033 1034 class GetRecentTasksException : Exception { 1035 constructor(message: String?) : super(message) 1036 1037 constructor(message: String?, cause: Throwable?) : super(message, cause) 1038 } 1039 1040 /** 1041 * Retrieves a list of Recent tasks from ActivityManager. 1042 * 1043 * @throws GetRecentTasksException if IRecentTasks is not initialized, or when we get 1044 * RemoteException from server side 1045 */ 1046 @Throws(GetRecentTasksException::class) 1047 fun getRecentTasks(numTasks: Int, userId: Int): ArrayList<GroupedTaskInfo> { 1048 if (recentTasks == null) { 1049 Log.e(TAG, "getRecentTasks() failed due to null mRecentTasks") 1050 throw GetRecentTasksException("null mRecentTasks") 1051 } 1052 try { 1053 val rawTasks = 1054 recentTasks?.getRecentTasks( 1055 numTasks, 1056 ActivityManager.RECENT_IGNORE_UNAVAILABLE, 1057 userId, 1058 ) ?: return ArrayList() 1059 return ArrayList(rawTasks.asList()) 1060 } catch (e: RemoteException) { 1061 Log.e(TAG, "Failed call getRecentTasks", e) 1062 throw GetRecentTasksException("Failed call getRecentTasks", e) 1063 } 1064 } 1065 1066 /** Gets the set of running tasks. */ 1067 fun getRunningTasks(numTasks: Int): List<RunningTaskInfo> { 1068 if (!shouldEnableRunningTasksForDesktopMode()) return emptyList() 1069 executeWithErrorLog({ "Failed call getRunningTasks" }) { 1070 return recentTasks?.getRunningTasks(numTasks)?.asList() ?: emptyList() 1071 } 1072 return emptyList() 1073 } 1074 1075 private fun shouldEnableRunningTasksForDesktopMode(): Boolean = 1076 DesktopModeStatus.canEnterDesktopMode(context) && 1077 ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS.isTrue 1078 1079 private fun handleMessageAsync(msg: Message): Boolean { 1080 return when (msg.what) { 1081 MSG_SET_SHELF_HEIGHT -> { 1082 setShelfHeightAsync(msg.arg1, msg.arg2) 1083 true 1084 } 1085 1086 MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT -> { 1087 setLauncherKeepClearAreaHeight(msg.arg1, msg.arg2) 1088 true 1089 } 1090 1091 else -> false 1092 } 1093 } 1094 1095 // 1096 // Desktop Mode 1097 // 1098 /** Calls shell to create a new desk (if possible) on the display whose ID is `displayId`. */ 1099 fun createDesk(displayId: Int) = 1100 executeWithErrorLog({ "Failed call createDesk" }) { desktopMode?.createDesk(displayId) } 1101 1102 /** 1103 * Calls shell to activate the desk whose ID is `deskId` on whatever display it exists on. This 1104 * will bring all tasks on this desk to the front. 1105 */ 1106 fun activateDesk(deskId: Int, transition: RemoteTransition?) = 1107 executeWithErrorLog({ "Failed call activateDesk" }) { 1108 desktopMode?.activateDesk(deskId, transition) 1109 } 1110 1111 /** Calls shell to remove the desk whose ID is `deskId`. */ 1112 fun removeDesk(deskId: Int) = 1113 executeWithErrorLog({ "Failed call removeDesk" }) { desktopMode?.removeDesk(deskId) } 1114 1115 /** Calls shell to remove all the available desks on all displays. */ 1116 fun removeAllDesks() = 1117 executeWithErrorLog({ "Failed call removeAllDesks" }) { desktopMode?.removeAllDesks() } 1118 1119 /** Call shell to show all apps active on the desktop */ 1120 fun showDesktopApps(displayId: Int, transition: RemoteTransition?) = 1121 executeWithErrorLog({ "Failed call showDesktopApps" }) { 1122 desktopMode?.showDesktopApps(displayId, transition) 1123 } 1124 1125 /** If task with the given id is on the desktop, bring it to front */ 1126 fun showDesktopApp( 1127 taskId: Int, 1128 transition: RemoteTransition?, 1129 toFrontReason: DesktopTaskToFrontReason, 1130 ) = 1131 executeWithErrorLog({ "Failed call showDesktopApp" }) { 1132 desktopMode?.showDesktopApp(taskId, transition, toFrontReason) 1133 } 1134 1135 /** Set a listener on shell to get updates about desktop task state */ 1136 fun setDesktopTaskListener(listener: IDesktopTaskListener?) { 1137 desktopTaskListener = listener 1138 executeWithErrorLog({ "Failed call setDesktopTaskListener" }) { 1139 desktopMode?.setTaskListener(listener) 1140 } 1141 } 1142 1143 /** Perform cleanup transactions after animation to split select is complete */ 1144 fun onDesktopSplitSelectAnimComplete(taskInfo: RunningTaskInfo?) = 1145 executeWithErrorLog({ "Failed call onDesktopSplitSelectAnimComplete" }) { 1146 desktopMode?.onDesktopSplitSelectAnimComplete(taskInfo) 1147 } 1148 1149 /** Call shell to move a task with given `taskId` to desktop */ 1150 fun moveToDesktop( 1151 taskId: Int, 1152 transitionSource: DesktopModeTransitionSource?, 1153 transition: RemoteTransition?, 1154 successCallback: Runnable, 1155 ) = 1156 executeWithErrorLog({ "Failed call moveToDesktop" }) { 1157 desktopMode?.moveToDesktop( 1158 taskId, 1159 transitionSource, 1160 transition, 1161 object : IMoveToDesktopCallback.Stub() { 1162 override fun onTaskMovedToDesktop() { 1163 successCallback.run() 1164 } 1165 }, 1166 ) 1167 } 1168 1169 /** Call shell to remove the desktop that is on given `displayId` */ 1170 fun removeDefaultDeskInDisplay(displayId: Int) = 1171 executeWithErrorLog({ "Failed call removeDefaultDeskInDisplay" }) { 1172 desktopMode?.removeDefaultDeskInDisplay(displayId) 1173 } 1174 1175 /** Call shell to move a task with given `taskId` to external display. */ 1176 fun moveToExternalDisplay(taskId: Int) = 1177 executeWithErrorLog({ "Failed call moveToExternalDisplay" }) { 1178 desktopMode?.moveToExternalDisplay(taskId) 1179 } 1180 1181 // 1182 // Unfold transition 1183 // 1184 /** Sets the unfold animation lister to sysui. */ 1185 fun setUnfoldAnimationListener(callback: IUnfoldTransitionListener?) { 1186 unfoldAnimationListener = callback 1187 executeWithErrorLog({ "Failed call setUnfoldAnimationListener" }) { 1188 unfoldAnimation?.setListener(callback) 1189 } 1190 } 1191 1192 // 1193 // Recents 1194 // 1195 /** Starts the recents activity. The caller should manage the thread on which this is called. */ 1196 fun startRecentsActivity( 1197 intent: Intent?, 1198 options: ActivityOptions, 1199 listener: RecentsAnimationListener, 1200 useSyntheticRecentsTransition: Boolean, 1201 ): Boolean { 1202 executeWithErrorLog({ "Error starting recents via shell" }) { 1203 recentTasks?.startRecentsTransition( 1204 recentsPendingIntent, 1205 intent, 1206 options.toBundle().apply { 1207 if (useSyntheticRecentsTransition) { 1208 putBoolean("is_synthetic_recents_transition", true) 1209 } 1210 }, 1211 context.iApplicationThread, 1212 RecentsAnimationListenerStub(listener), 1213 ) 1214 ?: run { 1215 ActiveGestureProtoLogProxy.logRecentTasksMissing() 1216 return false 1217 } 1218 return true 1219 } 1220 return false 1221 } 1222 1223 private class RecentsAnimationListenerStub(val listener: RecentsAnimationListener) : 1224 IRecentsAnimationRunner.Stub() { 1225 override fun onAnimationStart( 1226 controller: IRecentsAnimationController, 1227 apps: Array<RemoteAnimationTarget>?, 1228 wallpapers: Array<RemoteAnimationTarget>?, 1229 homeContentInsets: Rect?, 1230 minimizedHomeBounds: Rect?, 1231 extras: Bundle?, 1232 transitionInfo: TransitionInfo?, 1233 ) = 1234 listener.onAnimationStart( 1235 RecentsAnimationControllerCompat(controller), 1236 apps, 1237 wallpapers, 1238 homeContentInsets, 1239 minimizedHomeBounds, 1240 extras?.apply { 1241 // Aidl bundles need to explicitly set class loader 1242 // https://developer.android.com/guide/components/aidl#Bundles 1243 classLoader = SplitBounds::class.java.classLoader 1244 }, 1245 transitionInfo, 1246 ) 1247 1248 override fun onAnimationCanceled(taskIds: IntArray?, taskSnapshots: Array<TaskSnapshot>?) = 1249 listener.onAnimationCanceled(wrap(taskIds, taskSnapshots)) 1250 1251 override fun onTasksAppeared( 1252 apps: Array<RemoteAnimationTarget>?, 1253 transitionInfo: TransitionInfo?, 1254 ) { 1255 listener.onTasksAppeared(apps, transitionInfo) 1256 } 1257 } 1258 1259 // 1260 // Drag and drop 1261 // 1262 /** 1263 * For testing purposes. Returns `true` only if the shell drop target has shown and drawn and is 1264 * ready to handle drag events and the subsequent drop. 1265 */ 1266 fun isDragAndDropReady(): Boolean { 1267 executeWithErrorLog({ "Error querying drag state" }) { 1268 return dragAndDrop?.isReadyToHandleDrag ?: false 1269 } 1270 return false 1271 } 1272 1273 fun dump(pw: PrintWriter) { 1274 pw.println("$TAG:") 1275 1276 pw.println("\tmSystemUiProxy=$systemUiProxy") 1277 pw.println("\tmPip=$pip") 1278 pw.println("\tmPipAnimationListener=$pipAnimationListener") 1279 pw.println("\tmBubbles=$bubbles") 1280 pw.println("\tmBubblesListener=$bubblesListener") 1281 pw.println("\tmSplitScreen=$splitScreen") 1282 pw.println("\tmSplitScreenListener=$splitScreenListener") 1283 pw.println("\tmSplitSelectListener=$splitSelectListener") 1284 pw.println("\tmOneHanded=$oneHanded") 1285 pw.println("\tmShellTransitions=$shellTransitions") 1286 pw.println("\tmHomeVisibilityState=" + homeVisibilityState) 1287 pw.println("\tmFocusState=" + focusState) 1288 pw.println("\tmStartingWindow=$startingWindow") 1289 pw.println("\tmStartingWindowListener=$startingWindowListener") 1290 pw.println("\tmSysuiUnlockAnimationController=$sysuiUnlockAnimationController") 1291 pw.println("\tmLauncherActivityClass=$launcherActivityClass") 1292 pw.println("\tmLauncherUnlockAnimationController=$launcherUnlockAnimationController") 1293 pw.println("\tmRecentTasks=$recentTasks") 1294 pw.println("\tmRecentTasksListener=$recentTasksListener") 1295 pw.println("\tmBackAnimation=$backAnimation") 1296 pw.println("\tmBackToLauncherCallback=$backToLauncherCallback") 1297 pw.println("\tmBackToLauncherRunner=$backToLauncherRunner") 1298 pw.println("\tmDesktopMode=$desktopMode") 1299 pw.println("\tmDesktopTaskListener=$desktopTaskListener") 1300 pw.println("\tmUnfoldAnimation=$unfoldAnimation") 1301 pw.println("\tmUnfoldAnimationListener=$unfoldAnimationListener") 1302 pw.println("\tmDragAndDrop=$dragAndDrop") 1303 } 1304 1305 /** Adds all interfaces held by this proxy to the bundle */ 1306 @VisibleForTesting 1307 fun addAllInterfaces(out: Bundle) { 1308 QuickStepContract.addInterface(systemUiProxy, out) 1309 QuickStepContract.addInterface(pip, out) 1310 QuickStepContract.addInterface(bubbles, out) 1311 QuickStepContract.addInterface(sysuiUnlockAnimationController, out) 1312 QuickStepContract.addInterface(splitScreen, out) 1313 QuickStepContract.addInterface(oneHanded, out) 1314 QuickStepContract.addInterface(shellTransitions, out) 1315 QuickStepContract.addInterface(startingWindow, out) 1316 QuickStepContract.addInterface(recentTasks, out) 1317 QuickStepContract.addInterface(backAnimation, out) 1318 QuickStepContract.addInterface(desktopMode, out) 1319 QuickStepContract.addInterface(unfoldAnimation, out) 1320 QuickStepContract.addInterface(dragAndDrop, out) 1321 } 1322 1323 companion object { 1324 private const val TAG = "SystemUiProxy" 1325 1326 @JvmField val INSTANCE = DaggerSingletonObject(LauncherAppComponent::getSystemUiProxy) 1327 1328 private const val MSG_SET_SHELF_HEIGHT = 1 1329 private const val MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT = 2 1330 } 1331 } 1332