Merge "Adding swipe gestures in overview screen" into ub-launcher3-master
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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.launcher3.uioverrides;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.dragndrop.DragLayer;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.quickstep.RecentsView;
|
||||
import com.android.quickstep.TaskView;
|
||||
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
|
||||
|
||||
/**
|
||||
* Touch controller for swipe interaction in Overview state
|
||||
*/
|
||||
public class OverviewSwipeController extends AnimatorListenerAdapter
|
||||
implements TouchController, SwipeDetector.Listener {
|
||||
|
||||
private static final String TAG = "OverviewSwipeController";
|
||||
|
||||
private static final float ALLOWED_FLING_DIRECTION_CHANGE_PROGRESS = 0.1f;
|
||||
private static final int SINGLE_FRAME_MS = 16;
|
||||
|
||||
// Progress after which the transition is assumed to be a success in case user does not fling
|
||||
private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final SwipeDetector mDetector;
|
||||
private final RecentsView mRecentsView;
|
||||
private final int[] mTempCords = new int[2];
|
||||
|
||||
private AnimatorPlaybackController mCurrentAnimation;
|
||||
private boolean mCurrentAnimationIsGoingUp;
|
||||
|
||||
private boolean mNoIntercept;
|
||||
private boolean mSwipeDownEnabled;
|
||||
|
||||
private float mDisplacementShift;
|
||||
private float mProgressMultiplier;
|
||||
private float mEndDisplacement;
|
||||
|
||||
private TaskView mTaskBeingDragged;
|
||||
|
||||
public OverviewSwipeController(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
mRecentsView = launcher.getOverviewPanel();
|
||||
mDetector = new SwipeDetector(launcher, this, SwipeDetector.VERTICAL);
|
||||
}
|
||||
|
||||
private boolean canInterceptTouch() {
|
||||
if (mCurrentAnimation != null) {
|
||||
// If we are already animating from a previous state, we can intercept.
|
||||
return true;
|
||||
}
|
||||
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
|
||||
return false;
|
||||
}
|
||||
return mLauncher.isInState(OVERVIEW);
|
||||
}
|
||||
|
||||
private boolean isEventOverHotseat(MotionEvent ev) {
|
||||
if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
|
||||
return ev.getY() >
|
||||
mLauncher.getDragLayer().getHeight() * OVERVIEW.getVerticalProgress(mLauncher);
|
||||
} else {
|
||||
return mLauncher.getDragLayer().isEventOverHotseat(ev);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) {
|
||||
Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
|
||||
mDetector.finishedScrolling();
|
||||
mCurrentAnimation = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mNoIntercept = !canInterceptTouch();
|
||||
if (mNoIntercept) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now figure out which direction scroll events the controller will start
|
||||
// calling the callbacks.
|
||||
final int directionsToDetectScroll;
|
||||
boolean ignoreSlopWhenSettling = false;
|
||||
|
||||
if (mCurrentAnimation != null) {
|
||||
directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
|
||||
ignoreSlopWhenSettling = true;
|
||||
} else {
|
||||
mTaskBeingDragged = null;
|
||||
mSwipeDownEnabled = true;
|
||||
|
||||
int currentPage = mRecentsView.getCurrentPage();
|
||||
if (currentPage == 0) {
|
||||
// User is on home tile
|
||||
directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
|
||||
} else {
|
||||
View view = mRecentsView.getChildAt(currentPage);
|
||||
if (mLauncher.getDragLayer().isEventOverView(view, ev) &&
|
||||
view instanceof TaskView) {
|
||||
// The tile can be dragged down to open the task.
|
||||
mTaskBeingDragged = (TaskView) view;
|
||||
directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
|
||||
} else if (isEventOverHotseat(ev)) {
|
||||
// The hotseat is being dragged
|
||||
directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
|
||||
mSwipeDownEnabled = false;
|
||||
} else {
|
||||
mNoIntercept = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mDetector.setDetectableScrollConditions(
|
||||
directionsToDetectScroll, ignoreSlopWhenSettling);
|
||||
}
|
||||
|
||||
if (mNoIntercept) {
|
||||
return false;
|
||||
}
|
||||
|
||||
onControllerTouchEvent(ev);
|
||||
return mDetector.isDraggingOrSettling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onControllerTouchEvent(MotionEvent ev) {
|
||||
return mDetector.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
private void reinitAnimationController(boolean goingUp) {
|
||||
if (!goingUp && !mSwipeDownEnabled) {
|
||||
goingUp = true;
|
||||
}
|
||||
if (mCurrentAnimation != null && mCurrentAnimationIsGoingUp == goingUp) {
|
||||
// No need to init
|
||||
return;
|
||||
}
|
||||
if (mCurrentAnimation != null) {
|
||||
mCurrentAnimation.setPlayFraction(0);
|
||||
}
|
||||
mCurrentAnimationIsGoingUp = goingUp;
|
||||
float range = mLauncher.getAllAppsController().getShiftRange();
|
||||
long maxDuration = (long) (2 * range);
|
||||
DragLayer dl = mLauncher.getDragLayer();
|
||||
|
||||
if (mTaskBeingDragged == null) {
|
||||
// User is either going to all apps or home
|
||||
mCurrentAnimation = mLauncher.getStateManager()
|
||||
.createAnimationToNewWorkspace(goingUp ? ALL_APPS : NORMAL, maxDuration);
|
||||
if (goingUp) {
|
||||
mEndDisplacement = -range;
|
||||
} else {
|
||||
View ws = mLauncher.getWorkspace();
|
||||
mTempCords[1] = ws.getHeight() - ws.getPaddingBottom();
|
||||
dl.getDescendantCoordRelativeToSelf(ws, mTempCords);
|
||||
|
||||
float distance = mTempCords[1];
|
||||
if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
|
||||
mTempCords[1] = 0;
|
||||
dl.getDescendantCoordRelativeToSelf(mLauncher.getHotseat(), mTempCords);
|
||||
distance = mTempCords[1] - distance;
|
||||
} else {
|
||||
distance = dl.getHeight() - distance;
|
||||
}
|
||||
|
||||
mEndDisplacement = distance;
|
||||
}
|
||||
} else {
|
||||
if (goingUp) {
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
ObjectAnimator translate = ObjectAnimator.ofFloat(
|
||||
mTaskBeingDragged, View.TRANSLATION_Y, -mTaskBeingDragged.getBottom());
|
||||
translate.setInterpolator(LINEAR);
|
||||
translate.setDuration(maxDuration);
|
||||
anim.play(translate);
|
||||
|
||||
ObjectAnimator alpha = ObjectAnimator.ofFloat(mTaskBeingDragged, View.ALPHA, 0);
|
||||
alpha.setInterpolator(DEACCEL_1_5);
|
||||
alpha.setDuration(maxDuration);
|
||||
anim.play(alpha);
|
||||
mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration);
|
||||
mEndDisplacement = -mTaskBeingDragged.getBottom();
|
||||
} else {
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
// TODO: Setup a zoom animation
|
||||
mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration);
|
||||
|
||||
mTempCords[1] = mTaskBeingDragged.getHeight();
|
||||
dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
|
||||
mEndDisplacement = dl.getHeight() - mTempCords[1];
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentAnimation.getTarget().addListener(this);
|
||||
mCurrentAnimation.dispatchOnStart();
|
||||
mProgressMultiplier = 1 / mEndDisplacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
if (mCurrentAnimation == null) {
|
||||
reinitAnimationController(mDetector.wasInitialTouchPositive());
|
||||
mDisplacementShift = 0;
|
||||
} else {
|
||||
mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier;
|
||||
mCurrentAnimation.pause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrag(float displacement, float velocity) {
|
||||
float totalDisplacement = displacement + mDisplacementShift;
|
||||
boolean isGoingUp =
|
||||
totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0;
|
||||
if (isGoingUp != mCurrentAnimationIsGoingUp) {
|
||||
reinitAnimationController(isGoingUp);
|
||||
}
|
||||
mCurrentAnimation.setPlayFraction(totalDisplacement * mProgressMultiplier);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity, boolean fling) {
|
||||
final boolean goingToEnd;
|
||||
|
||||
if (fling) {
|
||||
boolean goingUp = velocity < 0;
|
||||
if (!goingUp && !mSwipeDownEnabled) {
|
||||
goingToEnd = false;
|
||||
} else if (goingUp != mCurrentAnimationIsGoingUp) {
|
||||
// In case the fling is in opposite direction, make sure if is close enough
|
||||
// from the start position
|
||||
if (mCurrentAnimation.getProgressFraction()
|
||||
>= ALLOWED_FLING_DIRECTION_CHANGE_PROGRESS) {
|
||||
// Not allowed
|
||||
goingToEnd = false;
|
||||
} else {
|
||||
reinitAnimationController(goingUp);
|
||||
goingToEnd = true;
|
||||
}
|
||||
} else {
|
||||
goingToEnd = true;
|
||||
}
|
||||
} else {
|
||||
goingToEnd = mCurrentAnimation.getProgressFraction() > SUCCESS_TRANSITION_PROGRESS;
|
||||
}
|
||||
|
||||
float progress = mCurrentAnimation.getProgressFraction();
|
||||
long animationDuration = SwipeDetector.calculateDuration(
|
||||
velocity, goingToEnd ? (1 - progress) : progress);
|
||||
|
||||
float nextFrameProgress = Utilities.boundToRange(
|
||||
progress + velocity * SINGLE_FRAME_MS / Math.abs(mEndDisplacement), 0f, 1f);
|
||||
|
||||
|
||||
mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd));
|
||||
|
||||
ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
|
||||
anim.setFloatValues(nextFrameProgress, goingToEnd ? 1f : 0f);
|
||||
anim.setDuration(animationDuration);
|
||||
anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
|
||||
anim.start();
|
||||
}
|
||||
|
||||
private void onCurrentAnimationEnd(boolean wasSuccess) {
|
||||
// TODO: Might be a good time to log something.
|
||||
if (mTaskBeingDragged == null) {
|
||||
LauncherState state = wasSuccess ?
|
||||
(mCurrentAnimationIsGoingUp ? ALL_APPS : NORMAL) : OVERVIEW;
|
||||
mLauncher.getStateManager().goToState(state, false);
|
||||
} else if (wasSuccess) {
|
||||
if (mCurrentAnimationIsGoingUp) {
|
||||
mRecentsView.onTaskDismissed(mTaskBeingDragged);
|
||||
} else {
|
||||
mTaskBeingDragged.launchTask(false);
|
||||
}
|
||||
}
|
||||
mDetector.finishedScrolling();
|
||||
mTaskBeingDragged = null;
|
||||
mCurrentAnimation = null;
|
||||
}
|
||||
}
|
||||
@@ -41,11 +41,11 @@ public class UiFactory {
|
||||
return new TouchController[]{
|
||||
new EdgeSwipeController(launcher),
|
||||
new TwoStepSwipeController(launcher),
|
||||
new OverviewSwipeUpController(launcher)};
|
||||
new OverviewSwipeController(launcher)};
|
||||
} else {
|
||||
return new TouchController[]{
|
||||
new TwoStepSwipeController(launcher),
|
||||
new OverviewSwipeUpController(launcher)};
|
||||
new OverviewSwipeController(launcher)};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,29 +16,17 @@
|
||||
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
|
||||
import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Property;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.touch.SwipeDetector;
|
||||
import com.android.quickstep.RecentsView.PageCallbacks;
|
||||
import com.android.quickstep.RecentsView.ScrollState;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
@@ -52,11 +40,13 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
|
||||
import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
|
||||
|
||||
/**
|
||||
* A task in the Recents view.
|
||||
*/
|
||||
public class TaskView extends FrameLayout implements TaskCallbacks, SwipeDetector.Listener,
|
||||
PageCallbacks {
|
||||
public class TaskView extends FrameLayout implements TaskCallbacks, PageCallbacks {
|
||||
|
||||
/** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
|
||||
private static final float CURVE_FACTOR = 0.25f;
|
||||
@@ -70,30 +60,8 @@ public class TaskView extends FrameLayout implements TaskCallbacks, SwipeDetecto
|
||||
*/
|
||||
private static final float MAX_PAGE_SCRIM_ALPHA = 0.8f;
|
||||
|
||||
private static final int SWIPE_DIRECTIONS = SwipeDetector.DIRECTION_POSITIVE;
|
||||
|
||||
/**
|
||||
* The task will appear fully dismissed when the distance swiped
|
||||
* reaches this percentage of the card height.
|
||||
*/
|
||||
private static final float SWIPE_DISTANCE_HEIGHT_PERCENTAGE = 0.38f;
|
||||
|
||||
private static final long SCALE_ICON_DURATION = 120;
|
||||
|
||||
private static final Property<TaskView, Float> PROPERTY_SWIPE_PROGRESS =
|
||||
new Property<TaskView, Float>(Float.class, "swipe_progress") {
|
||||
|
||||
@Override
|
||||
public Float get(TaskView taskView) {
|
||||
return taskView.mSwipeProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(TaskView taskView, Float progress) {
|
||||
taskView.setSwipeProgress(progress);
|
||||
}
|
||||
};
|
||||
|
||||
private static final Property<TaskView, Float> SCALE_ICON_PROPERTY =
|
||||
new Property<TaskView, Float>(Float.TYPE, "scale_icon") {
|
||||
@Override
|
||||
@@ -110,11 +78,6 @@ public class TaskView extends FrameLayout implements TaskCallbacks, SwipeDetecto
|
||||
private Task mTask;
|
||||
private TaskThumbnailView mSnapshotView;
|
||||
private ImageView mIconView;
|
||||
private SwipeDetector mSwipeDetector;
|
||||
private float mSwipeDistance;
|
||||
private float mSwipeProgress;
|
||||
private Interpolator mAlphaInterpolator;
|
||||
private Interpolator mSwipeAnimInterpolator;
|
||||
private float mIconScale = 1f;
|
||||
|
||||
public TaskView(Context context) {
|
||||
@@ -130,11 +93,6 @@ public class TaskView extends FrameLayout implements TaskCallbacks, SwipeDetecto
|
||||
setOnClickListener((view) -> {
|
||||
launchTask(true /* animate */);
|
||||
});
|
||||
|
||||
mSwipeDetector = new SwipeDetector(getContext(), this, SwipeDetector.VERTICAL);
|
||||
mSwipeDetector.setDetectableScrollConditions(SWIPE_DIRECTIONS, false);
|
||||
mAlphaInterpolator = Interpolators.ACCEL_1_5;
|
||||
mSwipeAnimInterpolator = Interpolators.SCROLL_CUBIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,15 +102,6 @@ public class TaskView extends FrameLayout implements TaskCallbacks, SwipeDetecto
|
||||
mIconView = findViewById(R.id.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
View p = (View) getParent();
|
||||
mSwipeDistance = (getMeasuredHeight() - p.getPaddingTop() - p.getPaddingBottom())
|
||||
* SWIPE_DISTANCE_HEIGHT_PERCENTAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this task view to the given {@param task}.
|
||||
*/
|
||||
@@ -223,80 +172,6 @@ public class TaskView extends FrameLayout implements TaskCallbacks, SwipeDetecto
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
mSwipeDetector.onTouchEvent(ev);
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
mSwipeDetector.onTouchEvent(event);
|
||||
return mSwipeDetector.isDraggingOrSettling() || super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
// Swipe detector methods
|
||||
|
||||
@Override
|
||||
public void onDragStart(boolean start) {
|
||||
getParent().requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrag(float displacement, float velocity) {
|
||||
setSwipeProgress(Utilities.boundToRange(displacement / mSwipeDistance,
|
||||
allowsSwipeUp() ? -1 : 0, allowsSwipeDown() ? 1 : 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the page is being removed.
|
||||
* @param progress Ranges from -1 (fading upwards) to 1 (fading downwards).
|
||||
*/
|
||||
private void setSwipeProgress(float progress) {
|
||||
mSwipeProgress = progress;
|
||||
float translationY = mSwipeProgress * mSwipeDistance;
|
||||
float alpha = 1f - mAlphaInterpolator.getInterpolation(Math.abs(mSwipeProgress));
|
||||
// Only change children to avoid changing our properties while dragging.
|
||||
mIconView.setTranslationY(translationY);
|
||||
mSnapshotView.setTranslationY(translationY);
|
||||
mIconView.setAlpha(alpha);
|
||||
mSnapshotView.setAlpha(alpha);
|
||||
}
|
||||
|
||||
private boolean allowsSwipeUp() {
|
||||
return (SWIPE_DIRECTIONS & SwipeDetector.DIRECTION_POSITIVE) != 0;
|
||||
}
|
||||
|
||||
private boolean allowsSwipeDown() {
|
||||
return (SWIPE_DIRECTIONS & SwipeDetector.DIRECTION_NEGATIVE) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragEnd(float velocity, boolean fling) {
|
||||
boolean movingAwayFromCenter = velocity < 0 == mSwipeProgress < 0;
|
||||
boolean flingAway = fling && movingAwayFromCenter
|
||||
&& (allowsSwipeUp() && velocity < 0 || allowsSwipeDown() && velocity > 0);
|
||||
final boolean shouldRemove = flingAway || (!fling && Math.abs(mSwipeProgress) > 0.5f);
|
||||
float fromProgress = mSwipeProgress;
|
||||
float toProgress = !shouldRemove ? 0f : mSwipeProgress < 0 ? -1f : 1f;
|
||||
ValueAnimator swipeAnimator = ObjectAnimator.ofFloat(this, PROPERTY_SWIPE_PROGRESS,
|
||||
fromProgress, toProgress);
|
||||
swipeAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (shouldRemove) {
|
||||
((RecentsView) getParent()).onTaskDismissed(TaskView.this);
|
||||
}
|
||||
mSwipeDetector.finishedScrolling();
|
||||
}
|
||||
});
|
||||
swipeAnimator.setDuration(SwipeDetector.calculateDuration(velocity,
|
||||
Math.abs(toProgress - fromProgress)));
|
||||
swipeAnimator.setInterpolator(mSwipeAnimInterpolator);
|
||||
swipeAnimator.start();
|
||||
}
|
||||
|
||||
public void animateIconToScale(float scale) {
|
||||
ObjectAnimator.ofFloat(this, SCALE_ICON_PROPERTY, scale)
|
||||
.setDuration(SCALE_ICON_DURATION).start();
|
||||
|
||||
@@ -33,6 +33,12 @@ import java.util.List;
|
||||
*/
|
||||
public abstract class AnimatorPlaybackController implements ValueAnimator.AnimatorUpdateListener {
|
||||
|
||||
/**
|
||||
* Creates an animation controller for the provided animation.
|
||||
* The actual duration does not matter as the animation is manually controlled. It just
|
||||
* needs to be larger than the total number of pixels so that we don't have jittering due
|
||||
* to float (animation-fraction * total duration) to int conversion.
|
||||
*/
|
||||
public static AnimatorPlaybackController wrap(AnimatorSet anim, long duration) {
|
||||
|
||||
/**
|
||||
|
||||
@@ -286,6 +286,16 @@ public class SwipeDetector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the start drag was towards the positive direction or negative.
|
||||
*
|
||||
* @see #setDetectableScrollConditions(int, boolean)
|
||||
* @see #DIRECTION_BOTH
|
||||
*/
|
||||
public boolean wasInitialTouchPositive() {
|
||||
return mSubtractDisplacement < 0;
|
||||
}
|
||||
|
||||
private boolean reportDragging() {
|
||||
if (mDisplacement != mLastDisplacement) {
|
||||
if (DBG) {
|
||||
|
||||
Reference in New Issue
Block a user