blob: bea3150bcb96c005023cc57a7673a856276c1a64 [file] [edit]
/*
* 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()
}
}