1 /* 2 * Copyright (C) 2024 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.content.Context 19 import android.view.MotionEvent 20 import androidx.annotation.VisibleForTesting 21 import com.android.launcher3.anim.AnimatedFloat 22 import com.android.launcher3.statemanager.BaseState 23 import com.android.launcher3.statemanager.StatefulContainer 24 import com.android.launcher3.taskbar.TaskbarManager 25 import com.android.launcher3.util.LockedUserState.Companion.get 26 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer 27 import com.android.quickstep.inputconsumers.AssistantInputConsumer 28 import com.android.quickstep.inputconsumers.BubbleBarInputConsumer 29 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer 30 import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer 31 import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer 32 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer 33 import com.android.quickstep.inputconsumers.OverviewInputConsumer 34 import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer 35 import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer 36 import com.android.quickstep.inputconsumers.ResetGestureInputConsumer 37 import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer 38 import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer 39 import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer 40 import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer 41 import com.android.quickstep.util.ActiveGestureErrorDetector 42 import com.android.quickstep.util.ActiveGestureLog 43 import com.android.quickstep.util.ActiveGestureLog.CompoundString 44 import com.android.quickstep.util.ActiveGestureProtoLogProxy 45 import com.android.quickstep.views.RecentsViewContainer 46 import com.android.systemui.shared.system.InputChannelCompat 47 import com.android.systemui.shared.system.InputMonitorCompat 48 import com.android.wm.shell.Flags 49 import java.util.function.Consumer 50 import java.util.function.Function 51 52 /** Utility class for creating input consumers. */ 53 object InputConsumerUtils { 54 private const val SUBSTRING_PREFIX = "; " 55 private const val NEWLINE_PREFIX = "\n\t\t\t-> " 56 57 @JvmStatic newConsumernull58 fun <S : BaseState<S>, T> newConsumer( 59 context: Context, 60 userUnlocked: Boolean, 61 overviewComponentObserver: OverviewComponentObserver, 62 deviceState: RecentsAnimationDeviceState, 63 previousGestureState: GestureState, 64 gestureState: GestureState, 65 taskAnimationManager: TaskAnimationManager, 66 inputMonitorCompat: InputMonitorCompat, 67 swipeUpHandlerFactory: AbsSwipeUpHandler.Factory, 68 onCompleteCallback: Consumer<OtherActivityInputConsumer>, 69 inputEventReceiver: InputChannelCompat.InputEventReceiver, 70 taskbarManager: TaskbarManager, 71 swipeUpProxyProvider: Function<GestureState?, AnimatedFloat?>, 72 overviewCommandHelper: OverviewCommandHelper, 73 event: MotionEvent, 74 ): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> { 75 val tac = taskbarManager.currentActivityContext 76 val bubbleControllers = tac?.bubbleControllers 77 if (bubbleControllers != null && BubbleBarInputConsumer.isEventOnBubbles(tac, event)) { 78 val consumer: InputConsumer = 79 BubbleBarInputConsumer( 80 context, 81 gestureState.displayId, 82 bubbleControllers, 83 inputMonitorCompat, 84 ) 85 logInputConsumerSelectionReason( 86 consumer, 87 newCompoundString("event is on bubbles, creating new input consumer"), 88 ) 89 return consumer 90 } 91 val progressProxy = swipeUpProxyProvider.apply(gestureState) 92 if (progressProxy != null) { 93 val consumer: InputConsumer = 94 ProgressDelegateInputConsumer( 95 context, 96 taskAnimationManager, 97 gestureState, 98 inputMonitorCompat, 99 progressProxy, 100 ) 101 102 logInputConsumerSelectionReason( 103 consumer, 104 newCompoundString( 105 "mSwipeUpProxyProvider has been set, using ProgressDelegateInputConsumer" 106 ), 107 ) 108 109 return consumer 110 } 111 112 val canStartSystemGesture = 113 if (gestureState.isTrackpadGesture) deviceState.canStartTrackpadGesture() 114 else deviceState.canStartSystemGesture() 115 116 if (!get(context).isUserUnlocked) { 117 val reasonString = newCompoundString("device locked") 118 val consumer = 119 if (canStartSystemGesture) { 120 // This handles apps launched in direct boot mode (e.g. dialer) as well as apps 121 // launched while device is locked even after exiting direct boot mode (e.g. 122 // camera). 123 createDeviceLockedInputConsumer( 124 context, 125 userUnlocked, 126 taskbarManager, 127 deviceState, 128 gestureState, 129 taskAnimationManager, 130 inputMonitorCompat, 131 reasonString.append("%scan start system gesture", SUBSTRING_PREFIX), 132 ) 133 } else { 134 getDefaultInputConsumer( 135 gestureState.displayId, 136 userUnlocked, 137 taskAnimationManager, 138 taskbarManager, 139 reasonString.append("%scannot start system gesture", SUBSTRING_PREFIX), 140 ) 141 } 142 logInputConsumerSelectionReason(consumer, reasonString) 143 return consumer 144 } 145 146 var reasonString: CompoundString 147 var base: InputConsumer 148 // When there is an existing recents animation running, bypass systemState check as this is 149 // a followup gesture and the first gesture started in a valid system state. 150 if (canStartSystemGesture || previousGestureState.isRecentsAnimationRunning) { 151 reasonString = 152 newCompoundString( 153 if (canStartSystemGesture) 154 "can start system gesture, trying to use base consumer" 155 else "recents animation was running, trying to use base consumer" 156 ) 157 base = 158 newBaseConsumer<S, T>( 159 context, 160 userUnlocked, 161 taskbarManager, 162 overviewComponentObserver, 163 deviceState, 164 previousGestureState, 165 gestureState, 166 taskAnimationManager, 167 inputMonitorCompat, 168 swipeUpHandlerFactory, 169 onCompleteCallback, 170 inputEventReceiver, 171 event, 172 reasonString, 173 ) 174 } else { 175 reasonString = 176 newCompoundString( 177 "cannot start system gesture and recents " + 178 "animation was not running, trying to use default input consumer" 179 ) 180 base = 181 getDefaultInputConsumer( 182 gestureState.displayId, 183 userUnlocked, 184 taskAnimationManager, 185 taskbarManager, 186 reasonString, 187 ) 188 } 189 if (deviceState.isGesturalNavMode || gestureState.isTrackpadGesture) { 190 handleOrientationSetup(base) 191 } 192 if (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture) { 193 val reasonPrefix = 194 "device is in gesture navigation mode or 3-button mode with a trackpad gesture" 195 if (deviceState.canTriggerAssistantAction(event)) { 196 reasonString.append( 197 "%s%s%sgesture can trigger the assistant, " + 198 "trying to use assistant input consumer", 199 NEWLINE_PREFIX, 200 reasonPrefix, 201 SUBSTRING_PREFIX, 202 ) 203 base = 204 tryCreateAssistantInputConsumer( 205 context, 206 deviceState, 207 inputMonitorCompat, 208 base, 209 gestureState, 210 event, 211 reasonString, 212 ) 213 } 214 215 // If Taskbar is present, we listen for swipe or cursor hover events to unstash it. 216 if (tac != null && base !is AssistantInputConsumer) { 217 // Present always on large screen or on small screen w/ flag 218 val useTaskbarConsumer = 219 (tac.deviceProfile.isTaskbarPresent && 220 !tac.isPhoneMode && 221 !tac.isInStashedLauncherState) 222 if (canStartSystemGesture && useTaskbarConsumer) { 223 reasonString.append( 224 "%s%s%sTaskbarActivityContext != null, " + 225 "using TaskbarUnstashInputConsumer", 226 NEWLINE_PREFIX, 227 reasonPrefix, 228 SUBSTRING_PREFIX, 229 ) 230 base = 231 TaskbarUnstashInputConsumer( 232 context, 233 base, 234 inputMonitorCompat, 235 tac, 236 overviewCommandHelper, 237 gestureState, 238 ) 239 } 240 } 241 if (Flags.enableBubblesLongPressNavHandle()) { 242 // Create bubbles input consumer before NavHandleLongPressInputConsumer. 243 // This allows for nav handle to fall back to bubbles. 244 if (deviceState.isBubblesExpanded) { 245 reasonString = 246 newCompoundString(reasonPrefix) 247 .append( 248 "%sbubbles expanded, trying to use default input consumer", 249 SUBSTRING_PREFIX, 250 ) 251 // Bubbles can handle home gesture itself. 252 base = 253 getDefaultInputConsumer( 254 gestureState.displayId, 255 userUnlocked, 256 taskAnimationManager, 257 taskbarManager, 258 reasonString, 259 ) 260 } 261 } 262 263 val navHandle = tac?.navHandle ?: SystemUiProxy.INSTANCE[context] 264 if ( 265 canStartSystemGesture && 266 !previousGestureState.isRecentsAnimationRunning && 267 navHandle.canNavHandleBeLongPressed() && 268 !ignoreThreeFingerTrackpadForNavHandleLongPress(gestureState) 269 ) { 270 reasonString.append( 271 "%s%s%sNot running recents animation, ", 272 NEWLINE_PREFIX, 273 reasonPrefix, 274 SUBSTRING_PREFIX, 275 ) 276 if (tac != null && tac.navHandle.canNavHandleBeLongPressed()) { 277 reasonString.append("stashed handle is long-pressable, ") 278 } 279 reasonString.append("using NavHandleLongPressInputConsumer") 280 base = 281 NavHandleLongPressInputConsumer( 282 context, 283 base, 284 inputMonitorCompat, 285 deviceState, 286 navHandle, 287 gestureState, 288 ) 289 } 290 291 if (!Flags.enableBubblesLongPressNavHandle()) { 292 // Continue overriding nav handle input consumer with bubbles 293 if (deviceState.isBubblesExpanded) { 294 reasonString = 295 newCompoundString(reasonPrefix) 296 .append( 297 "%sbubbles expanded, trying to use default input consumer", 298 SUBSTRING_PREFIX, 299 ) 300 // Bubbles can handle home gesture itself. 301 base = 302 getDefaultInputConsumer( 303 gestureState.displayId, 304 userUnlocked, 305 taskAnimationManager, 306 taskbarManager, 307 reasonString, 308 ) 309 } 310 } 311 312 if (deviceState.isSystemUiDialogShowing) { 313 reasonString = 314 newCompoundString(reasonPrefix) 315 .append( 316 "%ssystem dialog is showing, using SysUiOverlayInputConsumer", 317 SUBSTRING_PREFIX, 318 ) 319 base = 320 SysUiOverlayInputConsumer( 321 context, 322 gestureState.displayId, 323 deviceState, 324 inputMonitorCompat, 325 ) 326 } 327 328 if ( 329 gestureState.isTrackpadGesture && 330 canStartSystemGesture && 331 !previousGestureState.isRecentsAnimationRunning 332 ) { 333 reasonString = 334 newCompoundString(reasonPrefix) 335 .append( 336 "%sTrackpad 3-finger gesture, using TrackpadStatusBarInputConsumer", 337 SUBSTRING_PREFIX, 338 ) 339 base = 340 TrackpadStatusBarInputConsumer( 341 context, 342 gestureState.displayId, 343 base, 344 inputMonitorCompat, 345 ) 346 } 347 348 if (deviceState.isScreenPinningActive) { 349 reasonString = 350 newCompoundString(reasonPrefix) 351 .append( 352 "%sscreen pinning is active, using ScreenPinnedInputConsumer", 353 SUBSTRING_PREFIX, 354 ) 355 // Note: we only allow accessibility to wrap this, and it replaces the previous 356 // base input consumer (which should be NO_OP anyway since topTaskLocked == true). 357 base = ScreenPinnedInputConsumer(context, gestureState) 358 } 359 360 if (deviceState.canTriggerOneHandedAction(event)) { 361 reasonString.append( 362 "%s%s%sgesture can trigger one handed mode, " + 363 "using OneHandedModeInputConsumer", 364 NEWLINE_PREFIX, 365 reasonPrefix, 366 SUBSTRING_PREFIX, 367 ) 368 base = 369 OneHandedModeInputConsumer( 370 context, 371 gestureState.displayId, 372 deviceState, 373 base, 374 inputMonitorCompat, 375 ) 376 } 377 378 if (deviceState.isAccessibilityMenuAvailable) { 379 reasonString.append( 380 "%s%s%saccessibility menu is available, using AccessibilityInputConsumer", 381 NEWLINE_PREFIX, 382 reasonPrefix, 383 SUBSTRING_PREFIX, 384 ) 385 base = 386 AccessibilityInputConsumer( 387 context, 388 gestureState.displayId, 389 deviceState, 390 base, 391 inputMonitorCompat, 392 ) 393 } 394 } else { 395 val reasonPrefix = "device is not in gesture navigation mode" 396 if (deviceState.isScreenPinningActive) { 397 reasonString = 398 newCompoundString(reasonPrefix) 399 .append( 400 "%sscreen pinning is active, trying to use default input consumer", 401 SUBSTRING_PREFIX, 402 ) 403 base = 404 getDefaultInputConsumer( 405 gestureState.displayId, 406 userUnlocked, 407 taskAnimationManager, 408 taskbarManager, 409 reasonString, 410 ) 411 } 412 413 if (deviceState.canTriggerOneHandedAction(event)) { 414 reasonString.append( 415 "%s%s%sgesture can trigger one handed mode, " + 416 "using OneHandedModeInputConsumer", 417 NEWLINE_PREFIX, 418 reasonPrefix, 419 SUBSTRING_PREFIX, 420 ) 421 base = 422 OneHandedModeInputConsumer( 423 context, 424 gestureState.displayId, 425 deviceState, 426 base, 427 inputMonitorCompat, 428 ) 429 } 430 } 431 logInputConsumerSelectionReason(base, reasonString) 432 return base 433 } 434 435 @JvmStatic tryCreateAssistantInputConsumernull436 fun tryCreateAssistantInputConsumer( 437 context: Context, 438 deviceState: RecentsAnimationDeviceState, 439 inputMonitorCompat: InputMonitorCompat, 440 gestureState: GestureState, 441 motionEvent: MotionEvent, 442 ): InputConsumer { 443 return tryCreateAssistantInputConsumer( 444 context, 445 deviceState, 446 inputMonitorCompat, 447 InputConsumer.createNoOpInputConsumer(gestureState.displayId), 448 gestureState, 449 motionEvent, 450 CompoundString.NO_OP, 451 ) 452 } 453 tryCreateAssistantInputConsumernull454 private fun tryCreateAssistantInputConsumer( 455 context: Context, 456 deviceState: RecentsAnimationDeviceState, 457 inputMonitorCompat: InputMonitorCompat, 458 base: InputConsumer, 459 gestureState: GestureState, 460 motionEvent: MotionEvent, 461 reasonString: CompoundString, 462 ): InputConsumer { 463 return if (deviceState.isGestureBlockedTask(gestureState.runningTask)) { 464 reasonString.append( 465 "%sis gesture-blocked task, using base input consumer", 466 SUBSTRING_PREFIX, 467 ) 468 base 469 } else { 470 reasonString.append("%susing AssistantInputConsumer", SUBSTRING_PREFIX) 471 AssistantInputConsumer( 472 context, 473 gestureState, 474 base, 475 inputMonitorCompat, 476 deviceState, 477 motionEvent, 478 ) 479 } 480 } 481 482 @VisibleForTesting 483 @JvmStatic newBaseConsumernull484 fun <S : BaseState<S>, T> newBaseConsumer( 485 context: Context, 486 userUnlocked: Boolean, 487 taskbarManager: TaskbarManager, 488 overviewComponentObserver: OverviewComponentObserver, 489 deviceState: RecentsAnimationDeviceState, 490 previousGestureState: GestureState, 491 gestureState: GestureState, 492 taskAnimationManager: TaskAnimationManager, 493 inputMonitorCompat: InputMonitorCompat, 494 swipeUpHandlerFactory: AbsSwipeUpHandler.Factory, 495 onCompleteCallback: Consumer<OtherActivityInputConsumer>, 496 inputEventReceiver: InputChannelCompat.InputEventReceiver, 497 event: MotionEvent, 498 reasonString: CompoundString, 499 ): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> { 500 if (deviceState.isKeyguardShowingOccluded) { 501 // This handles apps showing over the lockscreen (e.g. camera) 502 return createDeviceLockedInputConsumer( 503 context, 504 userUnlocked, 505 taskbarManager, 506 deviceState, 507 gestureState, 508 taskAnimationManager, 509 inputMonitorCompat, 510 reasonString.append( 511 "%skeyguard is showing occluded, " + 512 "trying to use device locked input consumer", 513 SUBSTRING_PREFIX, 514 ), 515 ) 516 } 517 518 reasonString.append("%skeyguard is not showing occluded", SUBSTRING_PREFIX) 519 520 val runningTask = gestureState.runningTask 521 // Use overview input consumer for sharesheets on top of home. 522 val forceOverviewInputConsumer = 523 gestureState.getContainerInterface<S, T>().isStarted() && 524 runningTask != null && 525 runningTask.isRootChooseActivity 526 527 if (!Flags.enableShellTopTaskTracking()) { 528 // In the case where we are in an excluded, translucent overlay, ignore it and treat the 529 // running activity as the task behind the overlay. 530 val otherVisibleTask = runningTask?.visibleNonExcludedTask 531 if (otherVisibleTask != null) { 532 ActiveGestureProtoLogProxy.logUpdateGestureStateRunningTask( 533 otherVisibleTask.packageName ?: "MISSING", 534 runningTask.packageName ?: "MISSING", 535 ) 536 gestureState.updateRunningTask(otherVisibleTask) 537 } 538 } 539 540 val previousGestureAnimatedToLauncher = 541 (previousGestureState.isRunningAnimationToLauncher || 542 deviceState.isPredictiveBackToHomeInProgress) 543 // with shell-transitions, home is resumed during recents animation, so 544 // explicitly check against recents animation too. 545 val launcherResumedThroughShellTransition = 546 (gestureState.getContainerInterface<S, T>().isResumed() && 547 !previousGestureState.isRecentsAnimationRunning) 548 // If a task fragment within Launcher is resumed 549 val launcherChildActivityResumed = 550 (com.android.launcher3.Flags.useActivityOverlay() && 551 runningTask != null && 552 runningTask.isHomeTask && 553 overviewComponentObserver.isHomeAndOverviewSameActivity && 554 !launcherResumedThroughShellTransition && 555 !previousGestureState.isRecentsAnimationRunning) 556 557 return if (gestureState.getContainerInterface<S, T>().isInLiveTileMode()) { 558 createOverviewInputConsumer<S, T>( 559 userUnlocked, 560 taskAnimationManager, 561 taskbarManager, 562 deviceState, 563 inputMonitorCompat, 564 previousGestureState, 565 gestureState, 566 event, 567 reasonString.append( 568 "%sis in live tile mode, trying to use overview input consumer", 569 SUBSTRING_PREFIX, 570 ), 571 ) 572 } else if (runningTask == null) { 573 getDefaultInputConsumer( 574 gestureState.displayId, 575 userUnlocked, 576 taskAnimationManager, 577 taskbarManager, 578 reasonString.append("%srunning task == null", SUBSTRING_PREFIX), 579 ) 580 } else if ( 581 previousGestureAnimatedToLauncher || 582 launcherResumedThroughShellTransition || 583 forceOverviewInputConsumer 584 ) { 585 createOverviewInputConsumer<S, T>( 586 userUnlocked, 587 taskAnimationManager, 588 taskbarManager, 589 deviceState, 590 inputMonitorCompat, 591 previousGestureState, 592 gestureState, 593 event, 594 reasonString.append( 595 if (previousGestureAnimatedToLauncher) 596 ("%sprevious gesture animated to launcher, " + 597 "trying to use overview input consumer") 598 else 599 (if (launcherResumedThroughShellTransition) 600 ("%slauncher resumed through a shell transition, " + 601 "trying to use overview input consumer") 602 else 603 ("%sforceOverviewInputConsumer == true, " + 604 "trying to use overview input consumer")), 605 SUBSTRING_PREFIX, 606 ), 607 ) 608 } else if (deviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) { 609 getDefaultInputConsumer( 610 gestureState.displayId, 611 userUnlocked, 612 taskAnimationManager, 613 taskbarManager, 614 reasonString.append( 615 if (launcherChildActivityResumed) 616 "%sis launcher child-task, trying to use default input consumer" 617 else "%sis gesture-blocked task, trying to use default input consumer", 618 SUBSTRING_PREFIX, 619 ), 620 ) 621 } else { 622 reasonString.append("%susing OtherActivityInputConsumer", SUBSTRING_PREFIX) 623 createOtherActivityInputConsumer<S, T>( 624 context, 625 swipeUpHandlerFactory, 626 overviewComponentObserver, 627 deviceState, 628 taskAnimationManager, 629 inputMonitorCompat, 630 onCompleteCallback, 631 inputEventReceiver, 632 gestureState, 633 event, 634 ) 635 } 636 } 637 createDeviceLockedInputConsumernull638 private fun createDeviceLockedInputConsumer( 639 context: Context, 640 userUnlocked: Boolean, 641 taskbarManager: TaskbarManager, 642 deviceState: RecentsAnimationDeviceState, 643 gestureState: GestureState, 644 taskAnimationManager: TaskAnimationManager, 645 inputMonitorCompat: InputMonitorCompat, 646 reasonString: CompoundString, 647 ): InputConsumer { 648 return if ( 649 (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture) && 650 gestureState.runningTask != null 651 ) { 652 reasonString.append( 653 "%sdevice is in gesture nav mode or 3-button mode with a trackpad " + 654 "gesture and running task != null, using DeviceLockedInputConsumer", 655 SUBSTRING_PREFIX, 656 ) 657 DeviceLockedInputConsumer( 658 context, 659 deviceState, 660 taskAnimationManager, 661 gestureState, 662 inputMonitorCompat, 663 ) 664 } else { 665 getDefaultInputConsumer( 666 gestureState.displayId, 667 userUnlocked, 668 taskAnimationManager, 669 taskbarManager, 670 reasonString.append( 671 if (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture) 672 "%srunning task == null, trying to use default input consumer" 673 else 674 ("%sdevice is not in gesture nav mode and it's not a trackpad gesture," + 675 " trying to use default input consumer"), 676 SUBSTRING_PREFIX, 677 ), 678 ) 679 } 680 } 681 createOverviewInputConsumernull682 private fun <S : BaseState<S>, T> createOverviewInputConsumer( 683 userUnlocked: Boolean, 684 taskAnimationManager: TaskAnimationManager, 685 taskbarManager: TaskbarManager, 686 deviceState: RecentsAnimationDeviceState, 687 inputMonitorCompat: InputMonitorCompat, 688 previousGestureState: GestureState, 689 gestureState: GestureState, 690 event: MotionEvent, 691 reasonString: CompoundString, 692 ): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> { 693 val container: T = 694 gestureState.getContainerInterface<S, T>().getCreatedContainer() 695 ?: return getDefaultInputConsumer( 696 gestureState.displayId, 697 userUnlocked, 698 taskAnimationManager, 699 taskbarManager, 700 reasonString.append( 701 "%sactivity == null, trying to use default input consumer", 702 SUBSTRING_PREFIX, 703 ), 704 ) 705 706 val rootView = container.rootView 707 val hasWindowFocus = rootView?.hasWindowFocus() ?: false 708 val isPreviousGestureAnimatingToLauncher = 709 (previousGestureState.isRunningAnimationToLauncher || 710 deviceState.isPredictiveBackToHomeInProgress) 711 val isInLiveTileMode: Boolean = 712 gestureState.getContainerInterface<S, T>().isInLiveTileMode() 713 714 reasonString.append( 715 if (hasWindowFocus) "%sactivity has window focus" 716 else 717 (if (isPreviousGestureAnimatingToLauncher) 718 "%sprevious gesture is still animating to launcher" 719 else if (isInLiveTileMode) "%sdevice is in live mode" 720 else "%sall overview focus conditions failed"), 721 SUBSTRING_PREFIX, 722 ) 723 return if (hasWindowFocus || isPreviousGestureAnimatingToLauncher || isInLiveTileMode) { 724 reasonString.append( 725 "%soverview should have focus, using OverviewInputConsumer", 726 SUBSTRING_PREFIX, 727 ) 728 OverviewInputConsumer( 729 gestureState, 730 container, 731 inputMonitorCompat, 732 /* startingInActivityBounds= */ false, 733 ) 734 } else { 735 reasonString.append( 736 "%soverview shouldn't have focus, using OverviewWithoutFocusInputConsumer", 737 SUBSTRING_PREFIX, 738 ) 739 val disableHorizontalSwipe = deviceState.isInExclusionRegion(event) 740 OverviewWithoutFocusInputConsumer( 741 container.asContext(), 742 deviceState, 743 gestureState, 744 inputMonitorCompat, 745 disableHorizontalSwipe, 746 ) 747 } 748 } 749 750 /** Returns the [ResetGestureInputConsumer] if user is unlocked, else NO_OP. */ 751 @JvmStatic getDefaultInputConsumernull752 fun getDefaultInputConsumer( 753 displayId: Int, 754 userUnlocked: Boolean, 755 taskAnimationManager: TaskAnimationManager?, 756 taskbarManager: TaskbarManager?, 757 reasonString: CompoundString, 758 ): InputConsumer { 759 return if (userUnlocked && taskAnimationManager != null && taskbarManager != null) { 760 reasonString.append( 761 "%sResetGestureInputConsumer available, using ResetGestureInputConsumer", 762 SUBSTRING_PREFIX, 763 ) 764 ResetGestureInputConsumer(displayId, taskAnimationManager) { 765 taskbarManager.getTaskbarForDisplay(displayId) 766 } 767 } else { 768 reasonString.append( 769 "%s${ 770 if (userUnlocked) "user is locked" 771 else if (taskAnimationManager == null) "taskAnimationManager is null" 772 else "taskbarManager is null" 773 }, using no-op input consumer", 774 SUBSTRING_PREFIX, 775 ) 776 // ResetGestureInputConsumer isn't available until onUserUnlocked(), so reset to 777 // NO_OP until then (we never want these to be null). 778 InputConsumer.createNoOpInputConsumer(displayId) 779 } 780 } 781 createOtherActivityInputConsumernull782 private fun <S : BaseState<S>, T> createOtherActivityInputConsumer( 783 context: Context, 784 swipeUpHandlerFactory: AbsSwipeUpHandler.Factory, 785 overviewComponentObserver: OverviewComponentObserver, 786 deviceState: RecentsAnimationDeviceState, 787 taskAnimationManager: TaskAnimationManager, 788 inputMonitorCompat: InputMonitorCompat, 789 onCompleteCallback: Consumer<OtherActivityInputConsumer>, 790 inputEventReceiver: InputChannelCompat.InputEventReceiver, 791 gestureState: GestureState, 792 event: MotionEvent, 793 ): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> { 794 val shouldDefer = 795 (!overviewComponentObserver.isHomeAndOverviewSame || 796 gestureState 797 .getContainerInterface<S, T>() 798 .deferStartingActivity(deviceState, event)) 799 val disableHorizontalSwipe = deviceState.isInExclusionRegion(event) 800 return OtherActivityInputConsumer( 801 /* base= */ context, 802 deviceState, 803 taskAnimationManager, 804 gestureState, 805 /* isDeferredDownTarget= */ shouldDefer, 806 onCompleteCallback, 807 inputMonitorCompat, 808 inputEventReceiver, 809 disableHorizontalSwipe, 810 swipeUpHandlerFactory, 811 ) 812 } 813 newCompoundStringnull814 private fun newCompoundString(substring: String): CompoundString { 815 return CompoundString("%s%s", NEWLINE_PREFIX, substring) 816 } 817 logInputConsumerSelectionReasonnull818 private fun logInputConsumerSelectionReason( 819 consumer: InputConsumer, 820 reasonString: CompoundString, 821 ) { 822 ActiveGestureProtoLogProxy.logSetInputConsumer(consumer.name, reasonString.toString()) 823 if ((consumer.type and InputConsumer.TYPE_OTHER_ACTIVITY) != 0) { 824 ActiveGestureLog.INSTANCE.trackEvent( 825 ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER 826 ) 827 } 828 } 829 ignoreThreeFingerTrackpadForNavHandleLongPressnull830 private fun ignoreThreeFingerTrackpadForNavHandleLongPress( 831 gestureState: GestureState 832 ): Boolean { 833 return (com.android.launcher3.Flags.ignoreThreeFingerTrackpadForNavHandleLongPress() && 834 gestureState.isThreeFingerTrackpadGesture) 835 } 836 handleOrientationSetupnull837 private fun handleOrientationSetup(baseInputConsumer: InputConsumer) { 838 baseInputConsumer.notifyOrientationSetup() 839 } 840 } 841