Refactor InputConsumer selection logic into a util class
This will allow us to test the logic in isolation Flag: EXEMPT refactor Bug: 371020209 Test: NONE refactor Change-Id: I5e1e9cc79e69db261ea28a2f7d43a983339f178b
This commit is contained in:
@@ -274,7 +274,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
|
||||
* @return the interface to the activity handing the UI updates for this gesture.
|
||||
*/
|
||||
public <S extends BaseState<S>, T extends RecentsViewContainer & StatefulContainer<S>>
|
||||
BaseContainerInterface getContainerInterface() {
|
||||
BaseContainerInterface<S, T> getContainerInterface() {
|
||||
return mContainerInterface;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,746 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep
|
||||
|
||||
import android.content.Context
|
||||
import android.view.MotionEvent
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.launcher3.anim.AnimatedFloat
|
||||
import com.android.launcher3.statemanager.BaseState
|
||||
import com.android.launcher3.statemanager.StatefulContainer
|
||||
import com.android.launcher3.taskbar.TaskbarManager
|
||||
import com.android.launcher3.util.LockedUserState.Companion.get
|
||||
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer
|
||||
import com.android.quickstep.inputconsumers.AssistantInputConsumer
|
||||
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer
|
||||
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer
|
||||
import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer
|
||||
import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer
|
||||
import com.android.quickstep.inputconsumers.OtherActivityInputConsumer
|
||||
import com.android.quickstep.inputconsumers.OverviewInputConsumer
|
||||
import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer
|
||||
import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer
|
||||
import com.android.quickstep.inputconsumers.ResetGestureInputConsumer
|
||||
import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer
|
||||
import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer
|
||||
import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer
|
||||
import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer
|
||||
import com.android.quickstep.util.ActiveGestureErrorDetector
|
||||
import com.android.quickstep.util.ActiveGestureLog
|
||||
import com.android.quickstep.util.ActiveGestureLog.CompoundString
|
||||
import com.android.quickstep.util.ActiveGestureProtoLogProxy
|
||||
import com.android.quickstep.views.RecentsViewContainer
|
||||
import com.android.systemui.shared.system.InputChannelCompat
|
||||
import com.android.systemui.shared.system.InputMonitorCompat
|
||||
import com.android.wm.shell.Flags
|
||||
import java.util.function.Consumer
|
||||
import java.util.function.Function
|
||||
|
||||
/** Utility class for creating input consumers. */
|
||||
object InputConsumerUtils {
|
||||
private const val SUBSTRING_PREFIX = "; "
|
||||
private const val NEWLINE_PREFIX = "\n\t\t\t-> "
|
||||
|
||||
@JvmStatic
|
||||
fun <S : BaseState<S>, T> newConsumer(
|
||||
baseContext: Context,
|
||||
tisContext: Context,
|
||||
resetGestureInputConsumer: ResetGestureInputConsumer?,
|
||||
overviewComponentObserver: OverviewComponentObserver,
|
||||
deviceState: RecentsAnimationDeviceState,
|
||||
previousGestureState: GestureState,
|
||||
gestureState: GestureState,
|
||||
taskAnimationManager: TaskAnimationManager,
|
||||
inputMonitorCompat: InputMonitorCompat,
|
||||
swipeUpHandlerFactory: AbsSwipeUpHandler.Factory,
|
||||
onCompleteCallback: Consumer<OtherActivityInputConsumer>,
|
||||
inputEventReceiver: InputChannelCompat.InputEventReceiver,
|
||||
taskbarManager: TaskbarManager,
|
||||
swipeUpProxyProvider: Function<GestureState?, AnimatedFloat?>,
|
||||
overviewCommandHelper: OverviewCommandHelper,
|
||||
event: MotionEvent,
|
||||
): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> {
|
||||
val tac = taskbarManager.currentActivityContext
|
||||
val bubbleControllers = tac?.bubbleControllers
|
||||
if (bubbleControllers != null && BubbleBarInputConsumer.isEventOnBubbles(tac, event)) {
|
||||
val consumer: InputConsumer =
|
||||
BubbleBarInputConsumer(tisContext, bubbleControllers, inputMonitorCompat)
|
||||
logInputConsumerSelectionReason(
|
||||
consumer,
|
||||
newCompoundString("event is on bubbles, creating new input consumer"),
|
||||
)
|
||||
return consumer
|
||||
}
|
||||
val progressProxy = swipeUpProxyProvider.apply(gestureState)
|
||||
if (progressProxy != null) {
|
||||
val consumer: InputConsumer =
|
||||
ProgressDelegateInputConsumer(
|
||||
tisContext,
|
||||
taskAnimationManager,
|
||||
gestureState,
|
||||
inputMonitorCompat,
|
||||
progressProxy,
|
||||
)
|
||||
|
||||
logInputConsumerSelectionReason(
|
||||
consumer,
|
||||
newCompoundString(
|
||||
"mSwipeUpProxyProvider has been set, using ProgressDelegateInputConsumer"
|
||||
),
|
||||
)
|
||||
|
||||
return consumer
|
||||
}
|
||||
|
||||
val canStartSystemGesture =
|
||||
if (gestureState.isTrackpadGesture) deviceState.canStartTrackpadGesture()
|
||||
else deviceState.canStartSystemGesture()
|
||||
|
||||
if (!get(tisContext).isUserUnlocked) {
|
||||
val reasonString = newCompoundString("device locked")
|
||||
val consumer =
|
||||
if (canStartSystemGesture) {
|
||||
// This handles apps launched in direct boot mode (e.g. dialer) as well as apps
|
||||
// launched while device is locked even after exiting direct boot mode (e.g.
|
||||
// camera).
|
||||
createDeviceLockedInputConsumer(
|
||||
tisContext,
|
||||
resetGestureInputConsumer,
|
||||
deviceState,
|
||||
gestureState,
|
||||
taskAnimationManager,
|
||||
inputMonitorCompat,
|
||||
reasonString.append("%scan start system gesture", SUBSTRING_PREFIX),
|
||||
)
|
||||
} else {
|
||||
getDefaultInputConsumer(
|
||||
resetGestureInputConsumer,
|
||||
reasonString.append("%scannot start system gesture", SUBSTRING_PREFIX),
|
||||
)
|
||||
}
|
||||
logInputConsumerSelectionReason(consumer, reasonString)
|
||||
return consumer
|
||||
}
|
||||
|
||||
var reasonString: CompoundString
|
||||
var base: InputConsumer
|
||||
// When there is an existing recents animation running, bypass systemState check as this is
|
||||
// a followup gesture and the first gesture started in a valid system state.
|
||||
if (canStartSystemGesture || previousGestureState.isRecentsAnimationRunning) {
|
||||
reasonString =
|
||||
newCompoundString(
|
||||
if (canStartSystemGesture)
|
||||
"can start system gesture, trying to use base consumer"
|
||||
else "recents animation was running, trying to use base consumer"
|
||||
)
|
||||
base =
|
||||
newBaseConsumer<S, T>(
|
||||
tisContext,
|
||||
resetGestureInputConsumer,
|
||||
overviewComponentObserver,
|
||||
deviceState,
|
||||
previousGestureState,
|
||||
gestureState,
|
||||
taskAnimationManager,
|
||||
inputMonitorCompat,
|
||||
swipeUpHandlerFactory,
|
||||
onCompleteCallback,
|
||||
inputEventReceiver,
|
||||
event,
|
||||
reasonString,
|
||||
)
|
||||
} else {
|
||||
reasonString =
|
||||
newCompoundString(
|
||||
"cannot start system gesture and recents " +
|
||||
"animation was not running, trying to use default input consumer"
|
||||
)
|
||||
base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
|
||||
}
|
||||
if (deviceState.isGesturalNavMode || gestureState.isTrackpadGesture) {
|
||||
handleOrientationSetup(base)
|
||||
}
|
||||
if (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture) {
|
||||
val reasonPrefix =
|
||||
"device is in gesture navigation mode or 3-button mode with a trackpad gesture"
|
||||
if (deviceState.canTriggerAssistantAction(event)) {
|
||||
reasonString.append(
|
||||
"%s%s%sgesture can trigger the assistant, " +
|
||||
"trying to use assistant input consumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
base =
|
||||
tryCreateAssistantInputConsumer(
|
||||
tisContext,
|
||||
deviceState,
|
||||
inputMonitorCompat,
|
||||
base,
|
||||
gestureState,
|
||||
event,
|
||||
reasonString,
|
||||
)
|
||||
}
|
||||
|
||||
// If Taskbar is present, we listen for swipe or cursor hover events to unstash it.
|
||||
if (tac != null && base !is AssistantInputConsumer) {
|
||||
// Present always on large screen or on small screen w/ flag
|
||||
val useTaskbarConsumer =
|
||||
(tac.deviceProfile.isTaskbarPresent &&
|
||||
!tac.isPhoneMode &&
|
||||
!tac.isInStashedLauncherState)
|
||||
if (canStartSystemGesture && useTaskbarConsumer) {
|
||||
reasonString.append(
|
||||
"%s%s%sTaskbarActivityContext != null, " +
|
||||
"using TaskbarUnstashInputConsumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
base =
|
||||
TaskbarUnstashInputConsumer(
|
||||
tisContext,
|
||||
base,
|
||||
inputMonitorCompat,
|
||||
tac,
|
||||
overviewCommandHelper,
|
||||
gestureState,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (Flags.enableBubblesLongPressNavHandle()) {
|
||||
// Create bubbles input consumer before NavHandleLongPressInputConsumer.
|
||||
// This allows for nav handle to fall back to bubbles.
|
||||
if (deviceState.isBubblesExpanded) {
|
||||
reasonString =
|
||||
newCompoundString(reasonPrefix)
|
||||
.append(
|
||||
"%sbubbles expanded, trying to use default input consumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
// Bubbles can handle home gesture itself.
|
||||
base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
|
||||
}
|
||||
}
|
||||
|
||||
val navHandle = tac?.navHandle ?: SystemUiProxy.INSTANCE[tisContext]
|
||||
if (
|
||||
canStartSystemGesture &&
|
||||
!previousGestureState.isRecentsAnimationRunning &&
|
||||
navHandle.canNavHandleBeLongPressed() &&
|
||||
!ignoreThreeFingerTrackpadForNavHandleLongPress(gestureState)
|
||||
) {
|
||||
reasonString.append(
|
||||
"%s%s%sNot running recents animation, ",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
if (tac != null && tac.navHandle.canNavHandleBeLongPressed()) {
|
||||
reasonString.append("stashed handle is long-pressable, ")
|
||||
}
|
||||
reasonString.append("using NavHandleLongPressInputConsumer")
|
||||
base =
|
||||
NavHandleLongPressInputConsumer(
|
||||
tisContext,
|
||||
base,
|
||||
inputMonitorCompat,
|
||||
deviceState,
|
||||
navHandle,
|
||||
gestureState,
|
||||
)
|
||||
}
|
||||
|
||||
if (!Flags.enableBubblesLongPressNavHandle()) {
|
||||
// Continue overriding nav handle input consumer with bubbles
|
||||
if (deviceState.isBubblesExpanded) {
|
||||
reasonString =
|
||||
newCompoundString(reasonPrefix)
|
||||
.append(
|
||||
"%sbubbles expanded, trying to use default input consumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
// Bubbles can handle home gesture itself.
|
||||
base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceState.isSystemUiDialogShowing) {
|
||||
reasonString =
|
||||
newCompoundString(reasonPrefix)
|
||||
.append(
|
||||
"%ssystem dialog is showing, using SysUiOverlayInputConsumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
base = SysUiOverlayInputConsumer(baseContext, deviceState, inputMonitorCompat)
|
||||
}
|
||||
|
||||
if (
|
||||
gestureState.isTrackpadGesture &&
|
||||
canStartSystemGesture &&
|
||||
!previousGestureState.isRecentsAnimationRunning
|
||||
) {
|
||||
reasonString =
|
||||
newCompoundString(reasonPrefix)
|
||||
.append(
|
||||
"%sTrackpad 3-finger gesture, using TrackpadStatusBarInputConsumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
base = TrackpadStatusBarInputConsumer(baseContext, base, inputMonitorCompat)
|
||||
}
|
||||
|
||||
if (deviceState.isScreenPinningActive) {
|
||||
reasonString =
|
||||
newCompoundString(reasonPrefix)
|
||||
.append(
|
||||
"%sscreen pinning is active, using ScreenPinnedInputConsumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
// Note: we only allow accessibility to wrap this, and it replaces the previous
|
||||
// base input consumer (which should be NO_OP anyway since topTaskLocked == true).
|
||||
base = ScreenPinnedInputConsumer(tisContext, gestureState)
|
||||
}
|
||||
|
||||
if (deviceState.canTriggerOneHandedAction(event)) {
|
||||
reasonString.append(
|
||||
"%s%s%sgesture can trigger one handed mode, " +
|
||||
"using OneHandedModeInputConsumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
base = OneHandedModeInputConsumer(tisContext, deviceState, base, inputMonitorCompat)
|
||||
}
|
||||
|
||||
if (deviceState.isAccessibilityMenuAvailable) {
|
||||
reasonString.append(
|
||||
"%s%s%saccessibility menu is available, using AccessibilityInputConsumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
base =
|
||||
AccessibilityInputConsumer(
|
||||
tisContext,
|
||||
deviceState,
|
||||
gestureState,
|
||||
base,
|
||||
inputMonitorCompat,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val reasonPrefix = "device is not in gesture navigation mode"
|
||||
if (deviceState.isScreenPinningActive) {
|
||||
reasonString =
|
||||
newCompoundString(reasonPrefix)
|
||||
.append(
|
||||
"%sscreen pinning is active, trying to use default input consumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
base = getDefaultInputConsumer(resetGestureInputConsumer, reasonString)
|
||||
}
|
||||
|
||||
if (deviceState.canTriggerOneHandedAction(event)) {
|
||||
reasonString.append(
|
||||
"%s%s%sgesture can trigger one handed mode, " +
|
||||
"using OneHandedModeInputConsumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
base = OneHandedModeInputConsumer(tisContext, deviceState, base, inputMonitorCompat)
|
||||
}
|
||||
}
|
||||
logInputConsumerSelectionReason(base, reasonString)
|
||||
return base
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun tryCreateAssistantInputConsumer(
|
||||
context: Context,
|
||||
deviceState: RecentsAnimationDeviceState,
|
||||
inputMonitorCompat: InputMonitorCompat,
|
||||
gestureState: GestureState,
|
||||
motionEvent: MotionEvent,
|
||||
): InputConsumer {
|
||||
return tryCreateAssistantInputConsumer(
|
||||
context,
|
||||
deviceState,
|
||||
inputMonitorCompat,
|
||||
InputConsumer.NO_OP,
|
||||
gestureState,
|
||||
motionEvent,
|
||||
CompoundString.NO_OP,
|
||||
)
|
||||
}
|
||||
|
||||
private fun tryCreateAssistantInputConsumer(
|
||||
context: Context,
|
||||
deviceState: RecentsAnimationDeviceState,
|
||||
inputMonitorCompat: InputMonitorCompat,
|
||||
base: InputConsumer,
|
||||
gestureState: GestureState,
|
||||
motionEvent: MotionEvent,
|
||||
reasonString: CompoundString,
|
||||
): InputConsumer {
|
||||
return if (deviceState.isGestureBlockedTask(gestureState.runningTask)) {
|
||||
reasonString.append(
|
||||
"%sis gesture-blocked task, using base input consumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
base
|
||||
} else {
|
||||
reasonString.append("%susing AssistantInputConsumer", SUBSTRING_PREFIX)
|
||||
AssistantInputConsumer(
|
||||
context,
|
||||
gestureState,
|
||||
base,
|
||||
inputMonitorCompat,
|
||||
deviceState,
|
||||
motionEvent,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@JvmStatic
|
||||
fun <S : BaseState<S>, T> newBaseConsumer(
|
||||
context: Context,
|
||||
resetGestureInputConsumer: ResetGestureInputConsumer?,
|
||||
overviewComponentObserver: OverviewComponentObserver,
|
||||
deviceState: RecentsAnimationDeviceState,
|
||||
previousGestureState: GestureState,
|
||||
gestureState: GestureState,
|
||||
taskAnimationManager: TaskAnimationManager,
|
||||
inputMonitorCompat: InputMonitorCompat,
|
||||
swipeUpHandlerFactory: AbsSwipeUpHandler.Factory,
|
||||
onCompleteCallback: Consumer<OtherActivityInputConsumer>,
|
||||
inputEventReceiver: InputChannelCompat.InputEventReceiver,
|
||||
event: MotionEvent,
|
||||
reasonString: CompoundString,
|
||||
): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> {
|
||||
if (deviceState.isKeyguardShowingOccluded) {
|
||||
// This handles apps showing over the lockscreen (e.g. camera)
|
||||
return createDeviceLockedInputConsumer(
|
||||
context,
|
||||
resetGestureInputConsumer,
|
||||
deviceState,
|
||||
gestureState,
|
||||
taskAnimationManager,
|
||||
inputMonitorCompat,
|
||||
reasonString.append(
|
||||
"%skeyguard is showing occluded, " +
|
||||
"trying to use device locked input consumer",
|
||||
SUBSTRING_PREFIX,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
reasonString.append("%skeyguard is not showing occluded", SUBSTRING_PREFIX)
|
||||
|
||||
val runningTask = gestureState.runningTask
|
||||
// Use overview input consumer for sharesheets on top of home.
|
||||
val forceOverviewInputConsumer =
|
||||
gestureState.getContainerInterface<S, T>().isStarted() &&
|
||||
runningTask != null &&
|
||||
runningTask.isRootChooseActivity
|
||||
|
||||
if (!Flags.enableShellTopTaskTracking()) {
|
||||
// In the case where we are in an excluded, translucent overlay, ignore it and treat the
|
||||
// running activity as the task behind the overlay.
|
||||
val otherVisibleTask = runningTask?.visibleNonExcludedTask
|
||||
if (otherVisibleTask != null) {
|
||||
ActiveGestureProtoLogProxy.logUpdateGestureStateRunningTask(
|
||||
otherVisibleTask.packageName ?: "MISSING",
|
||||
runningTask.packageName ?: "MISSING",
|
||||
)
|
||||
gestureState.updateRunningTask(otherVisibleTask)
|
||||
}
|
||||
}
|
||||
|
||||
val previousGestureAnimatedToLauncher =
|
||||
(previousGestureState.isRunningAnimationToLauncher ||
|
||||
deviceState.isPredictiveBackToHomeInProgress)
|
||||
// with shell-transitions, home is resumed during recents animation, so
|
||||
// explicitly check against recents animation too.
|
||||
val launcherResumedThroughShellTransition =
|
||||
(gestureState.getContainerInterface<S, T>().isResumed() &&
|
||||
!previousGestureState.isRecentsAnimationRunning)
|
||||
// If a task fragment within Launcher is resumed
|
||||
val launcherChildActivityResumed =
|
||||
(com.android.launcher3.Flags.useActivityOverlay() &&
|
||||
runningTask != null &&
|
||||
runningTask.isHomeTask &&
|
||||
overviewComponentObserver.isHomeAndOverviewSame &&
|
||||
!launcherResumedThroughShellTransition &&
|
||||
!previousGestureState.isRecentsAnimationRunning)
|
||||
|
||||
return if (gestureState.getContainerInterface<S, T>().isInLiveTileMode()) {
|
||||
createOverviewInputConsumer<S, T>(
|
||||
resetGestureInputConsumer,
|
||||
deviceState,
|
||||
inputMonitorCompat,
|
||||
previousGestureState,
|
||||
gestureState,
|
||||
event,
|
||||
reasonString.append(
|
||||
"%sis in live tile mode, trying to use overview input consumer",
|
||||
SUBSTRING_PREFIX,
|
||||
),
|
||||
)
|
||||
} else if (runningTask == null) {
|
||||
getDefaultInputConsumer(
|
||||
resetGestureInputConsumer,
|
||||
reasonString.append("%srunning task == null", SUBSTRING_PREFIX),
|
||||
)
|
||||
} else if (
|
||||
previousGestureAnimatedToLauncher ||
|
||||
launcherResumedThroughShellTransition ||
|
||||
forceOverviewInputConsumer
|
||||
) {
|
||||
createOverviewInputConsumer<S, T>(
|
||||
resetGestureInputConsumer,
|
||||
deviceState,
|
||||
inputMonitorCompat,
|
||||
previousGestureState,
|
||||
gestureState,
|
||||
event,
|
||||
reasonString.append(
|
||||
if (previousGestureAnimatedToLauncher)
|
||||
("%sprevious gesture animated to launcher, " +
|
||||
"trying to use overview input consumer")
|
||||
else
|
||||
(if (launcherResumedThroughShellTransition)
|
||||
("%slauncher resumed through a shell transition, " +
|
||||
"trying to use overview input consumer")
|
||||
else
|
||||
("%sforceOverviewInputConsumer == true, " +
|
||||
"trying to use overview input consumer")),
|
||||
SUBSTRING_PREFIX,
|
||||
),
|
||||
)
|
||||
} else if (deviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) {
|
||||
getDefaultInputConsumer(
|
||||
resetGestureInputConsumer,
|
||||
reasonString.append(
|
||||
if (launcherChildActivityResumed)
|
||||
"%sis launcher child-task, trying to use default input consumer"
|
||||
else "%sis gesture-blocked task, trying to use default input consumer",
|
||||
SUBSTRING_PREFIX,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
reasonString.append("%susing OtherActivityInputConsumer", SUBSTRING_PREFIX)
|
||||
createOtherActivityInputConsumer<S, T>(
|
||||
context,
|
||||
swipeUpHandlerFactory,
|
||||
overviewComponentObserver,
|
||||
deviceState,
|
||||
taskAnimationManager,
|
||||
inputMonitorCompat,
|
||||
onCompleteCallback,
|
||||
inputEventReceiver,
|
||||
gestureState,
|
||||
event,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDeviceLockedInputConsumer(
|
||||
context: Context,
|
||||
resetGestureInputConsumer: ResetGestureInputConsumer?,
|
||||
deviceState: RecentsAnimationDeviceState,
|
||||
gestureState: GestureState,
|
||||
taskAnimationManager: TaskAnimationManager,
|
||||
inputMonitorCompat: InputMonitorCompat,
|
||||
reasonString: CompoundString,
|
||||
): InputConsumer {
|
||||
return if (
|
||||
(deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture) &&
|
||||
gestureState.runningTask != null
|
||||
) {
|
||||
reasonString.append(
|
||||
"%sdevice is in gesture nav mode or 3-button mode with a trackpad " +
|
||||
"gesture and running task != null, using DeviceLockedInputConsumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
DeviceLockedInputConsumer(
|
||||
context,
|
||||
deviceState,
|
||||
taskAnimationManager,
|
||||
gestureState,
|
||||
inputMonitorCompat,
|
||||
)
|
||||
} else {
|
||||
getDefaultInputConsumer(
|
||||
resetGestureInputConsumer,
|
||||
reasonString.append(
|
||||
if (deviceState.isFullyGesturalNavMode || gestureState.isTrackpadGesture)
|
||||
"%srunning task == null, trying to use default input consumer"
|
||||
else
|
||||
("%sdevice is not in gesture nav mode and it's not a trackpad gesture," +
|
||||
" trying to use default input consumer"),
|
||||
SUBSTRING_PREFIX,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <S : BaseState<S>, T> createOverviewInputConsumer(
|
||||
resetGestureInputConsumer: ResetGestureInputConsumer?,
|
||||
deviceState: RecentsAnimationDeviceState,
|
||||
inputMonitorCompat: InputMonitorCompat,
|
||||
previousGestureState: GestureState,
|
||||
gestureState: GestureState,
|
||||
event: MotionEvent,
|
||||
reasonString: CompoundString,
|
||||
): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> {
|
||||
val container: T =
|
||||
gestureState.getContainerInterface<S, T>().getCreatedContainer()
|
||||
?: return getDefaultInputConsumer(
|
||||
resetGestureInputConsumer,
|
||||
reasonString.append(
|
||||
"%sactivity == null, trying to use default input consumer",
|
||||
SUBSTRING_PREFIX,
|
||||
),
|
||||
)
|
||||
|
||||
val rootView = container.rootView
|
||||
val hasWindowFocus = rootView?.hasWindowFocus() ?: false
|
||||
val isPreviousGestureAnimatingToLauncher =
|
||||
(previousGestureState.isRunningAnimationToLauncher ||
|
||||
deviceState.isPredictiveBackToHomeInProgress)
|
||||
val isInLiveTileMode: Boolean =
|
||||
gestureState.getContainerInterface<S, T>().isInLiveTileMode()
|
||||
|
||||
reasonString.append(
|
||||
if (hasWindowFocus) "%sactivity has window focus"
|
||||
else
|
||||
(if (isPreviousGestureAnimatingToLauncher)
|
||||
"%sprevious gesture is still animating to launcher"
|
||||
else if (isInLiveTileMode) "%sdevice is in live mode"
|
||||
else "%sall overview focus conditions failed"),
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
return if (hasWindowFocus || isPreviousGestureAnimatingToLauncher || isInLiveTileMode) {
|
||||
reasonString.append(
|
||||
"%soverview should have focus, using OverviewInputConsumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
OverviewInputConsumer(
|
||||
gestureState,
|
||||
container,
|
||||
inputMonitorCompat,
|
||||
/* startingInActivityBounds= */ false,
|
||||
)
|
||||
} else {
|
||||
reasonString.append(
|
||||
"%soverview shouldn't have focus, using OverviewWithoutFocusInputConsumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
val disableHorizontalSwipe = deviceState.isInExclusionRegion(event)
|
||||
OverviewWithoutFocusInputConsumer(
|
||||
container.asContext(),
|
||||
deviceState,
|
||||
gestureState,
|
||||
inputMonitorCompat,
|
||||
disableHorizontalSwipe,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the [ResetGestureInputConsumer] if user is unlocked, else NO_OP. */
|
||||
private fun getDefaultInputConsumer(
|
||||
resetGestureInputConsumer: ResetGestureInputConsumer?,
|
||||
reasonString: CompoundString,
|
||||
): InputConsumer {
|
||||
return if (resetGestureInputConsumer != null) {
|
||||
reasonString.append(
|
||||
"%smResetGestureInputConsumer initialized, using ResetGestureInputConsumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
resetGestureInputConsumer
|
||||
} else {
|
||||
reasonString.append(
|
||||
"%smResetGestureInputConsumer not initialized, using no-op input consumer",
|
||||
SUBSTRING_PREFIX,
|
||||
)
|
||||
// mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to
|
||||
// NO_OP until then (we never want these to be null).
|
||||
InputConsumer.NO_OP
|
||||
}
|
||||
}
|
||||
|
||||
private fun <S : BaseState<S>, T> createOtherActivityInputConsumer(
|
||||
context: Context,
|
||||
swipeUpHandlerFactory: AbsSwipeUpHandler.Factory,
|
||||
overviewComponentObserver: OverviewComponentObserver,
|
||||
deviceState: RecentsAnimationDeviceState,
|
||||
taskAnimationManager: TaskAnimationManager,
|
||||
inputMonitorCompat: InputMonitorCompat,
|
||||
onCompleteCallback: Consumer<OtherActivityInputConsumer>,
|
||||
inputEventReceiver: InputChannelCompat.InputEventReceiver,
|
||||
gestureState: GestureState,
|
||||
event: MotionEvent,
|
||||
): InputConsumer where T : RecentsViewContainer, T : StatefulContainer<S> {
|
||||
val shouldDefer =
|
||||
(!overviewComponentObserver.isHomeAndOverviewSame ||
|
||||
gestureState
|
||||
.getContainerInterface<S, T>()
|
||||
.deferStartingActivity(deviceState, event))
|
||||
val disableHorizontalSwipe = deviceState.isInExclusionRegion(event)
|
||||
return OtherActivityInputConsumer(
|
||||
/* base= */ context,
|
||||
deviceState,
|
||||
taskAnimationManager,
|
||||
gestureState,
|
||||
/* isDeferredDownTarget= */ shouldDefer,
|
||||
onCompleteCallback,
|
||||
inputMonitorCompat,
|
||||
inputEventReceiver,
|
||||
disableHorizontalSwipe,
|
||||
swipeUpHandlerFactory,
|
||||
)
|
||||
}
|
||||
|
||||
private fun newCompoundString(substring: String): CompoundString {
|
||||
return CompoundString("%s%s", NEWLINE_PREFIX, substring)
|
||||
}
|
||||
|
||||
private fun logInputConsumerSelectionReason(
|
||||
consumer: InputConsumer,
|
||||
reasonString: CompoundString,
|
||||
) {
|
||||
ActiveGestureProtoLogProxy.logSetInputConsumer(consumer.name, reasonString.toString())
|
||||
if ((consumer.type and InputConsumer.TYPE_OTHER_ACTIVITY) != 0) {
|
||||
ActiveGestureLog.INSTANCE.trackEvent(
|
||||
ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ignoreThreeFingerTrackpadForNavHandleLongPress(
|
||||
gestureState: GestureState
|
||||
): Boolean {
|
||||
return (com.android.launcher3.Flags.ignoreThreeFingerTrackpadForNavHandleLongPress() &&
|
||||
gestureState.isThreeFingerTrackpadGesture)
|
||||
}
|
||||
|
||||
private fun handleOrientationSetup(baseInputConsumer: InputConsumer) {
|
||||
baseInputConsumer.notifyOrientationSetup()
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import static android.view.MotionEvent.ACTION_UP;
|
||||
|
||||
import static com.android.launcher3.Flags.enableCursorHoverStates;
|
||||
import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
|
||||
import static com.android.launcher3.Flags.useActivityOverlay;
|
||||
import static com.android.launcher3.LauncherPrefs.backedUpItem;
|
||||
import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
|
||||
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
|
||||
@@ -35,12 +34,12 @@ import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WI
|
||||
import static com.android.quickstep.GestureState.DEFAULT_STATE;
|
||||
import static com.android.quickstep.GestureState.TrackpadGestureType.getTrackpadGestureType;
|
||||
import static com.android.quickstep.InputConsumer.TYPE_CURSOR_HOVER;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER;
|
||||
import static com.android.quickstep.InputConsumerUtils.newConsumer;
|
||||
import static com.android.quickstep.InputConsumerUtils.tryCreateAssistantInputConsumer;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
|
||||
import static com.android.wm.shell.Flags.enableBubblesLongPressNavHandle;
|
||||
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
|
||||
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
|
||||
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
|
||||
@@ -71,7 +70,6 @@ import android.view.Choreographer;
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.BinderThread;
|
||||
import androidx.annotation.MainThread;
|
||||
@@ -106,21 +104,9 @@ import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.quickstep.OverviewCommandHelper.CommandType;
|
||||
import com.android.quickstep.fallback.window.RecentsWindowManager;
|
||||
import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler;
|
||||
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.AssistantInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.NavHandleLongPressInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.ActiveGestureLog.CompoundString;
|
||||
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
|
||||
@@ -959,7 +945,8 @@ public class TouchInteractionService extends Service {
|
||||
+ "consuming gesture for assistant action");
|
||||
mGestureState =
|
||||
createGestureState(mGestureState, getTrackpadGestureType(event));
|
||||
mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event);
|
||||
mUncheckedConsumer = tryCreateAssistantInputConsumer(
|
||||
this, mDeviceState, mInputMonitorCompat, mGestureState, event);
|
||||
} else {
|
||||
reasonString.append(" but event cannot trigger Assistant, "
|
||||
+ "consuming gesture as no-op");
|
||||
@@ -978,7 +965,23 @@ public class TouchInteractionService extends Service {
|
||||
getTrackpadGestureType(event));
|
||||
mConsumer.onConsumerAboutToBeSwitched();
|
||||
mGestureState = newGestureState;
|
||||
mConsumer = newConsumer(prevGestureState, mGestureState, event);
|
||||
mConsumer = newConsumer(
|
||||
getBaseContext(),
|
||||
this,
|
||||
mResetGestureInputConsumer,
|
||||
mOverviewComponentObserver,
|
||||
mDeviceState,
|
||||
prevGestureState,
|
||||
mGestureState,
|
||||
mTaskAnimationManager,
|
||||
mInputMonitorCompat,
|
||||
getSwipeUpHandlerFactory(),
|
||||
this::onConsumerInactive,
|
||||
mInputEventReceiver,
|
||||
mTaskbarManager,
|
||||
mSwipeUpProxyProvider,
|
||||
mOverviewCommandHelper,
|
||||
event);
|
||||
mUncheckedConsumer = mConsumer;
|
||||
} else if ((mDeviceState.isFullyGesturalNavMode() || isTrackpadMultiFingerSwipe(event))
|
||||
&& mDeviceState.canTriggerAssistantAction(event)) {
|
||||
@@ -991,7 +994,8 @@ public class TouchInteractionService extends Service {
|
||||
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
|
||||
// should not interrupt it. QuickSwitch assumes that interruption can only
|
||||
// happen if the next gesture is also quick switch.
|
||||
mUncheckedConsumer = tryCreateAssistantInputConsumer(mGestureState, event);
|
||||
mUncheckedConsumer = tryCreateAssistantInputConsumer(
|
||||
this, mDeviceState, mInputMonitorCompat, mGestureState, event);
|
||||
} else if (mDeviceState.canTriggerOneHandedAction(event)) {
|
||||
reasonString.append("event can trigger one-handed action, "
|
||||
+ "consuming gesture for one-handed action");
|
||||
@@ -1073,28 +1077,6 @@ public class TouchInteractionService extends Service {
|
||||
return event.isHoverEvent() && event.getSource() == InputDevice.SOURCE_MOUSE;
|
||||
}
|
||||
|
||||
private InputConsumer tryCreateAssistantInputConsumer(
|
||||
GestureState gestureState, MotionEvent motionEvent) {
|
||||
return tryCreateAssistantInputConsumer(
|
||||
InputConsumer.NO_OP, gestureState, motionEvent, CompoundString.NO_OP);
|
||||
}
|
||||
|
||||
private InputConsumer tryCreateAssistantInputConsumer(
|
||||
InputConsumer base,
|
||||
GestureState gestureState,
|
||||
MotionEvent motionEvent,
|
||||
CompoundString reasonString) {
|
||||
if (mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())) {
|
||||
reasonString.append(
|
||||
"%sis gesture-blocked task, using base input consumer", SUBSTRING_PREFIX);
|
||||
return base;
|
||||
} else {
|
||||
reasonString.append("%susing AssistantInputConsumer", SUBSTRING_PREFIX);
|
||||
return new AssistantInputConsumer(
|
||||
this, gestureState, base, mInputMonitorCompat, mDeviceState, motionEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public GestureState createGestureState(GestureState previousGestureState,
|
||||
GestureState.TrackpadGestureType trackpadGestureType) {
|
||||
final GestureState gestureState;
|
||||
@@ -1125,312 +1107,6 @@ public class TouchInteractionService extends Service {
|
||||
return gestureState;
|
||||
}
|
||||
|
||||
private InputConsumer newConsumer(
|
||||
GestureState previousGestureState, GestureState newGestureState, MotionEvent event) {
|
||||
TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
|
||||
BubbleControllers bubbleControllers = tac != null ? tac.getBubbleControllers() : null;
|
||||
if (bubbleControllers != null && BubbleBarInputConsumer.isEventOnBubbles(tac, event)) {
|
||||
InputConsumer consumer = new BubbleBarInputConsumer(this, bubbleControllers,
|
||||
mInputMonitorCompat);
|
||||
logInputConsumerSelectionReason(consumer, newCompoundString(
|
||||
"event is on bubbles, creating new input consumer"));
|
||||
return consumer;
|
||||
}
|
||||
AnimatedFloat progressProxy = mSwipeUpProxyProvider.apply(mGestureState);
|
||||
if (progressProxy != null) {
|
||||
InputConsumer consumer = new ProgressDelegateInputConsumer(
|
||||
this, mTaskAnimationManager, mGestureState, mInputMonitorCompat, progressProxy);
|
||||
|
||||
logInputConsumerSelectionReason(consumer, newCompoundString(
|
||||
"mSwipeUpProxyProvider has been set, using ProgressDelegateInputConsumer"));
|
||||
|
||||
return consumer;
|
||||
}
|
||||
|
||||
boolean canStartSystemGesture =
|
||||
mGestureState.isTrackpadGesture() ? mDeviceState.canStartTrackpadGesture()
|
||||
: mDeviceState.canStartSystemGesture();
|
||||
|
||||
if (!LockedUserState.get(this).isUserUnlocked()) {
|
||||
CompoundString reasonString = newCompoundString("device locked");
|
||||
InputConsumer consumer;
|
||||
if (canStartSystemGesture) {
|
||||
// This handles apps launched in direct boot mode (e.g. dialer) as well as apps
|
||||
// launched while device is locked even after exiting direct boot mode (e.g. camera).
|
||||
consumer = createDeviceLockedInputConsumer(
|
||||
newGestureState,
|
||||
reasonString.append("%scan start system gesture", SUBSTRING_PREFIX));
|
||||
} else {
|
||||
consumer = getDefaultInputConsumer(
|
||||
reasonString.append("%scannot start system gesture", SUBSTRING_PREFIX));
|
||||
}
|
||||
logInputConsumerSelectionReason(consumer, reasonString);
|
||||
return consumer;
|
||||
}
|
||||
|
||||
CompoundString reasonString;
|
||||
InputConsumer base;
|
||||
// When there is an existing recents animation running, bypass systemState check as this is
|
||||
// a followup gesture and the first gesture started in a valid system state.
|
||||
if (canStartSystemGesture || previousGestureState.isRecentsAnimationRunning()) {
|
||||
reasonString = newCompoundString(canStartSystemGesture
|
||||
? "can start system gesture, trying to use base consumer"
|
||||
: "recents animation was running, trying to use base consumer");
|
||||
base = newBaseConsumer(previousGestureState, newGestureState, event, reasonString);
|
||||
} else {
|
||||
reasonString = newCompoundString("cannot start system gesture and recents "
|
||||
+ "animation was not running, trying to use default input consumer");
|
||||
base = getDefaultInputConsumer(reasonString);
|
||||
}
|
||||
if (mDeviceState.isGesturalNavMode() || newGestureState.isTrackpadGesture()) {
|
||||
handleOrientationSetup(base);
|
||||
}
|
||||
if (mDeviceState.isFullyGesturalNavMode() || newGestureState.isTrackpadGesture()) {
|
||||
String reasonPrefix =
|
||||
"device is in gesture navigation mode or 3-button mode with a trackpad gesture";
|
||||
if (mDeviceState.canTriggerAssistantAction(event)) {
|
||||
reasonString.append("%s%s%sgesture can trigger the assistant, "
|
||||
+ "trying to use assistant input consumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX);
|
||||
base = tryCreateAssistantInputConsumer(base, newGestureState, event, reasonString);
|
||||
}
|
||||
|
||||
// If Taskbar is present, we listen for swipe or cursor hover events to unstash it.
|
||||
if (tac != null && !(base instanceof AssistantInputConsumer)) {
|
||||
// Present always on large screen or on small screen w/ flag
|
||||
boolean useTaskbarConsumer = tac.getDeviceProfile().isTaskbarPresent
|
||||
&& !tac.isPhoneMode()
|
||||
&& !tac.isInStashedLauncherState();
|
||||
if (canStartSystemGesture && useTaskbarConsumer) {
|
||||
reasonString.append("%s%s%sTaskbarActivityContext != null, "
|
||||
+ "using TaskbarUnstashInputConsumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX);
|
||||
base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac,
|
||||
mOverviewCommandHelper, mGestureState);
|
||||
}
|
||||
}
|
||||
if (enableBubblesLongPressNavHandle()) {
|
||||
// Create bubbles input consumer before NavHandleLongPressInputConsumer.
|
||||
// This allows for nav handle to fall back to bubbles.
|
||||
if (mDeviceState.isBubblesExpanded()) {
|
||||
reasonString = newCompoundString(reasonPrefix).append(
|
||||
"%sbubbles expanded, trying to use default input consumer",
|
||||
SUBSTRING_PREFIX);
|
||||
// Bubbles can handle home gesture itself.
|
||||
base = getDefaultInputConsumer(reasonString);
|
||||
}
|
||||
}
|
||||
|
||||
NavHandle navHandle = tac != null ? tac.getNavHandle()
|
||||
: SystemUiProxy.INSTANCE.get(this);
|
||||
if (canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()
|
||||
&& navHandle.canNavHandleBeLongPressed()
|
||||
&& !ignoreThreeFingerTrackpadForNavHandleLongPress(mGestureState)) {
|
||||
reasonString.append("%s%s%sNot running recents animation, ",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX);
|
||||
if (tac != null && tac.getNavHandle().canNavHandleBeLongPressed()) {
|
||||
reasonString.append("stashed handle is long-pressable, ");
|
||||
}
|
||||
reasonString.append("using NavHandleLongPressInputConsumer");
|
||||
base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat,
|
||||
mDeviceState, navHandle, mGestureState);
|
||||
}
|
||||
|
||||
if (!enableBubblesLongPressNavHandle()) {
|
||||
// Continue overriding nav handle input consumer with bubbles
|
||||
if (mDeviceState.isBubblesExpanded()) {
|
||||
reasonString = newCompoundString(reasonPrefix).append(
|
||||
"%sbubbles expanded, trying to use default input consumer",
|
||||
SUBSTRING_PREFIX);
|
||||
// Bubbles can handle home gesture itself.
|
||||
base = getDefaultInputConsumer(reasonString);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDeviceState.isSystemUiDialogShowing()) {
|
||||
reasonString = newCompoundString(reasonPrefix).append(
|
||||
"%ssystem dialog is showing, using SysUiOverlayInputConsumer",
|
||||
SUBSTRING_PREFIX);
|
||||
base = new SysUiOverlayInputConsumer(
|
||||
getBaseContext(), mDeviceState, mInputMonitorCompat);
|
||||
}
|
||||
|
||||
if (mGestureState.isTrackpadGesture()
|
||||
&& canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()) {
|
||||
reasonString = newCompoundString(reasonPrefix).append(
|
||||
"%sTrackpad 3-finger gesture, using TrackpadStatusBarInputConsumer",
|
||||
SUBSTRING_PREFIX);
|
||||
base = new TrackpadStatusBarInputConsumer(getBaseContext(), base,
|
||||
mInputMonitorCompat);
|
||||
}
|
||||
|
||||
if (mDeviceState.isScreenPinningActive()) {
|
||||
reasonString = newCompoundString(reasonPrefix).append(
|
||||
"%sscreen pinning is active, using ScreenPinnedInputConsumer",
|
||||
SUBSTRING_PREFIX);
|
||||
// Note: we only allow accessibility to wrap this, and it replaces the previous
|
||||
// base input consumer (which should be NO_OP anyway since topTaskLocked == true).
|
||||
base = new ScreenPinnedInputConsumer(this, newGestureState);
|
||||
}
|
||||
|
||||
if (mDeviceState.canTriggerOneHandedAction(event)) {
|
||||
reasonString.append("%s%s%sgesture can trigger one handed mode, "
|
||||
+ "using OneHandedModeInputConsumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX);
|
||||
base = new OneHandedModeInputConsumer(
|
||||
this, mDeviceState, base, mInputMonitorCompat);
|
||||
}
|
||||
|
||||
if (mDeviceState.isAccessibilityMenuAvailable()) {
|
||||
reasonString.append(
|
||||
"%s%s%saccessibility menu is available, using AccessibilityInputConsumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX);
|
||||
base = new AccessibilityInputConsumer(
|
||||
this, mDeviceState, mGestureState, base, mInputMonitorCompat);
|
||||
}
|
||||
} else {
|
||||
String reasonPrefix = "device is not in gesture navigation mode";
|
||||
if (mDeviceState.isScreenPinningActive()) {
|
||||
reasonString = newCompoundString(reasonPrefix).append(
|
||||
"%sscreen pinning is active, trying to use default input consumer",
|
||||
SUBSTRING_PREFIX);
|
||||
base = getDefaultInputConsumer(reasonString);
|
||||
}
|
||||
|
||||
if (mDeviceState.canTriggerOneHandedAction(event)) {
|
||||
reasonString.append("%s%s%sgesture can trigger one handed mode, "
|
||||
+ "using OneHandedModeInputConsumer",
|
||||
NEWLINE_PREFIX,
|
||||
reasonPrefix,
|
||||
SUBSTRING_PREFIX);
|
||||
base = new OneHandedModeInputConsumer(
|
||||
this, mDeviceState, base, mInputMonitorCompat);
|
||||
}
|
||||
}
|
||||
logInputConsumerSelectionReason(base, reasonString);
|
||||
return base;
|
||||
}
|
||||
|
||||
private CompoundString newCompoundString(String substring) {
|
||||
return new CompoundString("%s%s", NEWLINE_PREFIX, substring);
|
||||
}
|
||||
|
||||
private boolean ignoreThreeFingerTrackpadForNavHandleLongPress(GestureState gestureState) {
|
||||
return Flags.ignoreThreeFingerTrackpadForNavHandleLongPress()
|
||||
&& gestureState.isThreeFingerTrackpadGesture();
|
||||
}
|
||||
|
||||
private void logInputConsumerSelectionReason(
|
||||
InputConsumer consumer, CompoundString reasonString) {
|
||||
ActiveGestureProtoLogProxy.logSetInputConsumer(consumer.getName(), reasonString.toString());
|
||||
if ((consumer.getType() & InputConsumer.TYPE_OTHER_ACTIVITY) != 0) {
|
||||
ActiveGestureLog.INSTANCE.trackEvent(FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOrientationSetup(InputConsumer baseInputConsumer) {
|
||||
baseInputConsumer.notifyOrientationSetup();
|
||||
}
|
||||
|
||||
private InputConsumer newBaseConsumer(
|
||||
GestureState previousGestureState,
|
||||
GestureState gestureState,
|
||||
MotionEvent event,
|
||||
CompoundString reasonString) {
|
||||
if (mDeviceState.isKeyguardShowingOccluded()) {
|
||||
// This handles apps showing over the lockscreen (e.g. camera)
|
||||
return createDeviceLockedInputConsumer(gestureState, reasonString.append(
|
||||
"%skeyguard is showing occluded, trying to use device locked input consumer",
|
||||
SUBSTRING_PREFIX));
|
||||
}
|
||||
|
||||
reasonString.append("%skeyguard is not showing occluded", SUBSTRING_PREFIX);
|
||||
|
||||
TopTaskTracker.CachedTaskInfo runningTask = gestureState.getRunningTask();
|
||||
// Use overview input consumer for sharesheets on top of home.
|
||||
boolean forceOverviewInputConsumer = gestureState.getContainerInterface().isStarted()
|
||||
&& runningTask != null
|
||||
&& runningTask.isRootChooseActivity();
|
||||
|
||||
if (!com.android.wm.shell.Flags.enableShellTopTaskTracking()) {
|
||||
// In the case where we are in an excluded, translucent overlay, ignore it and treat the
|
||||
// running activity as the task behind the overlay.
|
||||
TopTaskTracker.CachedTaskInfo otherVisibleTask = runningTask == null
|
||||
? null
|
||||
: runningTask.getVisibleNonExcludedTask();
|
||||
if (otherVisibleTask != null) {
|
||||
ActiveGestureProtoLogProxy.logUpdateGestureStateRunningTask(
|
||||
otherVisibleTask.getPackageName(), runningTask.getPackageName());
|
||||
gestureState.updateRunningTask(otherVisibleTask);
|
||||
}
|
||||
}
|
||||
|
||||
boolean previousGestureAnimatedToLauncher =
|
||||
previousGestureState.isRunningAnimationToLauncher()
|
||||
|| mDeviceState.isPredictiveBackToHomeInProgress();
|
||||
// with shell-transitions, home is resumed during recents animation, so
|
||||
// explicitly check against recents animation too.
|
||||
boolean launcherResumedThroughShellTransition =
|
||||
gestureState.getContainerInterface().isResumed()
|
||||
&& !previousGestureState.isRecentsAnimationRunning();
|
||||
// If a task fragment within Launcher is resumed
|
||||
boolean launcherChildActivityResumed = useActivityOverlay()
|
||||
&& runningTask != null
|
||||
&& runningTask.isHomeTask()
|
||||
&& mOverviewComponentObserver.isHomeAndOverviewSame()
|
||||
&& !launcherResumedThroughShellTransition
|
||||
&& !previousGestureState.isRecentsAnimationRunning();
|
||||
|
||||
if (gestureState.getContainerInterface().isInLiveTileMode()) {
|
||||
return createOverviewInputConsumer(
|
||||
previousGestureState,
|
||||
gestureState,
|
||||
event,
|
||||
forceOverviewInputConsumer,
|
||||
reasonString.append(
|
||||
"%sis in live tile mode, trying to use overview input consumer",
|
||||
SUBSTRING_PREFIX));
|
||||
} else if (runningTask == null) {
|
||||
return getDefaultInputConsumer(reasonString.append(
|
||||
"%srunning task == null", SUBSTRING_PREFIX));
|
||||
} else if (previousGestureAnimatedToLauncher
|
||||
|| launcherResumedThroughShellTransition
|
||||
|| forceOverviewInputConsumer) {
|
||||
return createOverviewInputConsumer(
|
||||
previousGestureState,
|
||||
gestureState,
|
||||
event,
|
||||
forceOverviewInputConsumer,
|
||||
reasonString.append(previousGestureAnimatedToLauncher
|
||||
? "%sprevious gesture animated to launcher, "
|
||||
+ "trying to use overview input consumer"
|
||||
: (launcherResumedThroughShellTransition
|
||||
? "%slauncher resumed through a shell transition, "
|
||||
+ "trying to use overview input consumer"
|
||||
: "%sforceOverviewInputConsumer == true, "
|
||||
+ "trying to use overview input consumer"),
|
||||
SUBSTRING_PREFIX));
|
||||
} else if (mDeviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) {
|
||||
return getDefaultInputConsumer(reasonString.append(launcherChildActivityResumed
|
||||
? "%sis launcher child-task, trying to use default input consumer"
|
||||
: "%sis gesture-blocked task, trying to use default input consumer",
|
||||
SUBSTRING_PREFIX));
|
||||
} else {
|
||||
reasonString.append("%susing OtherActivityInputConsumer", SUBSTRING_PREFIX);
|
||||
return createOtherActivityInputConsumer(gestureState, event);
|
||||
}
|
||||
}
|
||||
|
||||
public AbsSwipeUpHandler.Factory getSwipeUpHandlerFactory() {
|
||||
boolean recentsInWindow =
|
||||
Flags.enableFallbackOverviewInWindow() || Flags.enableLauncherOverviewInWindow();
|
||||
@@ -1439,80 +1115,6 @@ public class TouchInteractionService extends Service {
|
||||
? mRecentsWindowSwipeHandlerFactory : mFallbackSwipeHandlerFactory);
|
||||
}
|
||||
|
||||
private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
|
||||
MotionEvent event) {
|
||||
|
||||
final AbsSwipeUpHandler.Factory factory = getSwipeUpHandlerFactory();
|
||||
final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
|
||||
|| gestureState.getContainerInterface().deferStartingActivity(mDeviceState, event);
|
||||
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
|
||||
return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
|
||||
gestureState, shouldDefer, this::onConsumerInactive,
|
||||
mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory);
|
||||
}
|
||||
|
||||
private InputConsumer createDeviceLockedInputConsumer(
|
||||
GestureState gestureState, CompoundString reasonString) {
|
||||
if ((mDeviceState.isFullyGesturalNavMode() || gestureState.isTrackpadGesture())
|
||||
&& gestureState.getRunningTask() != null) {
|
||||
reasonString.append("%sdevice is in gesture nav mode or 3-button mode with a trackpad "
|
||||
+ "gesture and running task != null, using DeviceLockedInputConsumer",
|
||||
SUBSTRING_PREFIX);
|
||||
return new DeviceLockedInputConsumer(
|
||||
this, mDeviceState, mTaskAnimationManager, gestureState, mInputMonitorCompat);
|
||||
} else {
|
||||
return getDefaultInputConsumer(reasonString.append(
|
||||
mDeviceState.isFullyGesturalNavMode() || gestureState.isTrackpadGesture()
|
||||
? "%srunning task == null, trying to use default input consumer"
|
||||
: "%sdevice is not in gesture nav mode and it's not a trackpad gesture,"
|
||||
+ " trying to use default input consumer",
|
||||
SUBSTRING_PREFIX));
|
||||
}
|
||||
}
|
||||
|
||||
public InputConsumer createOverviewInputConsumer(
|
||||
GestureState previousGestureState,
|
||||
GestureState gestureState,
|
||||
MotionEvent event,
|
||||
boolean forceOverviewInputConsumer,
|
||||
CompoundString reasonString) {
|
||||
RecentsViewContainer container = gestureState.getContainerInterface().getCreatedContainer();
|
||||
if (container == null) {
|
||||
return getDefaultInputConsumer(reasonString.append(
|
||||
"%sactivity == null, trying to use default input consumer", SUBSTRING_PREFIX));
|
||||
}
|
||||
|
||||
View rootview = container.getRootView();
|
||||
boolean hasWindowFocus = rootview != null && rootview.hasWindowFocus();
|
||||
boolean isPreviousGestureAnimatingToLauncher =
|
||||
previousGestureState.isRunningAnimationToLauncher()
|
||||
|| mDeviceState.isPredictiveBackToHomeInProgress();
|
||||
boolean isInLiveTileMode = gestureState.getContainerInterface().isInLiveTileMode();
|
||||
|
||||
reasonString.append(hasWindowFocus
|
||||
? "%sactivity has window focus"
|
||||
: (isPreviousGestureAnimatingToLauncher
|
||||
? "%sprevious gesture is still animating to launcher"
|
||||
: isInLiveTileMode
|
||||
? "%sdevice is in live mode"
|
||||
: "%sall overview focus conditions failed"), SUBSTRING_PREFIX);
|
||||
if (hasWindowFocus
|
||||
|| isPreviousGestureAnimatingToLauncher
|
||||
|| isInLiveTileMode) {
|
||||
reasonString.append(
|
||||
"%soverview should have focus, using OverviewInputConsumer", SUBSTRING_PREFIX);
|
||||
return new OverviewInputConsumer(gestureState, container, mInputMonitorCompat,
|
||||
false /* startingInActivityBounds */);
|
||||
} else {
|
||||
reasonString.append(
|
||||
"%soverview shouldn't have focus, using OverviewWithoutFocusInputConsumer",
|
||||
SUBSTRING_PREFIX);
|
||||
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
|
||||
return new OverviewWithoutFocusInputConsumer(container.asContext(), mDeviceState,
|
||||
gestureState, mInputMonitorCompat, disableHorizontalSwipe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called by the consumer when it's no longer active. This can be called by any consumer
|
||||
* in the hierarchy at any point during the gesture (ie. if a delegate consumer starts
|
||||
|
||||
Reference in New Issue
Block a user