Merge "Fixing touch handling on resized tasks."
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 00f484d..a4137b9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -232,6 +232,9 @@
<!-- The size of the lock-to-app button icon. -->
<dimen name="recents_lock_to_app_icon_size">28dp</dimen>
+ <!-- The amount to allow the stack to overscroll. -->
+ <dimen name="recents_stack_overscroll">24dp</dimen>
+
<!-- Space reserved for the cards behind the top card in the top stack -->
<dimen name="top_stack_peek_amount">12dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 6668df9..ebfacac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -64,8 +64,6 @@
}
public static class TaskStackView {
- public static final int TaskStackMinOverscrollRange = 32;
- public static final int TaskStackMaxOverscrollRange = 128;
public static final int FilterStartDelay = 25;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index b05e1fe..23836ab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -469,7 +469,7 @@
TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
Rect taskStackBounds = new Rect(mTaskStackBounds);
algo.setSystemInsets(systemInsets);
- algo.computeRects(windowRect.width(), windowRect.height(), taskStackBounds);
+ algo.computeRects(taskStackBounds);
Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
if (!taskViewBounds.equals(mLastTaskViewBounds)) {
mLastTaskViewBounds.set(taskViewBounds);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ParametricCurve.java b/packages/SystemUI/src/com/android/systemui/recents/misc/ParametricCurve.java
index 8e85bfc..ea6821f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/ParametricCurve.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/ParametricCurve.java
@@ -48,6 +48,7 @@
float[] xp;
float[] px;
+ float mLength;
CurveFunction mFn;
ParametricCurveFunction mScaleFn;
@@ -79,6 +80,7 @@
dx[xStep] = (float) Math.hypot(fx[xStep] - fx[xStep - 1], step);
pLength += dx[xStep];
}
+ mLength = pLength;
// Approximate p(x), a function of cumulative progress with x, normalized to 0..1
float p = 0;
px[0] = 0f;
@@ -260,4 +262,11 @@
}
return 1f - xToP(maxX, bounds);
}
+
+ /**
+ * Returns the length of this curve.
+ */
+ public float getArcLength() {
+ return mLength;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 0793180..60051b8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -170,6 +170,12 @@
}
}
+ public boolean isFreeformTask() {
+ // Temporarily disable:
+ return false;
+ // return SystemServicesProxy.isFreeformStack(key.stackId);
+ }
+
/** Notifies the callback listeners that this task has been loaded */
public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon) {
this.applicationIcon = applicationIcon;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index e04699c1..b7c1de3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -68,6 +68,7 @@
private float mInitialTouchPos;
private boolean mDragging;
+ private float mSnapBackTranslationX;
private View mCurrView;
private boolean mCanCurrViewBeDimissed;
@@ -92,6 +93,10 @@
mDensityScale = densityScale;
}
+ public void setSnapBackTranslationX(float translationX) {
+ mSnapBackTranslationX = translationX;
+ }
+
public void setPagingTouchSlop(float pagingTouchSlop) {
mPagingTouchSlop = pagingTouchSlop;
}
@@ -267,7 +272,7 @@
private void snapChild(final View view, float velocity) {
final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
- ValueAnimator anim = createTranslationAnimation(view, 0);
+ ValueAnimator anim = createTranslationAnimation(view, mSnapBackTranslationX);
int duration = SNAP_ANIM_LEN;
anim.setDuration(duration);
anim.setInterpolator(mLinearOutSlowInInterpolator);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 757e695..21ceb33 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -124,7 +124,7 @@
mConfig = RecentsConfiguration.getInstance();
mViewPool = new ViewPool<>(context, this);
mInflater = LayoutInflater.from(context);
- mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(context, mConfig);
+ mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(context);
mFilterAlgorithm = new TaskStackViewFilterAlgorithm(this, mViewPool);
mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm);
mStackScroller.setCallbacks(this);
@@ -633,10 +633,9 @@
}
/** Computes the stack and task rects */
- public void computeRects(int windowWidth, int windowHeight, Rect taskStackBounds,
- boolean launchedWithAltTab, boolean launchedFromHome) {
+ public void computeRects(Rect taskStackBounds) {
// Compute the rects in the stack algorithm
- mLayoutAlgorithm.computeRects(windowWidth, windowHeight, taskStackBounds);
+ mLayoutAlgorithm.computeRects(taskStackBounds);
// Update the scroll bounds
updateMinMaxScroll(false);
@@ -674,9 +673,7 @@
int height = MeasureSpec.getSize(heightMeasureSpec);
// Compute our stack/task rects
- RecentsActivityLaunchState launchState = mConfig.getLaunchState();
- computeRects(width, height, mTaskStackBounds, launchState.launchedWithAltTab,
- launchState.launchedFromHome);
+ computeRects(mTaskStackBounds);
// If this is the first layout, then scroll to the front of the stack and synchronize the
// stack views immediately to load all the views
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 9a5d9bd..d81f3f6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -21,6 +21,7 @@
import android.graphics.Rect;
import android.util.Log;
import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.ParametricCurve;
import com.android.systemui.recents.misc.Utilities;
@@ -32,14 +33,15 @@
/**
* The layout logic for a TaskStackView.
+ *
*/
public class TaskStackViewLayoutAlgorithm {
- private static final boolean DEBUG = false;
private static final String TAG = "TaskStackViewLayoutAlgorithm";
+ private static final boolean DEBUG = false;
// The min scale of the last task at the top of the curve
- private static final float STACK_PEEK_MIN_SCALE = 0.75f;
+ private static final float STACK_PEEK_MIN_SCALE = 0.85f;
// The scale of the last task
private static final float SINGLE_TASK_SCALE = 0.95f;
// The percentage of height of task to show between tasks
@@ -58,14 +60,17 @@
}
Context mContext;
- RecentsConfiguration mConfig;
// This is the view bounds inset exactly by the search bar, but without the bottom inset
// see RecentsConfiguration.getTaskStackBounds()
public Rect mStackRect = new Rect();
+
// This is the task view bounds for layout (untransformed), the rect is top-aligned to the top
// of the stack rect
public Rect mTaskRect = new Rect();
+
+ // The bounds of the freeform workspace, the rect is top-aligned to the top of the stack rect
+ public Rect mFreeformRect = new Rect();
// This is the current system insets
public Rect mSystemInsets = new Rect();
@@ -74,8 +79,13 @@
// The largest scroll progress, at this value, the front most task will be visible above the
// navigation bar
float mMaxScrollP;
+ // The scroll progress at which the stack scroll ends and the overscroll begins. This serves
+ // as the point at which we can show the freeform space.
+ float mMaxStackScrollP;
// The initial progress that the scroller is set
float mInitialScrollP;
+ // The task progress for the front-most task in the stack
+ float mFrontMostTaskP;
// The relative progress to ensure that the height between affiliated tasks is respected
float mWithinAffiliationPOffset;
@@ -89,11 +99,21 @@
// The relative progress to ensure that the offset from the bottom of the stack to the bottom
// of the task is respected
float mTaskBottomPOffset;
+ // The relative progress to ensure that the freeform workspace height is respected
+ float mFreeformWorkspacePOffset;
// The front-most task bottom offset
int mTaskBottomOffset;
- // The last computed task count
- int mNumTasks;
+ // The number of cells in the freeform workspace
+ int mFreeformCellXCount;
+ int mFreeformCellYCount;
+ // The width and height of the cells in the freeform workspace
+ int mFreeformCellWidth;
+ int mFreeformCellHeight;
+
+ // The last computed task counts
+ int mNumStackTasks;
+ int mNumFreeformTasks;
// The min/max z translations
int mMinTranslationZ;
int mMaxTranslationZ;
@@ -104,12 +124,11 @@
// Log function
static ParametricCurve sCurve;
- public TaskStackViewLayoutAlgorithm(Context context, RecentsConfiguration config) {
+ public TaskStackViewLayoutAlgorithm(Context context) {
Resources res = context.getResources();
mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
mContext = context;
- mConfig = config;
if (sCurve == null) {
sCurve = new ParametricCurve(new ParametricCurve.CurveFunction() {
// The large the XScale, the longer the flat area of the curve
@@ -153,23 +172,25 @@
}
/**
- * Computes the stack and task rects
+ * Computes the stack and task rects.
*/
- public void computeRects(int windowWidth, int windowHeight, Rect taskStackBounds) {
- int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * taskStackBounds.width());
+ public void computeRects(Rect taskStackBounds) {
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
int heightPadding = mContext.getResources().getDimensionPixelSize(
R.dimen.recents_stack_top_padding);
// Compute the stack rect, inset from the given task stack bounds
mStackRect.set(taskStackBounds.left + widthPadding, taskStackBounds.top + heightPadding,
- taskStackBounds.right - widthPadding, windowHeight);
+ taskStackBounds.right - widthPadding, taskStackBounds.bottom);
mTaskBottomOffset = mSystemInsets.bottom + heightPadding;
// Compute the task rect, align it to the top-center square in the stack rect
- int size = Math.min(mStackRect.width(), taskStackBounds.height() - mTaskBottomOffset);
+ int size = Math.min(mStackRect.width(), mStackRect.height() - mTaskBottomOffset);
int xOffset = (mStackRect.width() - size) / 2;
mTaskRect.set(mStackRect.left + xOffset, mStackRect.top,
mStackRect.right - xOffset, mStackRect.top + size);
+ mFreeformRect.set(mTaskRect);
// Compute the progress offsets
int withinAffiliationOffset = mContext.getResources().getDimensionPixelSize(
@@ -184,9 +205,12 @@
mTaskHalfHeightPOffset = sCurve.computePOffsetForScaledHeight(mTaskRect.height() / 2,
mStackRect);
mTaskBottomPOffset = sCurve.computePOffsetForHeight(mTaskBottomOffset, mStackRect);
+ mFreeformWorkspacePOffset = sCurve.computePOffsetForHeight(mFreeformRect.height(),
+ mStackRect);
if (DEBUG) {
Log.d(TAG, "computeRects");
+ Log.d(TAG, "\tarclength: " + sCurve.getArcLength());
Log.d(TAG, "\tmStackRect: " + mStackRect);
Log.d(TAG, "\tmTaskRect: " + mTaskRect);
Log.d(TAG, "\tmSystemInsets: " + mSystemInsets);
@@ -222,29 +246,38 @@
// Clear the progress map
mTaskProgressMap.clear();
- mNumTasks = tasks.size();
// Return early if we have no tasks
if (tasks.isEmpty()) {
- mMinScrollP = mMaxScrollP = 0;
+ mMinScrollP = mMaxScrollP = mMaxStackScrollP = 0;
+ mNumStackTasks = mNumFreeformTasks = 0;
return;
}
- // We calculate the progress by taking the progress of the element from the bottom of the
- // screen
- if (mNumTasks == 1) {
- // Just center the task in the visible stack rect
- mMinScrollP = mMaxScrollP = mInitialScrollP = 0f;
- mTaskProgressMap.put(tasks.get(0).key, 0f);
- } else {
- // Update the tasks from back to front with the new progresses. We set the initial
- // progress to the progress at which the top of the last task is near the center of the
- // visible stack rect.
+ // Filter the set of freeform and stack tasks
+ ArrayList<Task> freeformTasks = new ArrayList<>();
+ ArrayList<Task> stackTasks = new ArrayList<>();
+ for (int i = 0; i < tasks.size(); i++) {
+ Task task = tasks.get(i);
+ if (task.isFreeformTask()) {
+ freeformTasks.add(task);
+ } else {
+ stackTasks.add(task);
+ }
+ }
+ mNumStackTasks = stackTasks.size();
+ mNumFreeformTasks = freeformTasks.size();
+
+ // TODO: In the case where there is only freeform tasks, then the scrolls should be set to
+ // zero
+
+ if (!stackTasks.isEmpty()) {
+ // Update the for each task from back to front.
float pAtBackMostTaskTop = 0;
float pAtFrontMostTaskTop = pAtBackMostTaskTop;
- int taskCount = tasks.size();
+ int taskCount = stackTasks.size();
for (int i = 0; i < taskCount; i++) {
- Task task = tasks.get(i);
+ Task task = stackTasks.get(i);
mTaskProgressMap.put(task.key, pAtFrontMostTaskTop);
if (i < (taskCount - 1)) {
@@ -255,15 +288,47 @@
}
}
- // Set the max scroll progress to the point at which the bottom of the front-most task
- // is aligned to the bottom of the stack (including nav bar and stack padding)
- mMaxScrollP = pAtFrontMostTaskTop - 1f + mTaskBottomPOffset + mTaskHeightPOffset;
+ mFrontMostTaskP = pAtFrontMostTaskTop;
+ // Set the max scroll progress to the point at which the top of the front-most task
+ // is aligned to the bottom of the stack (offset by nav bar, padding, and task height)
+ mMaxStackScrollP = getBottomAlignedScrollProgress(pAtFrontMostTaskTop,
+ mTaskBottomPOffset + mTaskHeightPOffset);
// Basically align the back-most task such that its progress is the same as the top of
- // the front most task at the max scroll
- mMinScrollP = pAtBackMostTaskTop - 1f + mTaskBottomPOffset + mTaskHeightPOffset;
- // The offset the inital scroll position to the front of the stack, with half the front
- // task height visible
- mInitialScrollP = Math.max(mMinScrollP, mMaxScrollP - mTaskHalfHeightPOffset);
+ // the front most task at the max stack scroll
+ mMinScrollP = getBottomAlignedScrollProgress(pAtBackMostTaskTop,
+ mTaskBottomPOffset + mTaskHeightPOffset);
+ }
+
+ if (!freeformTasks.isEmpty()) {
+ // Calculate the cell width/height depending on the number of freeform tasks
+ mFreeformCellXCount = Math.max(2, (int) Math.ceil(Math.sqrt(mNumFreeformTasks)));
+ mFreeformCellYCount = Math.max(2, (int) Math.ceil((float) mNumFreeformTasks / mFreeformCellXCount));
+ mFreeformCellWidth = mFreeformRect.width() / mFreeformCellXCount;
+ mFreeformCellHeight = mFreeformRect.height() / mFreeformCellYCount;
+
+ // Put each of the tasks in the progress map at a fixed index (does not need to actually
+ // map to a scroll position, just by index)
+ int taskCount = freeformTasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = freeformTasks.get(i);
+ mTaskProgressMap.put(task.key, (mFrontMostTaskP + 1) + i);
+ }
+
+ // The max scroll includes the freeform workspace offset. As the scroll progress exceeds
+ // mMaxStackScrollP up to mMaxScrollP, the stack will translate upwards and the freeform
+ // workspace will be visible
+ mMaxScrollP = mMaxStackScrollP + mFreeformWorkspacePOffset;
+ mInitialScrollP = mMaxScrollP;
+ } else {
+ mMaxScrollP = mMaxStackScrollP;
+ mInitialScrollP = Math.max(mMinScrollP, mMaxStackScrollP - mTaskHalfHeightPOffset);
+ }
+ if (DEBUG) {
+ Log.d(TAG, "mNumStackTasks: " + mNumStackTasks);
+ Log.d(TAG, "mNumFreeformTasks: " + mNumFreeformTasks);
+ Log.d(TAG, "mMinScrollP: " + mMinScrollP);
+ Log.d(TAG, "mMaxStackScrollP: " + mMaxStackScrollP);
+ Log.d(TAG, "mMaxScrollP: " + mMaxScrollP);
}
}
@@ -272,11 +337,24 @@
* computeMinMaxScroll() is called first.
*/
public VisibilityReport computeStackVisibilityReport(ArrayList<Task> tasks) {
+ // Ensure minimum visibility count
if (tasks.size() <= 1) {
return new VisibilityReport(1, 1);
}
- // Walk backwards in the task stack and count the number of tasks and visible thumbnails
+ // If there are freeform tasks, then they will be the only ones visible
+ int freeformTaskCount = 0;
+ for (Task t : tasks) {
+ if (t.isFreeformTask()) {
+ freeformTaskCount++;
+ }
+ }
+ if (freeformTaskCount > 0) {
+ return new VisibilityReport(freeformTaskCount, freeformTaskCount);
+ }
+
+ // Otherwise, walk backwards in the stack and count the number of tasks and visible
+ // thumbnails
int taskHeight = mTaskRect.height();
int taskBarHeight = mContext.getResources().getDimensionPixelSize(
R.dimen.recents_task_bar_height);
@@ -338,18 +416,38 @@
/** Update/get the transform */
public TaskViewTransform getStackTransform(float taskProgress, float stackScroll,
TaskViewTransform transformOut, TaskViewTransform prevTransform) {
- if (DEBUG) {
- Log.d(TAG, "getStackTransform: " + stackScroll);
+ float stackOverscroll = (stackScroll - mMaxStackScrollP) / mFreeformWorkspacePOffset;
+ int overscrollYOffset = 0;
+ if (mNumFreeformTasks > 0) {
+ overscrollYOffset = (int) (Math.max(0, stackOverscroll) * mFreeformRect.height());
}
- if (mNumTasks == 1) {
+ if ((mNumFreeformTasks > 0) && (stackScroll > mMaxStackScrollP) &&
+ (taskProgress > mFrontMostTaskP)) {
+ // This is a freeform task, so lay it out in the freeform workspace
+ int taskIndex = Math.round(taskProgress - (mFrontMostTaskP + 1));
+ int x = taskIndex % mFreeformCellXCount;
+ int y = taskIndex / mFreeformCellXCount;
+ int frontTaskBottom = mStackRect.height() - mTaskBottomOffset;
+ float scale = (float) mFreeformCellWidth / mTaskRect.width();
+ int scaleXOffset = (int) (((1f - scale) * mTaskRect.width()) / 2);
+ int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
+ transformOut.scale = scale;
+ transformOut.translationX = x * mFreeformCellWidth - scaleXOffset;
+ transformOut.translationY = frontTaskBottom - overscrollYOffset +
+ (y * mFreeformCellHeight) - scaleYOffset;
+ transformOut.visible = true;
+ return transformOut;
+
+ } else if (mNumStackTasks == 1) {
// Center the task in the stack, changing the scale will not follow the curve, but just
// modulate some values directly
- float pTaskRelative = -stackScroll;
+ float pTaskRelative = mMinScrollP - stackScroll;
float scale = SINGLE_TASK_SCALE;
int topOffset = (mStackRect.height() - mTaskBottomOffset - mTaskRect.height()) / 2;
transformOut.scale = scale;
- transformOut.translationY = (int) (topOffset + (pTaskRelative * mStackRect.height()));
+ transformOut.translationY = (int) (topOffset + (pTaskRelative * mStackRect.height())) -
+ overscrollYOffset;
transformOut.translationZ = mMaxTranslationZ;
transformOut.rect.set(mTaskRect);
transformOut.rect.offset(0, transformOut.translationY);
@@ -357,8 +455,12 @@
transformOut.visible = true;
transformOut.p = pTaskRelative;
return transformOut;
+
} else {
float pTaskRelative = taskProgress - stackScroll;
+ if (mNumFreeformTasks > 0) {
+ pTaskRelative = Math.min(mMaxStackScrollP, pTaskRelative);
+ }
float pBounded = Math.max(0, Math.min(pTaskRelative, 1f));
// If the task top is outside of the bounds below the screen, then immediately reset it
if (pTaskRelative > 1f) {
@@ -379,7 +481,7 @@
int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
transformOut.scale = scale;
transformOut.translationY = sCurve.pToX(pBounded, mStackRect) - mStackRect.top -
- scaleYOffset;
+ scaleYOffset - overscrollYOffset;
transformOut.translationZ = Math.max(mMinTranslationZ,
mMinTranslationZ + (pBounded * (mMaxTranslationZ - mMinTranslationZ)));
transformOut.rect.set(mTaskRect);
@@ -392,6 +494,27 @@
}
/**
+ * Update/get the transform
+ */
+ public TaskViewTransform getFreeformWorkspaceBounds(float stackScroll,
+ TaskViewTransform transformOut) {
+ transformOut.reset();
+ if (mNumFreeformTasks == 0) {
+ return transformOut;
+ }
+
+ if (stackScroll > mMaxStackScrollP) {
+ float stackOverscroll = (stackScroll - mMaxStackScrollP) / mFreeformWorkspacePOffset;
+ int overscrollYOffset = (int) (stackOverscroll * mFreeformRect.height());
+ int frontTaskBottom = mStackRect.height() - mTaskBottomOffset;
+ transformOut.visible = true;
+ transformOut.alpha =
+ transformOut.translationY = frontTaskBottom - overscrollYOffset;
+ }
+ return transformOut;
+ }
+
+ /**
* Returns the untransformed task view bounds.
*/
public Rect getUntransformedTaskViewBounds() {
@@ -406,4 +529,29 @@
if (!mTaskProgressMap.containsKey(t.key)) return 0f;
return mTaskProgressMap.get(t.key);
}
+
+ /**
+ * Maps a movement in screen y, relative to {@param downY}, to a movement in along the arc
+ * length of the curve. We know the curve is mostly flat, so we just map the length of the
+ * screen along the arc-length proportionally (1/arclength).
+ */
+ public float getDeltaPForY(int downY, int y) {
+ float deltaP = (float) (y - downY) / mStackRect.height() * (1f / sCurve.getArcLength());
+ return -deltaP;
+ }
+
+ /**
+ * This is the inverse of {@link #getDeltaPForY}. Given a movement along the arc length
+ * of the curve, map back to the screen y.
+ */
+ public int getYForDeltaP(float downScrollP, float p) {
+ int y = (int) ((p - downScrollP) * mStackRect.height() * sCurve.getArcLength());
+ return -y;
+ }
+
+ private float getBottomAlignedScrollProgress(float p, float pOffsetFromBottom) {
+ // At scroll progress == p, then p is at the top of the stack
+ // At scroll progress == p + 1, then p is at the bottom of the stack
+ return p - (1 - pOffsetFromBottom);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 3d3b13d..15fcab4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -21,6 +21,7 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.util.Log;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.OverScroller;
@@ -29,8 +30,12 @@
/* The scrolling logic for a TaskStackView */
public class TaskStackViewScroller {
+
+ private static final String TAG = "TaskStackViewScroller";
+ private static final boolean DEBUG = false;
+
public interface TaskStackViewScrollerCallbacks {
- public void onScrollChanged(float p);
+ void onScrollChanged(float p);
}
Context mContext;
@@ -38,6 +43,8 @@
TaskStackViewScrollerCallbacks mCb;
float mStackScrollP;
+ float mFlingDownScrollP;
+ int mFlingDownY;
OverScroller mScroller;
ObjectAnimator mScrollAnimator;
@@ -77,11 +84,6 @@
}
}
- /** Sets the current stack scroll without calling the callback. */
- void setStackScrollRaw(float s) {
- mStackScrollP = s;
- }
-
/**
* Sets the current stack scroll to the initial state when you first enter recents.
* @return whether the stack progress changed.
@@ -92,6 +94,20 @@
return Float.compare(prevStackScrollP, mStackScrollP) != 0;
}
+ /**
+ * Starts a fling that is coordinated with the {@link TaskStackViewTouchHandler}.
+ */
+ public void fling(float downScrollP, int downY, int y, int velY, int minY, int maxY,
+ int overscroll) {
+ if (DEBUG) {
+ Log.d(TAG, "fling: " + downScrollP + ", downY: " + downY + ", y: " + y +
+ ", velY: " + velY + ", minY: " + minY + ", maxY: " + maxY);
+ }
+ mFlingDownScrollP = downScrollP;
+ mFlingDownY = downY;
+ mScroller.fling(0, y, 0, velY, 0, 0, minY, maxY, 0, overscroll);
+ }
+
/** Bounds the current scroll if necessary */
public boolean boundScroll() {
float curScroll = getStackScroll();
@@ -174,21 +190,20 @@
/**** OverScroller ****/
+ // TODO: Remove
+ @Deprecated
int progressToScrollRange(float p) {
return (int) (p * mLayoutAlgorithm.mStackRect.height());
}
- float scrollRangeToProgress(int s) {
- return (float) s / mLayoutAlgorithm.mStackRect.height();
- }
-
/** Called from the view draw, computes the next scroll. */
boolean computeScroll() {
if (mScroller.computeScrollOffset()) {
- float scroll = scrollRangeToProgress(mScroller.getCurrY());
- setStackScrollRaw(scroll);
- if (mCb != null) {
- mCb.onScrollChanged(scroll);
+ float deltaP = mLayoutAlgorithm.getDeltaPForY(mFlingDownY, mScroller.getCurrY());
+ float scroll = mFlingDownScrollP + deltaP;
+ setStackScroll(scroll);
+ if (DEBUG) {
+ Log.d(TAG, "computeScroll: " + scroll);
}
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 3a1a987..08889c5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.views;
import android.content.Context;
+import android.content.res.Resources;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -34,7 +35,11 @@
/* Handles touch events for a TaskStackView. */
class TaskStackViewTouchHandler implements SwipeHelper.Callback {
- static int INACTIVE_POINTER_ID = -1;
+
+ private static final String TAG = "TaskStackViewTouchHandler";
+ private static final boolean DEBUG = true;
+
+ private static int INACTIVE_POINTER_ID = -1;
Context mContext;
TaskStackView mSv;
@@ -42,21 +47,16 @@
VelocityTracker mVelocityTracker;
boolean mIsScrolling;
-
- float mInitialP;
- float mLastP;
- float mTotalPMotion;
- int mInitialMotionX, mInitialMotionY;
- int mLastMotionX, mLastMotionY;
+ float mDownScrollP;
+ int mDownX, mDownY;
int mActivePointerId = INACTIVE_POINTER_ID;
+ int mOverscrollSize;
TaskView mActiveTaskView = null;
int mMinimumVelocity;
int mMaximumVelocity;
// The scroll touch slop is used to calculate when we start scrolling
int mScrollTouchSlop;
- // The page touch slop is used to calculate when we start swiping
- float mPagingTouchSlop;
// Used to calculate when a tap is outside a task view rectangle.
final int mWindowTouchSlop;
@@ -65,18 +65,20 @@
public TaskStackViewTouchHandler(Context context, TaskStackView sv,
TaskStackViewScroller scroller) {
- mContext = context;
+ Resources res = context.getResources();
ViewConfiguration configuration = ViewConfiguration.get(context);
+ mContext = context;
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
mScrollTouchSlop = configuration.getScaledTouchSlop();
- mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
mSv = sv;
mScroller = scroller;
- float densityScale = context.getResources().getDisplayMetrics().density;
- mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale, mPagingTouchSlop);
+ float densityScale = res.getDisplayMetrics().density;
+ mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_stack_overscroll);
+ mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale,
+ configuration.getScaledPagingTouchSlop());
mSwipeHelper.setMinAlpha(1f);
}
@@ -88,11 +90,6 @@
mVelocityTracker.clear();
}
}
- void initVelocityTrackerIfNotExists() {
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- }
void recycleVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
@@ -115,175 +112,70 @@
return null;
}
- /** Constructs a simulated motion event for the current stack scroll. */
- MotionEvent createMotionEventForStackScroll(MotionEvent ev) {
- MotionEvent pev = MotionEvent.obtainNoHistory(ev);
- pev.setLocation(0, mScroller.progressToScrollRange(mScroller.getStackScroll()));
- return pev;
- }
-
/** Touch preprocessing for handling below */
public boolean onInterceptTouchEvent(MotionEvent ev) {
- // Return early if we have no children
- boolean hasTaskViews = (mSv.getTaskViews().size() > 0);
- if (!hasTaskViews) {
- return false;
- }
-
// Pass through to swipe helper if we are swiping
mInterceptedBySwipeHelper = mSwipeHelper.onInterceptTouchEvent(ev);
if (mInterceptedBySwipeHelper) {
return true;
}
- TaskStackViewLayoutAlgorithm layoutAlgorithm = mSv.mLayoutAlgorithm;
- boolean wasScrolling = mScroller.isScrolling() ||
- (mScroller.mScrollAnimator != null && mScroller.mScrollAnimator.isRunning());
- int action = ev.getAction();
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN: {
- // Save the touch down info
- mInitialMotionX = mLastMotionX = (int) ev.getX();
- mInitialMotionY = mLastMotionY = (int) ev.getY();
- mInitialP = mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY,
- layoutAlgorithm.mStackRect);
- mActivePointerId = ev.getPointerId(0);
- mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY);
- // Stop the current scroll if it is still flinging
- mScroller.stopScroller();
- mScroller.stopBoundScrollAnimation();
- // Initialize the velocity tracker
- initOrResetVelocityTracker();
- mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
- break;
- }
- case MotionEvent.ACTION_POINTER_DOWN: {
- final int index = ev.getActionIndex();
- mActivePointerId = ev.getPointerId(index);
- mLastMotionX = (int) ev.getX(index);
- mLastMotionY = (int) ev.getY(index);
- mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
- break;
- }
- case MotionEvent.ACTION_MOVE: {
- if (mActivePointerId == INACTIVE_POINTER_ID) break;
-
- // Initialize the velocity tracker if necessary
- initVelocityTrackerIfNotExists();
- mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
-
- int activePointerIndex = ev.findPointerIndex(mActivePointerId);
- int y = (int) ev.getY(activePointerIndex);
- int x = (int) ev.getX(activePointerIndex);
- if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) {
- // Save the touch move info
- mIsScrolling = true;
- // Disallow parents from intercepting touch events
- final ViewParent parent = mSv.getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- }
-
- mLastMotionX = x;
- mLastMotionY = y;
- mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
- break;
- }
- case MotionEvent.ACTION_POINTER_UP: {
- int pointerIndex = ev.getActionIndex();
- int pointerId = ev.getPointerId(pointerIndex);
- if (pointerId == mActivePointerId) {
- // Select a new active pointer id and reset the motion state
- final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
- mActivePointerId = ev.getPointerId(newPointerIndex);
- mLastMotionX = (int) ev.getX(newPointerIndex);
- mLastMotionY = (int) ev.getY(newPointerIndex);
- mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
- mVelocityTracker.clear();
- }
- break;
- }
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP: {
- // Animate the scroll back if we've cancelled
- mScroller.animateBoundScroll();
- // Reset the drag state and the velocity tracker
- mIsScrolling = false;
- mActivePointerId = INACTIVE_POINTER_ID;
- mActiveTaskView = null;
- mTotalPMotion = 0;
- recycleVelocityTracker();
- break;
- }
- }
-
- return wasScrolling || mIsScrolling;
+ return handleTouchEvent(ev);
}
/** Handles touch events once we have intercepted them */
public boolean onTouchEvent(MotionEvent ev) {
- // Short circuit if we have no children
- boolean hasTaskViews = (mSv.getTaskViews().size() > 0);
- if (!hasTaskViews) {
- return false;
- }
-
// Pass through to swipe helper if we are swiping
if (mInterceptedBySwipeHelper && mSwipeHelper.onTouchEvent(ev)) {
return true;
}
- // Update the velocity tracker
- initVelocityTrackerIfNotExists();
+ handleTouchEvent(ev);
+ return true;
+ }
+
+ private boolean handleTouchEvent(MotionEvent ev) {
+ // Short circuit if we have no children
+ if (mSv.getTaskViews().size() == 0) {
+ return false;
+ }
TaskStackViewLayoutAlgorithm layoutAlgorithm = mSv.mLayoutAlgorithm;
int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
// Save the touch down info
- mInitialMotionX = mLastMotionX = (int) ev.getX();
- mInitialMotionY = mLastMotionY = (int) ev.getY();
- mInitialP = mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY,
- layoutAlgorithm.mStackRect);
+ mDownX = (int) ev.getX();
+ mDownY = (int) ev.getY();
+ mDownScrollP = mScroller.getStackScroll();
mActivePointerId = ev.getPointerId(0);
- mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY);
+ mActiveTaskView = findViewAtPoint(mDownX, mDownY);
+
// Stop the current scroll if it is still flinging
mScroller.stopScroller();
mScroller.stopBoundScrollAnimation();
+
// Initialize the velocity tracker
initOrResetVelocityTracker();
- mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
- // Disallow parents from intercepting touch events
- final ViewParent parent = mSv.getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
+ mVelocityTracker.addMovement(ev);
break;
}
case MotionEvent.ACTION_POINTER_DOWN: {
final int index = ev.getActionIndex();
+ mDownX = (int) ev.getX();
+ mDownY = (int) ev.getY();
+ mDownScrollP = mScroller.getStackScroll();
mActivePointerId = ev.getPointerId(index);
- mLastMotionX = (int) ev.getX(index);
- mLastMotionY = (int) ev.getY(index);
- mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY,
- layoutAlgorithm.mStackRect);
+ mVelocityTracker.addMovement(ev);
break;
}
case MotionEvent.ACTION_MOVE: {
- if (mActivePointerId == INACTIVE_POINTER_ID) break;
-
- mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
-
int activePointerIndex = ev.findPointerIndex(mActivePointerId);
- int x = (int) ev.getX(activePointerIndex);
int y = (int) ev.getY(activePointerIndex);
- int yTotal = Math.abs(y - mInitialMotionY);
- float curP = layoutAlgorithm.sCurve.xToP(y, layoutAlgorithm.mStackRect);
- float deltaP = mLastP - curP;
if (!mIsScrolling) {
- if (yTotal > mScrollTouchSlop) {
+ if (Math.abs(y - mDownY) > mScrollTouchSlop) {
mIsScrolling = true;
+
// Disallow parents from intercepting touch events
final ViewParent parent = mSv.getParent();
if (parent != null) {
@@ -292,54 +184,14 @@
}
}
if (mIsScrolling) {
- float curStackScroll = mScroller.getStackScroll();
- float overScrollAmount = mScroller.getScrollAmountOutOfBounds(curStackScroll + deltaP);
- if (Float.compare(overScrollAmount, 0f) != 0) {
- // Bound the overscroll to a fixed amount, and inversely scale the y-movement
- // relative to how close we are to the max overscroll
- float maxOverScroll = mContext.getResources().getFloat(
- R.dimen.recents_stack_overscroll_percentage);
- deltaP *= (1f - (Math.min(maxOverScroll, overScrollAmount)
- / maxOverScroll));
- }
- mScroller.setStackScroll(curStackScroll + deltaP);
- }
- mLastMotionX = x;
- mLastMotionY = y;
- mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
- mTotalPMotion += Math.abs(deltaP);
- break;
- }
- case MotionEvent.ACTION_UP: {
- mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- int velocity = (int) mVelocityTracker.getYVelocity(mActivePointerId);
- if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) {
- float overscrollRangePct = Math.abs((float) velocity / mMaximumVelocity);
- int overscrollRange = (int) (Math.min(1f, overscrollRangePct) *
- (Constants.Values.TaskStackView.TaskStackMaxOverscrollRange -
- Constants.Values.TaskStackView.TaskStackMinOverscrollRange));
- mScroller.mScroller.fling(0,
- mScroller.progressToScrollRange(mScroller.getStackScroll()),
- 0, velocity,
- 0, 0,
- mScroller.progressToScrollRange(mSv.mLayoutAlgorithm.mMinScrollP),
- mScroller.progressToScrollRange(mSv.mLayoutAlgorithm.mMaxScrollP),
- 0, Constants.Values.TaskStackView.TaskStackMinOverscrollRange +
- overscrollRange);
- // Invalidate to kick off computeScroll
- mSv.invalidate();
- } else if (mIsScrolling && mScroller.isScrollOutOfBounds()) {
- // Animate the scroll back into bounds
- mScroller.animateBoundScroll();
- } else if (mActiveTaskView == null) {
- // This tap didn't start on a task.
- maybeHideRecentsFromBackgroundTap((int) ev.getX(), (int) ev.getY());
+ // If we just move linearly on the screen, then that would map to 1/arclength
+ // of the curve, so just move the scroll proportional to that
+ float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y);
+ float curScrollP = mDownScrollP + deltaP;
+ mScroller.setStackScroll(curScrollP);
}
- mActivePointerId = INACTIVE_POINTER_ID;
- mIsScrolling = false;
- mTotalPMotion = 0;
- recycleVelocityTracker();
+ mVelocityTracker.addMovement(ev);
break;
}
case MotionEvent.ACTION_POINTER_UP: {
@@ -349,11 +201,41 @@
// Select a new active pointer id and reset the motion state
final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
- mLastMotionX = (int) ev.getX(newPointerIndex);
- mLastMotionY = (int) ev.getY(newPointerIndex);
- mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
- mVelocityTracker.clear();
}
+ mVelocityTracker.addMovement(ev);
+ break;
+ }
+ case MotionEvent.ACTION_UP: {
+ mVelocityTracker.addMovement(ev);
+ mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+ int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+ int y = (int) ev.getY(activePointerIndex);
+ int velocity = (int) mVelocityTracker.getYVelocity(mActivePointerId);
+ if (mIsScrolling) {
+ if (mScroller.isScrollOutOfBounds()) {
+ // Animate the scroll back into bounds
+ mScroller.animateBoundScroll();
+ } else if (Math.abs(velocity) > mMinimumVelocity) {
+ float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y);
+ float curScrollP = mDownScrollP + deltaP;
+ float downToCurY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
+ curScrollP);
+ float downToMinY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
+ layoutAlgorithm.mMaxScrollP);
+ float downToMaxY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
+ layoutAlgorithm.mMinScrollP);
+ mScroller.fling(mDownScrollP, mDownY, (int) downToCurY, velocity,
+ (int) downToMinY, (int) downToMaxY, mOverscrollSize);
+ mSv.invalidate();
+ }
+ } else if (mActiveTaskView == null) {
+ // This tap didn't start on a task.
+ maybeHideRecentsFromBackgroundTap((int) ev.getX(), (int) ev.getY());
+ }
+
+ mActivePointerId = INACTIVE_POINTER_ID;
+ mIsScrolling = false;
+ recycleVelocityTracker();
break;
}
case MotionEvent.ACTION_CANCEL: {
@@ -363,20 +245,19 @@
}
mActivePointerId = INACTIVE_POINTER_ID;
mIsScrolling = false;
- mTotalPMotion = 0;
recycleVelocityTracker();
break;
}
}
- return true;
+ return mIsScrolling;
}
/** Hides recents if the up event at (x, y) is a tap on the background area. */
void maybeHideRecentsFromBackgroundTap(int x, int y) {
// Ignore the up event if it's too far from its start position. The user might have been
// trying to scroll or swipe.
- int dx = Math.abs(mInitialMotionX - x);
- int dy = Math.abs(mInitialMotionY - y);
+ int dx = Math.abs(mDownX - x);
+ int dy = Math.abs(mDownY - y);
if (dx > mScrollTouchSlop || dy > mScrollTouchSlop) {
return;
}
@@ -427,12 +308,16 @@
@Override
public boolean canChildBeDismissed(View v) {
+ if (v instanceof TaskView) {
+ return !((TaskView) v).getTask().isFreeformTask();
+ }
return true;
}
@Override
public void onBeginDrag(View v) {
TaskView tv = (TaskView) v;
+ mSwipeHelper.setSnapBackTranslationX(tv.getTranslationX());
// Disable clipping with the stack while we are swiping
tv.setClipViewInStack(false);
// Disallow touch events from this task view
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index ec50eb6..174ff33 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -26,6 +26,7 @@
/* The transform state for a task view */
public class TaskViewTransform {
public int startDelay = 0;
+ public int translationX = 0;
public int translationY = 0;
public float translationZ = 0;
public float scale = 1f;
@@ -43,6 +44,7 @@
public TaskViewTransform(TaskViewTransform o) {
startDelay = o.startDelay;
+ translationX = o.translationX;
translationY = o.translationY;
translationZ = o.translationZ;
scale = o.scale;
@@ -52,9 +54,12 @@
p = o.p;
}
- /** Resets the current transform */
+ /**
+ * Resets the current transform.
+ */
public void reset() {
startDelay = 0;
+ translationX = 0;
translationY = 0;
translationZ = 0;
scale = 1f;
@@ -71,6 +76,9 @@
public boolean hasScaleChangedFrom(float v) {
return (Float.compare(scale, v) != 0);
}
+ public boolean hasTranslationXChangedFrom(float v) {
+ return (Float.compare(translationX, v) != 0);
+ }
public boolean hasTranslationYChangedFrom(float v) {
return (Float.compare(translationY, v) != 0);
}
@@ -87,6 +95,9 @@
boolean requiresLayers = false;
// Animate to the final state
+ if (hasTranslationXChangedFrom(v.getTranslationX())) {
+ anim.translationX(translationX);
+ }
if (hasTranslationYChangedFrom(v.getTranslationY())) {
anim.translationY(translationY);
}
@@ -117,6 +128,9 @@
.start();
} else {
// Set the changed properties
+ if (hasTranslationXChangedFrom(v.getTranslationX())) {
+ v.setTranslationX(translationX);
+ }
if (hasTranslationYChangedFrom(v.getTranslationY())) {
v.setTranslationY(translationY);
}
@@ -147,7 +161,8 @@
@Override
public String toString() {
- return "TaskViewTransform delay: " + startDelay + " y: " + translationY + " z: " + translationZ +
+ return "TaskViewTransform delay: " + startDelay +
+ " x: " + translationX + " y: " + translationY + " z: " + translationZ +
" scale: " + scale + " alpha: " + alpha + " visible: " + visible + " rect: " + rect +
" p: " + p;
}