diff options
3 files changed, 79 insertions, 70 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index 88bebdbf173b..e67b75f263dc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -16,20 +16,16 @@ package com.android.systemui.recents.views; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Path; import android.graphics.Rect; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.FloatProperty; -import android.util.Property; +import android.util.SparseArray; +import android.util.SparseIntArray; import android.view.ViewDebug; -import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivityLaunchState; @@ -135,11 +131,11 @@ public class TaskStackLayoutAlgorithm { new FreePathInterpolator(FOCUSED_DIM_PATH); // The various focus states - public static final float STATE_FOCUSED = 1f; - public static final float STATE_UNFOCUSED = 0f; + public static final int STATE_FOCUSED = 1; + public static final int STATE_UNFOCUSED = 0; public interface TaskStackLayoutAlgorithmCallbacks { - void onFocusStateChanged(float prevFocusState, float curFocusState); + void onFocusStateChanged(int prevFocusState, int curFocusState); } /** @@ -209,24 +205,6 @@ public class TaskStackLayoutAlgorithm { } } - /** - * A Property wrapper around the <code>focusState</code> functionality handled by the - * {@link TaskStackLayoutAlgorithm#setFocusState(float)} and - * {@link TaskStackLayoutAlgorithm#getFocusState()} methods. - */ - private static final Property<TaskStackLayoutAlgorithm, Float> FOCUS_STATE = - new FloatProperty<TaskStackLayoutAlgorithm>("focusState") { - @Override - public void setValue(TaskStackLayoutAlgorithm object, float value) { - object.setFocusState(value); - } - - @Override - public Float get(TaskStackLayoutAlgorithm object) { - return object.getFocusState(); - } - }; - // A report of the visibility state of the stack public class VisibilityReport { public int numVisibleTasks; @@ -289,10 +267,7 @@ public class TaskStackLayoutAlgorithm { // The state of the stack focus (0..1), which controls the transition of the stack from the // focused to non-focused state @ViewDebug.ExportedProperty(category="recents") - private float mFocusState; - - // The animator used to reset the focused state - private ObjectAnimator mFocusStateAnimator; + private int mFocusState; // The smallest scroll progress, at this value, the back most task will be visible @ViewDebug.ExportedProperty(category="recents") @@ -321,7 +296,8 @@ public class TaskStackLayoutAlgorithm { int mMaxTranslationZ; // Optimization, allows for quick lookup of task -> index - private ArrayMap<Task.TaskKey, Integer> mTaskIndexMap = new ArrayMap<>(); + private SparseIntArray mTaskIndexMap = new SparseIntArray(); + private SparseArray<Float> mTaskIndexOverrideMap = new SparseArray<>(); // The freeform workspace layout FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm; @@ -354,6 +330,7 @@ public class TaskStackLayoutAlgorithm { * Resets this layout when the stack view is reset. */ public void reset() { + mTaskIndexOverrideMap.clear(); setFocusState(getDefaultFocusState()); } @@ -367,8 +344,8 @@ public class TaskStackLayoutAlgorithm { /** * Sets the focused state. */ - public void setFocusState(float focusState) { - float prevFocusState = mFocusState; + public void setFocusState(int focusState) { + int prevFocusState = mFocusState; mFocusState = focusState; updateFrontBackTransforms(); if (mCb != null) { @@ -379,7 +356,7 @@ public class TaskStackLayoutAlgorithm { /** * Gets the focused state. */ - public float getFocusState() { + public int getFocusState() { return mFocusState; } @@ -469,7 +446,7 @@ public class TaskStackLayoutAlgorithm { int taskCount = stackTasks.size(); for (int i = 0; i < taskCount; i++) { Task task = stackTasks.get(i); - mTaskIndexMap.put(task.key, i); + mTaskIndexMap.put(task.key.id, i); } // Calculate the min/max scroll @@ -516,35 +493,56 @@ public class TaskStackLayoutAlgorithm { } /** - * Updates this stack when a scroll happens. + * Adds and override task progress for the given task when transitioning from focused to + * unfocused state. */ - public void updateFocusStateOnScroll(int yMovement) { - Utilities.cancelAnimationWithoutCallbacks(mFocusStateAnimator); - if (mFocusState > STATE_UNFOCUSED) { - float delta = (float) yMovement / (UNFOCUS_MULTIPLIER * mStackRect.height()); - setFocusState(mFocusState - Math.min(mFocusState, Math.abs(delta))); + public void addUnfocusedTaskOverride(Task task, float stackScroll) { + if (mFocusState != STATE_UNFOCUSED) { + mFocusedRange.offset(stackScroll); + mUnfocusedRange.offset(stackScroll); + float focusedRangeX = mFocusedRange.getNormalizedX(mTaskIndexMap.get(task.key.id)); + float focusedY = mFocusedCurveInterpolator.getInterpolation(focusedRangeX); + float unfocusedRangeX = mUnfocusedCurveInterpolator.getX(focusedY); + float unfocusedTaskProgress = stackScroll + mUnfocusedRange.getAbsoluteX(unfocusedRangeX); + if (Float.compare(focusedRangeX, unfocusedRangeX) != 0) { + mTaskIndexOverrideMap.put(task.key.id, unfocusedTaskProgress); + } } } /** - * Aniamtes the focused state back to its orginal state. + * Updates this stack when a scroll happens. */ - public void animateFocusState(float newState) { - Utilities.cancelAnimationWithoutCallbacks(mFocusStateAnimator); - if (Float.compare(newState, getFocusState()) != 0) { - mFocusStateAnimator = ObjectAnimator.ofFloat(this, FOCUS_STATE, getFocusState(), - newState); - mFocusStateAnimator.setDuration(mContext.getResources().getInteger( - R.integer.recents_animate_task_stack_scroll_duration)); - mFocusStateAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); - mFocusStateAnimator.start(); + public void updateFocusStateOnScroll(float stackScroll, float deltaScroll) { + for (int i = mTaskIndexOverrideMap.size() - 1; i >= 0; i--) { + int taskId = mTaskIndexOverrideMap.keyAt(i); + float x = mTaskIndexMap.get(taskId); + float overrideX = mTaskIndexOverrideMap.get(taskId, 0f); + float newOverrideX = overrideX + deltaScroll; + mUnfocusedRange.offset(stackScroll); + boolean outOfBounds = mUnfocusedRange.getNormalizedX(newOverrideX) < 0f || + mUnfocusedRange.getNormalizedX(newOverrideX) > 1f; + if (outOfBounds || (overrideX >= x && x >= newOverrideX) || + (overrideX <= x && x <= newOverrideX)) { + // Remove the override once we reach the original task index + mTaskIndexOverrideMap.removeAt(i); + } else if ((overrideX >= x && deltaScroll <= 0f) || + (overrideX <= x && deltaScroll >= 0f)) { + // Scrolling from override x towards x, then lock the task in place + mTaskIndexOverrideMap.put(taskId, newOverrideX); + } else { + // Scrolling override x away from x, we should still move the scroll towards x + float deltaX = overrideX - x; + newOverrideX = Math.signum(deltaX) * (Math.abs(deltaX) - deltaScroll); + mTaskIndexOverrideMap.put(taskId, x + newOverrideX); + } } } /** * Returns the default focus state. */ - public float getDefaultFocusState() { + public int getDefaultFocusState() { return STATE_FOCUSED; } @@ -650,18 +648,19 @@ public class TaskStackLayoutAlgorithm { false /* forceUpdate */); } - public TaskViewTransform getStackTransform(Task task, float stackScroll, float focusState, + public TaskViewTransform getStackTransform(Task task, float stackScroll, int focusState, TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate) { if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) { mFreeformLayoutAlgorithm.getTransform(task, transformOut, this); return transformOut; } else { // Return early if we have an invalid index - if (task == null || !mTaskIndexMap.containsKey(task.key)) { + if (task == null || mTaskIndexMap.get(task.key.id, -1) == -1) { transformOut.reset(); return transformOut; } - getStackTransform(mTaskIndexMap.get(task.key), stackScroll, focusState, transformOut, + float taskProgress = getStackScrollForTask(task); + getStackTransform(taskProgress, stackScroll, focusState, transformOut, frontTransform, false /* ignoreSingleTaskCase */, forceUpdate); return transformOut; } @@ -687,7 +686,7 @@ public class TaskStackLayoutAlgorithm { * internally to ensure that we can calculate the transform for any * position in the stack. */ - public void getStackTransform(float taskProgress, float stackScroll, float focusState, + public void getStackTransform(float taskProgress, float stackScroll, int focusState, TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean ignoreSingleTaskCase, boolean forceUpdate) { SystemServicesProxy ssp = Recents.getSystemServices(); @@ -773,8 +772,7 @@ public class TaskStackLayoutAlgorithm { * stack. */ float getStackScrollForTask(Task t) { - if (!mTaskIndexMap.containsKey(t.key)) return 0f; - return mTaskIndexMap.get(t.key); + return mTaskIndexOverrideMap.get(t.key.id, (float) mTaskIndexMap.get(t.key.id, 0)); } /** 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 1707c4f4ccd0..d5f88f7ac56c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -665,7 +665,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void getCurrentTaskTransforms(ArrayList<Task> tasks, ArrayList<TaskViewTransform> transformsOut) { Utilities.matchTaskListSize(tasks, transformsOut); - float focusState = mLayoutAlgorithm.getFocusState(); + int focusState = mLayoutAlgorithm.getFocusState(); for (int i = tasks.size() - 1; i >= 0; i--) { Task task = tasks.get(i); TaskViewTransform transform = transformsOut.get(i); @@ -684,7 +684,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal * Returns the task transforms for all the tasks in the stack if the stack was at the given * {@param stackScroll} and {@param focusState}. */ - public void getLayoutTaskTransforms(float stackScroll, float focusState, ArrayList<Task> tasks, + public void getLayoutTaskTransforms(float stackScroll, int focusState, ArrayList<Task> tasks, ArrayList<TaskViewTransform> transformsOut) { Utilities.matchTaskListSize(tasks, transformsOut); for (int i = tasks.size() - 1; i >= 0; i--) { @@ -1055,7 +1055,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal protected Parcelable onSaveInstanceState() { Bundle savedState = new Bundle(); savedState.putParcelable(KEY_SAVED_STATE_SUPER, super.onSaveInstanceState()); - savedState.putFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState()); + savedState.putInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState()); savedState.putFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL, mStackScroller.getStackScroll()); return super.onSaveInstanceState(); } @@ -1065,7 +1065,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Bundle savedState = (Bundle) state; super.onRestoreInstanceState(savedState.getParcelable(KEY_SAVED_STATE_SUPER)); - mLayoutAlgorithm.setFocusState(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE)); + mLayoutAlgorithm.setFocusState(savedState.getInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE)); mStackScroller.setStackScroll(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL)); } @@ -1517,7 +1517,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /**** TaskStackLayoutAlgorithm.TaskStackLayoutAlgorithmCallbacks ****/ @Override - public void onFocusStateChanged(float prevFocusState, float curFocusState) { + public void onFocusStateChanged(int prevFocusState, int curFocusState) { if (mDeferredTaskViewLayoutAnimation == null) { mUIDozeTrigger.poke(); relayoutTaskViewsOnNextFrame(AnimationProps.IMMEDIATE); @@ -1532,6 +1532,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (animation != null) { relayoutTaskViewsOnNextFrame(animation); } + mLayoutAlgorithm.updateFocusStateOnScroll(curScroll, curScroll - prevScroll); if (mEnterAnimationComplete) { if (shouldShowHistoryButton() && @@ -1636,11 +1637,19 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } public final void onBusEvent(FocusNextTaskViewEvent event) { + // Stop any scrolling + mStackScroller.stopScroller(); + mStackScroller.stopBoundScrollAnimation(); + setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */, false, event.timerIndicatorDuration); } public final void onBusEvent(FocusPreviousTaskViewEvent event) { + // Stop any scrolling + mStackScroller.stopScroller(); + mStackScroller.stopBoundScrollAnimation(); + setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */); } @@ -1771,10 +1780,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal removeIgnoreTask(event.task); } - public final void onBusEvent(StackViewScrolledEvent event) { - mLayoutAlgorithm.updateFocusStateOnScroll(event.yMovement.value); - } - public final void onBusEvent(IterateRecentsEvent event) { if (!mEnterAnimationComplete) { // Cancel the previous task's window transition before animating the focused state 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 3f0630d70c94..20933ee3cf6f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -223,6 +223,13 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { int xDiff = Math.abs(x - mDownX); if (Math.abs(y - mDownY) > mScrollTouchSlop && yDiff > xDiff) { mIsScrolling = true; + float stackScroll = mScroller.getStackScroll(); + List<TaskView> taskViews = mSv.getTaskViews(); + for (int i = taskViews.size() - 1; i >= 0; i--) { + layoutAlgorithm.addUnfocusedTaskOverride(taskViews.get(i).getTask(), + stackScroll); + } + layoutAlgorithm.setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED); // Disallow parents from intercepting touch events final ViewParent parent = mSv.getParent(); @@ -429,8 +436,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { // Otherwise, offset the scroll by the movement of the anchor task float anchorTaskScroll = layoutAlgorithm.getStackScrollForTask(anchorTask); float stackScrollOffset = (anchorTaskScroll - prevAnchorTaskScroll); - if (layoutAlgorithm.getFocusState() != - TaskStackLayoutAlgorithm.STATE_FOCUSED) { + if (layoutAlgorithm.getFocusState() != TaskStackLayoutAlgorithm.STATE_FOCUSED) { // If we are focused, we don't want the front task to move, but otherwise, we // allow the back task to move up, and the front task to move back stackScrollOffset /= 2; |