Merge "Convert TaskViewTouchController to Kotlin." into main

This commit is contained in:
Treehugger Robot
2025-01-23 09:51:04 -08:00
committed by Android (Google) Code Review
6 changed files with 494 additions and 84 deletions
@@ -23,6 +23,7 @@ import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
import static com.android.launcher3.Flags.enableExpressiveDismissTaskMotion;
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -149,7 +150,9 @@ import com.android.launcher3.uioverrides.touchcontrollers.NoButtonQuickSwitchTou
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewRecentsTouchContext;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchControllerDeprecated;
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
import com.android.launcher3.util.ActivityOptionsWrapper;
@@ -265,6 +268,25 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
private final OverviewChangeListener mOverviewChangeListener = this::onOverviewTargetChanged;
private final TaskViewRecentsTouchContext mTaskViewRecentsTouchContext =
new TaskViewRecentsTouchContext() {
@Override
public boolean isRecentsInteractive() {
return isInState(OVERVIEW) || isInState(OVERVIEW_MODAL_TASK);
}
@Override
public boolean isRecentsModal() {
return isInState(OVERVIEW_MODAL_TASK);
}
@Override
public void onUserControlledAnimationCreated(
AnimatorPlaybackController animController) {
getStateManager().setCurrentUserControlledAnimation(animController);
}
};
public static QuickstepLauncher getLauncher(Context context) {
return fromContext(context);
}
@@ -665,7 +687,11 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
list.add(new StatusBarTouchController(this));
}
list.add(new LauncherTaskViewController(this));
if (enableExpressiveDismissTaskMotion()) {
list.add(new TaskViewTouchController<>(this, mTaskViewRecentsTouchContext));
} else {
list.add(new TaskViewTouchControllerDeprecated<>(this, mTaskViewRecentsTouchContext));
}
return list.toArray(new TouchController[list.size()]);
}
@@ -1442,29 +1468,6 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
mBubbleBarLocation = bubbleBarLocation;
}
private static final class LauncherTaskViewController extends
TaskViewTouchController<QuickstepLauncher> {
LauncherTaskViewController(QuickstepLauncher activity) {
super(activity);
}
@Override
protected boolean isRecentsInteractive() {
return mContainer.isInState(OVERVIEW) || mContainer.isInState(OVERVIEW_MODAL_TASK);
}
@Override
protected boolean isRecentsModal() {
return mContainer.isInState(OVERVIEW_MODAL_TASK);
}
@Override
protected void onUserControlledAnimationCreated(AnimatorPlaybackController animController) {
mContainer.getStateManager().setCurrentUserControlledAnimation(animController);
}
}
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2025 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.launcher3.uioverrides.touchcontrollers;
import com.android.launcher3.anim.AnimatorPlaybackController;
/** Interface providing context about the RecentsView state to a {@link TaskViewTouchController}. */
public interface TaskViewRecentsTouchContext {
/** Returns whether Recents is interactive for touch. */
boolean isRecentsInteractive();
/** Returns if Recents is showing a single task in a modal way. */
boolean isRecentsModal();
/** Runs when a user controlled animation is created. */
default void onUserControlledAnimationCreated(AnimatorPlaybackController animController) {
}
}
@@ -0,0 +1,394 @@
/*
* Copyright (C) 2025 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.launcher3.uioverrides.touchcontrollers
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.content.Context
import android.graphics.Rect
import android.os.VibrationEffect
import android.view.MotionEvent
import android.view.animation.Interpolator
import com.android.app.animation.Interpolators
import com.android.launcher3.AbstractFloatingView
import com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS
import com.android.launcher3.LauncherAnimUtils.blockedFlingDurationFactor
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.anim.AnimatorPlaybackController
import com.android.launcher3.anim.PendingAnimation
import com.android.launcher3.touch.BaseSwipeDetector
import com.android.launcher3.touch.SingleAxisSwipeDetector
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.FlingBlockCheck
import com.android.launcher3.util.TouchController
import com.android.launcher3.util.VibratorWrapper
import com.android.quickstep.util.VibrationConstants
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.TaskView
import kotlin.math.abs
/** Touch controller for handling task view card swipes */
class TaskViewTouchController<CONTAINER>(
private val container: CONTAINER,
private val taskViewRecentsTouchContext: TaskViewRecentsTouchContext,
) : AnimatorListenerAdapter(), TouchController, SingleAxisSwipeDetector.Listener where
CONTAINER : Context,
CONTAINER : RecentsViewContainer {
private val recentsView: RecentsView<*, *> = container.getOverviewPanel()
private val detector: SingleAxisSwipeDetector =
SingleAxisSwipeDetector(
container as Context,
this,
recentsView.pagedOrientationHandler.upDownSwipeDirection,
)
private val tempRect = Rect()
private val isRtl = Utilities.isRtl(container.resources)
private val flingBlockCheck = FlingBlockCheck()
private var currentAnimation: AnimatorPlaybackController? = null
private var currentAnimationIsGoingUp = false
private var allowGoingUp = false
private var allowGoingDown = false
private var noIntercept = false
private var displacementShift = 0f
private var progressMultiplier = 0f
private var endDisplacement = 0f
private var draggingEnabled = true
private var overrideVelocity: Float? = null
private var taskBeingDragged: TaskView? = null
private var isDismissHapticRunning = false
private fun canInterceptTouch(ev: MotionEvent): Boolean {
val currentAnimation = currentAnimation
return when {
(ev.edgeFlags and Utilities.EDGE_NAV_BAR) != 0 -> {
// Don't intercept swipes on the nav bar, as user might be trying to go home
// during a task dismiss animation.
currentAnimation?.animationPlayer?.end()
false
}
currentAnimation != null -> {
currentAnimation.forceFinishIfCloseToEnd()
true
}
AbstractFloatingView.getTopOpenViewWithType(
container,
AbstractFloatingView.TYPE_TOUCH_CONTROLLER_NO_INTERCEPT,
) != null -> false
else -> taskViewRecentsTouchContext.isRecentsInteractive
}
}
override fun onAnimationCancel(animation: Animator) {
if (animation === currentAnimation?.target) {
clearState()
}
}
override fun onControllerInterceptTouchEvent(ev: MotionEvent): Boolean {
if (
(ev.action == MotionEvent.ACTION_UP || ev.action == MotionEvent.ACTION_CANCEL) &&
currentAnimation == null
) {
clearState()
}
if (ev.action == MotionEvent.ACTION_DOWN) {
// Disable swiping up and down if the task overlay is modal.
if (taskViewRecentsTouchContext.isRecentsModal) {
noIntercept = true
return false
}
noIntercept = !canInterceptTouch(ev)
if (noIntercept) {
return false
}
// Now figure out which direction scroll events the controller will start
// calling the callbacks.
var directionsToDetectScroll = 0
var ignoreSlopWhenSettling = false
if (currentAnimation != null) {
directionsToDetectScroll = SingleAxisSwipeDetector.DIRECTION_BOTH
ignoreSlopWhenSettling = true
} else {
taskBeingDragged = null
recentsView.taskViews.forEach { taskView ->
if (
recentsView.isTaskViewVisible(taskView) &&
container.dragLayer.isEventOverView(taskView, ev)
) {
taskBeingDragged = taskView
val upDirection = recentsView.pagedOrientationHandler.getUpDirection(isRtl)
// The task can be dragged up to dismiss it
allowGoingUp = true
// The task can be dragged down to open it if:
// - It's the current page
// - We support gestures to enter overview
// - It's the focused task if in grid view
// - The task is snapped
allowGoingDown =
taskView === recentsView.currentPageTaskView &&
DisplayController.getNavigationMode(container).hasGestures &&
(!recentsView.showAsGrid() || taskView.isLargeTile) &&
recentsView.isTaskInExpectedScrollPosition(taskView)
directionsToDetectScroll =
if (allowGoingDown) SingleAxisSwipeDetector.DIRECTION_BOTH
else upDirection
return@forEach
}
}
if (taskBeingDragged == null) {
noIntercept = true
return false
}
}
detector.setDetectableScrollConditions(directionsToDetectScroll, ignoreSlopWhenSettling)
}
if (noIntercept) {
return false
}
onControllerTouchEvent(ev)
return detector.isDraggingOrSettling
}
override fun onControllerTouchEvent(ev: MotionEvent): Boolean = detector.onTouchEvent(ev)
private fun reInitAnimationController(goingUp: Boolean) {
if (currentAnimation != null && currentAnimationIsGoingUp == goingUp) {
// No need to init
return
}
if ((goingUp && !allowGoingUp) || (!goingUp && !allowGoingDown)) {
// Trying to re-init in an unsupported direction.
return
}
val taskBeingDragged = taskBeingDragged ?: return
currentAnimation?.setPlayFraction(0f)
currentAnimation?.target?.removeListener(this)
currentAnimation?.dispatchOnCancel()
val orientationHandler = recentsView.pagedOrientationHandler
currentAnimationIsGoingUp = goingUp
val dl = container.dragLayer
val secondaryLayerDimension = orientationHandler.getSecondaryDimension(dl)
val maxDuration = 2L * secondaryLayerDimension
val verticalFactor = orientationHandler.getTaskDragDisplacementFactor(isRtl)
val secondaryTaskDimension = orientationHandler.getSecondaryDimension(taskBeingDragged)
// The interpolator controlling the most prominent visual movement. We use this to determine
// whether we passed SUCCESS_TRANSITION_PROGRESS.
val currentInterpolator: Interpolator
val pa: PendingAnimation
if (goingUp) {
currentInterpolator = Interpolators.LINEAR
pa = PendingAnimation(maxDuration)
recentsView.createTaskDismissAnimation(
pa,
taskBeingDragged,
true, /* animateTaskView */
true, /* removeTask */
maxDuration,
false, /* dismissingForSplitSelection*/
)
endDisplacement = -secondaryTaskDimension.toFloat()
} else {
currentInterpolator = Interpolators.ZOOM_IN
pa =
recentsView.createTaskLaunchAnimation(
taskBeingDragged,
maxDuration,
currentInterpolator,
)
// Since the thumbnail is what is filling the screen, based the end displacement on it.
taskBeingDragged.getThumbnailBounds(tempRect, /* relativeToDragLayer= */ true)
endDisplacement = (secondaryLayerDimension - tempRect.bottom).toFloat()
}
endDisplacement *= verticalFactor.toFloat()
currentAnimation =
pa.createPlaybackController().apply {
// Setting this interpolator doesn't affect the visual motion, but is used to
// determine whether we successfully reached the target state in onDragEnd().
target.interpolator = currentInterpolator
taskViewRecentsTouchContext.onUserControlledAnimationCreated(this)
target.addListener(this@TaskViewTouchController)
dispatchOnStart()
}
progressMultiplier = 1 / endDisplacement
}
override fun onDragStart(start: Boolean, startDisplacement: Float) {
if (!draggingEnabled) return
val currentAnimation = currentAnimation
val orientationHandler = recentsView.pagedOrientationHandler
if (currentAnimation == null) {
reInitAnimationController(orientationHandler.isGoingUp(startDisplacement, isRtl))
displacementShift = 0f
} else {
displacementShift = currentAnimation.progressFraction / progressMultiplier
currentAnimation.pause()
}
flingBlockCheck.unblockFling()
overrideVelocity = null
}
override fun onDrag(displacement: Float): Boolean {
if (!draggingEnabled) return true
val taskBeingDragged = taskBeingDragged ?: return true
val currentAnimation = currentAnimation ?: return true
val orientationHandler = recentsView.pagedOrientationHandler
val totalDisplacement = displacement + displacementShift
val isGoingUp =
if (totalDisplacement == 0f) currentAnimationIsGoingUp
else orientationHandler.isGoingUp(totalDisplacement, isRtl)
if (isGoingUp != currentAnimationIsGoingUp) {
reInitAnimationController(isGoingUp)
flingBlockCheck.blockFling()
} else {
flingBlockCheck.onEvent()
}
if (isGoingUp) {
if (currentAnimation.progressFraction < ANIMATION_PROGRESS_FRACTION_MIDPOINT) {
// Halve the value when dismissing, as we are animating the drag across the full
// length for only the first half of the progress
currentAnimation.setPlayFraction(
Utilities.boundToRange(totalDisplacement * progressMultiplier / 2, 0f, 1f)
)
} else {
// Set mOverrideVelocity to control task dismiss velocity in onDragEnd
var velocityDimenId = R.dimen.default_task_dismiss_drag_velocity
if (recentsView.showAsGrid()) {
velocityDimenId =
if (taskBeingDragged.isLargeTile) {
R.dimen.default_task_dismiss_drag_velocity_grid_focus_task
} else {
R.dimen.default_task_dismiss_drag_velocity_grid
}
}
overrideVelocity = -taskBeingDragged.resources.getDimension(velocityDimenId)
// Once halfway through task dismissal interpolation, switch from reversible
// dragging-task animation to playing the remaining task translation animations,
// while this is in progress disable dragging.
draggingEnabled = false
}
} else {
currentAnimation.setPlayFraction(
Utilities.boundToRange(totalDisplacement * progressMultiplier, 0f, 1f)
)
}
return true
}
override fun onDragEnd(velocity: Float) {
val taskBeingDragged = taskBeingDragged ?: return
val currentAnimation = currentAnimation ?: return
// Limit velocity, as very large scalar values make animations play too quickly
val maxTaskDismissDragVelocity =
taskBeingDragged.resources.getDimension(R.dimen.max_task_dismiss_drag_velocity)
val endVelocity =
Utilities.boundToRange(
overrideVelocity ?: velocity,
-maxTaskDismissDragVelocity,
maxTaskDismissDragVelocity,
)
overrideVelocity = null
var fling = draggingEnabled && detector.isFling(endVelocity)
val goingToEnd: Boolean
val blockedFling = fling && flingBlockCheck.isBlocked
if (blockedFling) {
fling = false
}
val orientationHandler = recentsView.pagedOrientationHandler
val goingUp = orientationHandler.isGoingUp(endVelocity, isRtl)
val progress = currentAnimation.progressFraction
val interpolatedProgress = currentAnimation.interpolatedProgress
goingToEnd =
if (fling) {
goingUp == currentAnimationIsGoingUp
} else {
interpolatedProgress > SUCCESS_TRANSITION_PROGRESS
}
var animationDuration =
BaseSwipeDetector.calculateDuration(
endVelocity,
if (goingToEnd) (1 - progress) else progress,
)
if (blockedFling && !goingToEnd) {
animationDuration *= blockedFlingDurationFactor(endVelocity).toLong()
}
// Due to very high or low velocity dismissals, animation durations can be inconsistently
// long or short. Bound the duration for animation of task translations for a more
// standardized feel.
animationDuration =
Utilities.boundToRange(
animationDuration,
MIN_TASK_DISMISS_ANIMATION_DURATION,
MAX_TASK_DISMISS_ANIMATION_DURATION,
)
currentAnimation.setEndAction { this.clearState() }
currentAnimation.startWithVelocity(
container,
goingToEnd,
abs(endVelocity.toDouble()).toFloat(),
endDisplacement,
animationDuration,
)
if (goingUp && goingToEnd && !isDismissHapticRunning) {
VibratorWrapper.INSTANCE.get(container)
.vibrate(
TASK_DISMISS_VIBRATION_PRIMITIVE,
TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE,
TASK_DISMISS_VIBRATION_FALLBACK,
)
isDismissHapticRunning = true
}
draggingEnabled = true
}
private fun clearState() {
detector.finishedScrolling()
detector.setDetectableScrollConditions(0, false)
draggingEnabled = true
taskBeingDragged = null
currentAnimation = null
isDismissHapticRunning = false
}
companion object {
private const val ANIMATION_PROGRESS_FRACTION_MIDPOINT = 0.5f
private const val MIN_TASK_DISMISS_ANIMATION_DURATION: Long = 300
private const val MAX_TASK_DISMISS_ANIMATION_DURATION: Long = 600
private const val TASK_DISMISS_VIBRATION_PRIMITIVE: Int =
VibrationEffect.Composition.PRIMITIVE_TICK
private const val TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE: Float = 1f
private val TASK_DISMISS_VIBRATION_FALLBACK: VibrationEffect =
VibrationConstants.EFFECT_TEXTURE_TICK
}
}
@@ -49,10 +49,13 @@ import com.android.quickstep.views.TaskView;
/**
* Touch controller for handling task view card swipes
*
* @deprecated This class will be replaced by the new {@link TaskViewTouchController}.
*/
public abstract class TaskViewTouchController<CONTAINER extends Context & RecentsViewContainer>
extends AnimatorListenerAdapter implements TouchController,
SingleAxisSwipeDetector.Listener {
@Deprecated
public class TaskViewTouchControllerDeprecated<
CONTAINER extends Context & RecentsViewContainer> extends AnimatorListenerAdapter
implements TouchController, SingleAxisSwipeDetector.Listener {
private static final float ANIMATION_PROGRESS_FRACTION_MIDPOINT = 0.5f;
private static final long MIN_TASK_DISMISS_ANIMATION_DURATION = 300;
@@ -65,6 +68,7 @@ public abstract class TaskViewTouchController<CONTAINER extends Context & Recent
VibrationConstants.EFFECT_TEXTURE_TICK;
protected final CONTAINER mContainer;
private final TaskViewRecentsTouchContext mTaskViewRecentsTouchContext;
private final SingleAxisSwipeDetector mDetector;
private final RecentsView<?, ?> mRecentsView;
private final Rect mTempRect = new Rect();
@@ -88,8 +92,10 @@ public abstract class TaskViewTouchController<CONTAINER extends Context & Recent
private boolean mIsDismissHapticRunning = false;
public TaskViewTouchController(CONTAINER container) {
public TaskViewTouchControllerDeprecated(CONTAINER container,
TaskViewRecentsTouchContext taskViewRecentsTouchContext) {
mContainer = container;
mTaskViewRecentsTouchContext = taskViewRecentsTouchContext;
mRecentsView = container.getOverviewPanel();
mIsRtl = Utilities.isRtl(container.getResources());
SingleAxisSwipeDetector.Direction dir =
@@ -117,15 +123,7 @@ public abstract class TaskViewTouchController<CONTAINER extends Context & Recent
mContainer, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null) {
return false;
}
return isRecentsInteractive();
}
protected abstract boolean isRecentsInteractive();
/** Is recents view showing a single task in a modal way. */
protected abstract boolean isRecentsModal();
protected void onUserControlledAnimationCreated(AnimatorPlaybackController animController) {
return mTaskViewRecentsTouchContext.isRecentsInteractive();
}
@Override
@@ -161,7 +159,7 @@ public abstract class TaskViewTouchController<CONTAINER extends Context & Recent
if (mRecentsView.isTaskViewVisible(taskView) && mContainer.getDragLayer()
.isEventOverView(taskView, ev)) {
// Disable swiping up and down if the task overlay is modal.
if (isRecentsModal()) {
if (mTaskViewRecentsTouchContext.isRecentsModal()) {
mTaskBeingDragged = null;
break;
}
@@ -259,7 +257,7 @@ public abstract class TaskViewTouchController<CONTAINER extends Context & Recent
// Setting this interpolator doesn't affect the visual motion, but is used to determine
// whether we successfully reached the target state in onDragEnd().
mCurrentAnimation.getTarget().setInterpolator(currentInterpolator);
onUserControlledAnimationCreated(mCurrentAnimation);
mTaskViewRecentsTouchContext.onUserControlledAnimationCreated(mCurrentAnimation);
mCurrentAnimation.getTarget().addListener(this);
mCurrentAnimation.dispatchOnStart();
mProgressMultiplier = 1 / mEndDisplacement;
@@ -15,9 +15,15 @@
*/
package com.android.quickstep.fallback;
import static com.android.launcher3.Flags.enableExpressiveDismissTaskMotion;
import android.content.Context;
import android.util.AttributeSet;
import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewRecentsTouchContext;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchControllerDeprecated;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.views.RecentsViewContainer;
@@ -25,16 +31,33 @@ import com.android.quickstep.views.RecentsViewContainer;
/**
* Drag layer for fallback recents activity
*/
public class RecentsDragLayer<T extends Context & RecentsViewContainer> extends BaseDragLayer<T> {
public class RecentsDragLayer<T extends Context & RecentsViewContainer
& StatefulContainer<RecentsState>> extends BaseDragLayer<T> {
private final TaskViewRecentsTouchContext mTaskViewRecentsTouchContext =
new TaskViewRecentsTouchContext() {
@Override
public boolean isRecentsInteractive() {
return mContainer.getRootView().hasWindowFocus()
|| mContainer.getStateManager().getState().hasLiveTile();
}
@Override
public boolean isRecentsModal() {
return false;
}
};
public RecentsDragLayer(Context context, AttributeSet attrs) {
super(context, attrs, 1 /* alphaChannelCount */);
}
@Override
public void recreateControllers() {
mControllers = new TouchController[] {
new RecentsTaskController(mContainer),
new FallbackNavBarTouchController(mContainer),
};
mControllers = new TouchController[]{
enableExpressiveDismissTaskMotion() ? new TaskViewTouchController<>(mContainer,
mTaskViewRecentsTouchContext) : new TaskViewTouchControllerDeprecated<>(
mContainer, mTaskViewRecentsTouchContext),
new FallbackNavBarTouchController(mContainer)};
}
}
@@ -1,40 +0,0 @@
/*
* Copyright (C) 2018 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.fallback;
import android.content.Context;
import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.quickstep.views.RecentsViewContainer;
public class RecentsTaskController<T extends Context & RecentsViewContainer &
StatefulContainer<RecentsState>> extends TaskViewTouchController<T> {
public RecentsTaskController(T container) {
super(container);
}
@Override
protected boolean isRecentsInteractive() {
return mContainer.getRootView().hasWindowFocus()
|| mContainer.getStateManager().getState().hasLiveTile();
}
@Override
protected boolean isRecentsModal() {
return false;
}
}