Loading packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java +0 −3 Original line number Diff line number Diff line Loading @@ -24,9 +24,6 @@ public class BakedBezierInterpolator implements TimeInterpolator { * P3 (1.0, 1.0) * * Values sampled with x at regular intervals between 0 and 1. * * These values were generated using: * ./scripts/bezier_interpolator_values_gen.py 0.4 0.2 */ private static final float[] VALUES = new float[] { 0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f, Loading packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +1 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ public class RecentsConfiguration { res.getInteger(R.integer.recents_animate_task_bar_enter_duration); } /** Updates the system insets */ public void updateSystemInsets(Rect insets) { systemInsets.set(insets); } Loading packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +2 −2 Original line number Diff line number Diff line Loading @@ -134,9 +134,9 @@ public class TaskStack { /* Notifies when a task has been removed from the stack */ public void onStackTaskRemoved(TaskStack stack, Task t); /** Notifies when the stack was filtered */ public void onStackFiltered(TaskStack newStack, ArrayList<Task> curStack, Task t); public void onStackFiltered(TaskStack newStack, ArrayList<Task> curTasks, Task t); /** Notifies when the stack was un-filtered */ public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curStack); public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks); } Context mContext; Loading packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +152 −232 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.Region; import android.util.Pair; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.VelocityTracker; Loading @@ -45,6 +46,7 @@ import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; import java.util.HashMap; /* The visual representation of a task stack view */ Loading Loading @@ -76,9 +78,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal OverScroller mScroller; ObjectAnimator mScrollAnimator; // Filtering AnimatorSet mFilterChildrenAnimator; // Optimizations int mHwLayersRefCount; int mStackViewsAnimationDuration; Loading Loading @@ -645,163 +644,22 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement)); } @Override public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curStack, Task filteredTask) { // NOTE: This code assumes that the current (unfiltered) stack is a superset of the new // (filtered) stack // XXX: Use HW Layers // Stash the scroll and filtered task for us to restore to when we unfilter mStashedScroll = getStackScroll(); // Compute the transforms of the items in the current stack final ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curStack, mStashedScroll, null, true); // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better updateMinMaxScroll(false); float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height(); setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight)); boundScrollRaw(); // Compute the transforms of the items in the new stack after setting the new scroll final ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(mStack.getTasks(), getStackScroll(), null, true); // Animate all of the existing views on screen either out of view (if they are not visible // in the new stack) or to their final positions in the new stack final ArrayList<TaskView> childrenToReturnToPool = new ArrayList<TaskView>(); final ArrayList<Task> tasks = mStack.getTasks(); ArrayList<Animator> childViewAnims = new ArrayList<Animator>(); int childCount = getChildCount(); int movement = 0; for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); Task task = tv.getTask(); TaskViewTransform toTransform; int taskIndex = tasks.indexOf(task); boolean willBeInvisible = (taskIndex < 0) || !taskTransforms.get(taskIndex).visible; if (willBeInvisible) { // Compose a new transform that fades and slides the task out of view TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task)); toTransform = new TaskViewTransform(fromTransform); tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); tv.prepareTaskTransformForFilterTaskHidden(toTransform); childrenToReturnToPool.add(tv); } else { toTransform = taskTransforms.get(taskIndex); // Use the movement of the visible views to calculate the duration of the animation movement = Math.max(movement, Math.abs(toTransform.translationY - (int) tv.getTranslationY())); } childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform)); } // Cancel the previous animation if (mFilterChildrenAnimator != null) { mFilterChildrenAnimator.cancel(); mFilterChildrenAnimator.removeAllListeners(); } // Create a new animation for the existing children final RecentsConfiguration config = RecentsConfiguration.getInstance(); mFilterChildrenAnimator = new AnimatorSet(); mFilterChildrenAnimator.setDuration( Utilities.calculateTranslationAnimationDuration(movement, config.filteringCurrentViewsMinAnimDuration)); mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() { boolean isCancelled; @Override public void onAnimationCancel(Animator animation) { isCancelled = true; } @Override public void onAnimationEnd(Animator animation) { if (isCancelled) return; // Return all the removed children to the view pool for (TaskView tv : childrenToReturnToPool) { mViewPool.returnViewToPool(tv); } // For views that are not already visible, animate them in ArrayList<Animator> newViewsAnims = new ArrayList<Animator>(); int taskCount = tasks.size(); int movement = 0; int offset = 0; for (int i = 0; i < taskCount; i++) { Task task = tasks.get(i); TaskViewTransform toTransform = taskTransforms.get(i); if (toTransform.visible) { TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task)); TaskView tv = getChildViewForTask(task); if (tv == null) { tv = mViewPool.pickUpViewFromPool(task, task); // Compose a new transform that fades and slides the new task in fromTransform = new TaskViewTransform(toTransform); tv.prepareTaskTransformForFilterTaskHidden(fromTransform); tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); Animator anim = tv.getAnimatorToTaskTransform(toTransform); anim.setStartDelay(offset * Constants.Values.TaskStackView.FilterStartDelay); newViewsAnims.add(anim); // Use the movement of the newly visible views to calculate the duration // of the animation movement = Math.max(movement, Math.abs(toTransform.translationY - fromTransform.translationY)); offset++; } } // Animate the new views in mFilterChildrenAnimator = new AnimatorSet(); mFilterChildrenAnimator.setDuration( Utilities.calculateTranslationAnimationDuration(movement, config.filteringNewViewsMinAnimDuration)); mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); mFilterChildrenAnimator.playTogether(newViewsAnims); mFilterChildrenAnimator.start(); } invalidate(); } }); mFilterChildrenAnimator.playTogether(childViewAnims); mFilterChildrenAnimator.start(); } @Override public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curStack) { // Compute the transforms of the items in the current stack final int curScroll = getStackScroll(); final ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curStack, curScroll, null, true); // Restore the stashed scroll updateMinMaxScroll(false); setStackScrollRaw(mStashedScroll); boundScrollRaw(); // Compute the transforms of the items in the new stack after restoring the stashed scroll final ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(mStack.getTasks(), getStackScroll(), null, true); /** * Creates the animations for all the children views that need to be removed or to move views * to their un/filtered position when we are un/filtering a stack, and returns the duration * for these animations. */ int getExitTransformsForFilterAnimation(ArrayList<Task> curTasks, ArrayList<TaskViewTransform> curTaskTransforms, ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms, HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut, ArrayList<TaskView> childrenToRemoveOut, RecentsConfiguration config) { // Animate all of the existing views out of view (if they are not in the visible range in // the new stack) or to their final positions in the new stack final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>(); final ArrayList<Task> tasks = mStack.getTasks(); ArrayList<Animator> childViewAnims = new ArrayList<Animator>(); int childCount = getChildCount(); int movement = 0; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); Task task = tv.getTask(); Loading @@ -811,59 +669,37 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // If the view is no longer visible, then we should just animate it out boolean willBeInvisible = taskIndex < 0 || !taskTransforms.get(taskIndex).visible; if (willBeInvisible) { if (taskIndex < 0) { toTransform = curTaskTransforms.get(curTasks.indexOf(task)); } else { toTransform = new TaskViewTransform(taskTransforms.get(taskIndex)); } tv.prepareTaskTransformForFilterTaskVisible(toTransform); childrenToRemove.add(tv); childrenToRemoveOut.add(tv); } else { toTransform = taskTransforms.get(taskIndex); // Use the movement of the visible views to calculate the duration of the animation movement = Math.max(movement, Math.abs(toTransform.translationY - (int) tv.getTranslationY())); } Animator anim = tv.getAnimatorToTaskTransform(toTransform); childViewAnims.add(anim); childViewTransformsOut.put(tv, new Pair(0, toTransform)); } // Cancel the previous animation if (mFilterChildrenAnimator != null) { mFilterChildrenAnimator.cancel(); mFilterChildrenAnimator.removeAllListeners(); return Utilities.calculateTranslationAnimationDuration(movement, config.filteringCurrentViewsMinAnimDuration); } // Create a new animation for the existing children final RecentsConfiguration config = RecentsConfiguration.getInstance(); mFilterChildrenAnimator = new AnimatorSet(); mFilterChildrenAnimator.setDuration( Utilities.calculateTranslationAnimationDuration(movement, config.filteringCurrentViewsMinAnimDuration)); mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() { boolean isCancelled; @Override public void onAnimationCancel(Animator animation) { isCancelled = true; } @Override public void onAnimationEnd(Animator animation) { if (isCancelled) return; // Return all the removed children to the view pool for (TaskView tv : childrenToRemove) { mViewPool.returnViewToPool(tv); } // Increment the hw layers ref count addHwLayersRefCount("unfilteredNewViews"); // For views that are not already visible, animate them in ArrayList<Animator> newViewAnims = new ArrayList<Animator>(); int taskCount = tasks.size(); int movement = 0; /** * Creates the animations for all the children views that need to be animated in when we are * un/filtering a stack, and returns the duration for these animations. */ int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms, HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut, RecentsConfiguration config) { int offset = 0; for (int i = 0; i < taskCount; i++) { int movement = 0; int taskCount = tasks.size(); for (int i = taskCount - 1; i >= 0; i--) { Task task = tasks.get(i); TaskViewTransform toTransform = taskTransforms.get(i); if (toTransform.visible) { Loading @@ -877,38 +713,122 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal tv.prepareTaskTransformForFilterTaskHidden(fromTransform); tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); Animator anim = tv.getAnimatorToTaskTransform(toTransform); anim.setStartDelay(offset * Constants.Values.TaskStackView.FilterStartDelay); newViewAnims.add(anim); // Use the movement of the newly visible views to calculate the duration // of the animation int startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay; childViewTransformsOut.put(tv, new Pair(startDelay, toTransform)); // Use the movement of the new views to calculate the duration of the animation movement = Math.max(movement, Math.abs(toTransform.translationY - fromTransform.translationY)); offset++; } } } return Utilities.calculateTranslationAnimationDuration(movement, config.filteringNewViewsMinAnimDuration); } // Run the animation mFilterChildrenAnimator = new AnimatorSet(); mFilterChildrenAnimator.setDuration( Utilities.calculateTranslationAnimationDuration(movement, config.filteringNewViewsMinAnimDuration)); mFilterChildrenAnimator.playTogether(newViewAnims); mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() { /** Orchestrates the animations of the current child views and any new views. */ void doFilteringAnimation(ArrayList<Task> curTasks, ArrayList<TaskViewTransform> curTaskTransforms, final ArrayList<Task> tasks, final ArrayList<TaskViewTransform> taskTransforms) { final RecentsConfiguration config = RecentsConfiguration.getInstance(); // Calculate the transforms to animate out all the existing views if they are not in the // new visible range (or to their final positions in the stack if they are) final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>(); final HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransforms = new HashMap<TaskView, Pair<Integer, TaskViewTransform>>(); int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks, taskTransforms, childViewTransforms, childrenToRemove, config); // If all the current views are in the visible range of the new stack, then don't wait for // views to animate out and animate all the new views into their place final boolean unifyNewViewAnimation = childrenToRemove.isEmpty(); if (unifyNewViewAnimation) { int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms, childViewTransforms, config); duration = Math.max(duration, inDuration); } // Animate all the views to their final transforms for (final TaskView tv : childViewTransforms.keySet()) { Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv); tv.animate().cancel(); tv.animate() .setStartDelay(t.first) .withEndAction(new Runnable() { @Override public void onAnimationEnd(Animator animation) { // Decrement the hw layers ref count decHwLayersRefCount("unfilteredNewViews"); public void run() { childViewTransforms.remove(tv); if (childViewTransforms.isEmpty()) { // Return all the removed children to the view pool for (TaskView tv : childrenToRemove) { mViewPool.returnViewToPool(tv); } if (!unifyNewViewAnimation) { // For views that are not already visible, animate them in childViewTransforms.clear(); int duration = getEnterTransformsForFilterAnimation(tasks, taskTransforms, childViewTransforms, config); for (final TaskView tv : childViewTransforms.keySet()) { Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv); tv.animate().setStartDelay(t.first); tv.updateViewPropertiesToTaskTransform(null, t.second, duration); } } } }); mFilterChildrenAnimator.start(); invalidate(); } }); mFilterChildrenAnimator.playTogether(childViewAnims); mFilterChildrenAnimator.start(); tv.updateViewPropertiesToTaskTransform(null, t.second, duration); } } @Override public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curTasks, Task filteredTask) { // Stash the scroll and filtered task for us to restore to when we unfilter mStashedScroll = getStackScroll(); // Calculate the current task transforms ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curTasks, getStackScroll(), null, true); // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better updateMinMaxScroll(false); float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height(); setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight)); boundScrollRaw(); // Compute the transforms of the items in the new stack after setting the new scroll final ArrayList<Task> tasks = mStack.getTasks(); final ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(mStack.getTasks(), getStackScroll(), null, true); // Animate doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms); } @Override public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curTasks) { // Calculate the current task transforms final ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curTasks, getStackScroll(), null, true); // Restore the stashed scroll updateMinMaxScroll(false); setStackScrollRaw(mStashedScroll); boundScrollRaw(); // Compute the transforms of the items in the new stack after restoring the stashed scroll final ArrayList<Task> tasks = mStack.getTasks(); final ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, getStackScroll(), null, true); // Animate doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms); // Clear the saved vars mStashedScroll = 0; Loading packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +8 −20 Original line number Diff line number Diff line Loading @@ -16,21 +16,13 @@ package com.android.systemui.recents.views; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Outline; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; import com.android.systemui.R; import com.android.systemui.recents.BakedBezierInterpolator; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.Utilities; import com.android.systemui.recents.model.Task; Loading Loading @@ -115,18 +107,6 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. } } /** Returns an animator to animate this task to the specified transform */ Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) { AnimatorSet anims = new AnimatorSet(); anims.playTogether( ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY), ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale), ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale), ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha) ); return anims; } /** Resets this view's properties */ void resetViewProperties() { setTranslationX(0f); Loading @@ -136,12 +116,20 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. setAlpha(1f); } /** * When we are un/filtering, this method will set up the transform that we are animating to, * in order to hide the task. */ void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) { // Fade the view out and slide it away toTransform.alpha = 0f; toTransform.translationY += 200; } /** * When we are un/filtering, this method will setup the transform that we are animating from, * in order to show the task. */ void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) { // Fade the view in fromTransform.alpha = 0f; Loading Loading
packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java +0 −3 Original line number Diff line number Diff line Loading @@ -24,9 +24,6 @@ public class BakedBezierInterpolator implements TimeInterpolator { * P3 (1.0, 1.0) * * Values sampled with x at regular intervals between 0 and 1. * * These values were generated using: * ./scripts/bezier_interpolator_values_gen.py 0.4 0.2 */ private static final float[] VALUES = new float[] { 0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f, Loading
packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +1 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ public class RecentsConfiguration { res.getInteger(R.integer.recents_animate_task_bar_enter_duration); } /** Updates the system insets */ public void updateSystemInsets(Rect insets) { systemInsets.set(insets); } Loading
packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +2 −2 Original line number Diff line number Diff line Loading @@ -134,9 +134,9 @@ public class TaskStack { /* Notifies when a task has been removed from the stack */ public void onStackTaskRemoved(TaskStack stack, Task t); /** Notifies when the stack was filtered */ public void onStackFiltered(TaskStack newStack, ArrayList<Task> curStack, Task t); public void onStackFiltered(TaskStack newStack, ArrayList<Task> curTasks, Task t); /** Notifies when the stack was un-filtered */ public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curStack); public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks); } Context mContext; Loading
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +152 −232 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.Region; import android.util.Pair; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.VelocityTracker; Loading @@ -45,6 +46,7 @@ import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; import java.util.HashMap; /* The visual representation of a task stack view */ Loading Loading @@ -76,9 +78,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal OverScroller mScroller; ObjectAnimator mScrollAnimator; // Filtering AnimatorSet mFilterChildrenAnimator; // Optimizations int mHwLayersRefCount; int mStackViewsAnimationDuration; Loading Loading @@ -645,163 +644,22 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement)); } @Override public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curStack, Task filteredTask) { // NOTE: This code assumes that the current (unfiltered) stack is a superset of the new // (filtered) stack // XXX: Use HW Layers // Stash the scroll and filtered task for us to restore to when we unfilter mStashedScroll = getStackScroll(); // Compute the transforms of the items in the current stack final ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curStack, mStashedScroll, null, true); // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better updateMinMaxScroll(false); float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height(); setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight)); boundScrollRaw(); // Compute the transforms of the items in the new stack after setting the new scroll final ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(mStack.getTasks(), getStackScroll(), null, true); // Animate all of the existing views on screen either out of view (if they are not visible // in the new stack) or to their final positions in the new stack final ArrayList<TaskView> childrenToReturnToPool = new ArrayList<TaskView>(); final ArrayList<Task> tasks = mStack.getTasks(); ArrayList<Animator> childViewAnims = new ArrayList<Animator>(); int childCount = getChildCount(); int movement = 0; for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); Task task = tv.getTask(); TaskViewTransform toTransform; int taskIndex = tasks.indexOf(task); boolean willBeInvisible = (taskIndex < 0) || !taskTransforms.get(taskIndex).visible; if (willBeInvisible) { // Compose a new transform that fades and slides the task out of view TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task)); toTransform = new TaskViewTransform(fromTransform); tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); tv.prepareTaskTransformForFilterTaskHidden(toTransform); childrenToReturnToPool.add(tv); } else { toTransform = taskTransforms.get(taskIndex); // Use the movement of the visible views to calculate the duration of the animation movement = Math.max(movement, Math.abs(toTransform.translationY - (int) tv.getTranslationY())); } childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform)); } // Cancel the previous animation if (mFilterChildrenAnimator != null) { mFilterChildrenAnimator.cancel(); mFilterChildrenAnimator.removeAllListeners(); } // Create a new animation for the existing children final RecentsConfiguration config = RecentsConfiguration.getInstance(); mFilterChildrenAnimator = new AnimatorSet(); mFilterChildrenAnimator.setDuration( Utilities.calculateTranslationAnimationDuration(movement, config.filteringCurrentViewsMinAnimDuration)); mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() { boolean isCancelled; @Override public void onAnimationCancel(Animator animation) { isCancelled = true; } @Override public void onAnimationEnd(Animator animation) { if (isCancelled) return; // Return all the removed children to the view pool for (TaskView tv : childrenToReturnToPool) { mViewPool.returnViewToPool(tv); } // For views that are not already visible, animate them in ArrayList<Animator> newViewsAnims = new ArrayList<Animator>(); int taskCount = tasks.size(); int movement = 0; int offset = 0; for (int i = 0; i < taskCount; i++) { Task task = tasks.get(i); TaskViewTransform toTransform = taskTransforms.get(i); if (toTransform.visible) { TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task)); TaskView tv = getChildViewForTask(task); if (tv == null) { tv = mViewPool.pickUpViewFromPool(task, task); // Compose a new transform that fades and slides the new task in fromTransform = new TaskViewTransform(toTransform); tv.prepareTaskTransformForFilterTaskHidden(fromTransform); tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); Animator anim = tv.getAnimatorToTaskTransform(toTransform); anim.setStartDelay(offset * Constants.Values.TaskStackView.FilterStartDelay); newViewsAnims.add(anim); // Use the movement of the newly visible views to calculate the duration // of the animation movement = Math.max(movement, Math.abs(toTransform.translationY - fromTransform.translationY)); offset++; } } // Animate the new views in mFilterChildrenAnimator = new AnimatorSet(); mFilterChildrenAnimator.setDuration( Utilities.calculateTranslationAnimationDuration(movement, config.filteringNewViewsMinAnimDuration)); mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); mFilterChildrenAnimator.playTogether(newViewsAnims); mFilterChildrenAnimator.start(); } invalidate(); } }); mFilterChildrenAnimator.playTogether(childViewAnims); mFilterChildrenAnimator.start(); } @Override public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curStack) { // Compute the transforms of the items in the current stack final int curScroll = getStackScroll(); final ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curStack, curScroll, null, true); // Restore the stashed scroll updateMinMaxScroll(false); setStackScrollRaw(mStashedScroll); boundScrollRaw(); // Compute the transforms of the items in the new stack after restoring the stashed scroll final ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(mStack.getTasks(), getStackScroll(), null, true); /** * Creates the animations for all the children views that need to be removed or to move views * to their un/filtered position when we are un/filtering a stack, and returns the duration * for these animations. */ int getExitTransformsForFilterAnimation(ArrayList<Task> curTasks, ArrayList<TaskViewTransform> curTaskTransforms, ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms, HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut, ArrayList<TaskView> childrenToRemoveOut, RecentsConfiguration config) { // Animate all of the existing views out of view (if they are not in the visible range in // the new stack) or to their final positions in the new stack final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>(); final ArrayList<Task> tasks = mStack.getTasks(); ArrayList<Animator> childViewAnims = new ArrayList<Animator>(); int childCount = getChildCount(); int movement = 0; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); Task task = tv.getTask(); Loading @@ -811,59 +669,37 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // If the view is no longer visible, then we should just animate it out boolean willBeInvisible = taskIndex < 0 || !taskTransforms.get(taskIndex).visible; if (willBeInvisible) { if (taskIndex < 0) { toTransform = curTaskTransforms.get(curTasks.indexOf(task)); } else { toTransform = new TaskViewTransform(taskTransforms.get(taskIndex)); } tv.prepareTaskTransformForFilterTaskVisible(toTransform); childrenToRemove.add(tv); childrenToRemoveOut.add(tv); } else { toTransform = taskTransforms.get(taskIndex); // Use the movement of the visible views to calculate the duration of the animation movement = Math.max(movement, Math.abs(toTransform.translationY - (int) tv.getTranslationY())); } Animator anim = tv.getAnimatorToTaskTransform(toTransform); childViewAnims.add(anim); childViewTransformsOut.put(tv, new Pair(0, toTransform)); } // Cancel the previous animation if (mFilterChildrenAnimator != null) { mFilterChildrenAnimator.cancel(); mFilterChildrenAnimator.removeAllListeners(); return Utilities.calculateTranslationAnimationDuration(movement, config.filteringCurrentViewsMinAnimDuration); } // Create a new animation for the existing children final RecentsConfiguration config = RecentsConfiguration.getInstance(); mFilterChildrenAnimator = new AnimatorSet(); mFilterChildrenAnimator.setDuration( Utilities.calculateTranslationAnimationDuration(movement, config.filteringCurrentViewsMinAnimDuration)); mFilterChildrenAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE); mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() { boolean isCancelled; @Override public void onAnimationCancel(Animator animation) { isCancelled = true; } @Override public void onAnimationEnd(Animator animation) { if (isCancelled) return; // Return all the removed children to the view pool for (TaskView tv : childrenToRemove) { mViewPool.returnViewToPool(tv); } // Increment the hw layers ref count addHwLayersRefCount("unfilteredNewViews"); // For views that are not already visible, animate them in ArrayList<Animator> newViewAnims = new ArrayList<Animator>(); int taskCount = tasks.size(); int movement = 0; /** * Creates the animations for all the children views that need to be animated in when we are * un/filtering a stack, and returns the duration for these animations. */ int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms, HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut, RecentsConfiguration config) { int offset = 0; for (int i = 0; i < taskCount; i++) { int movement = 0; int taskCount = tasks.size(); for (int i = taskCount - 1; i >= 0; i--) { Task task = tasks.get(i); TaskViewTransform toTransform = taskTransforms.get(i); if (toTransform.visible) { Loading @@ -877,38 +713,122 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal tv.prepareTaskTransformForFilterTaskHidden(fromTransform); tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0); Animator anim = tv.getAnimatorToTaskTransform(toTransform); anim.setStartDelay(offset * Constants.Values.TaskStackView.FilterStartDelay); newViewAnims.add(anim); // Use the movement of the newly visible views to calculate the duration // of the animation int startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay; childViewTransformsOut.put(tv, new Pair(startDelay, toTransform)); // Use the movement of the new views to calculate the duration of the animation movement = Math.max(movement, Math.abs(toTransform.translationY - fromTransform.translationY)); offset++; } } } return Utilities.calculateTranslationAnimationDuration(movement, config.filteringNewViewsMinAnimDuration); } // Run the animation mFilterChildrenAnimator = new AnimatorSet(); mFilterChildrenAnimator.setDuration( Utilities.calculateTranslationAnimationDuration(movement, config.filteringNewViewsMinAnimDuration)); mFilterChildrenAnimator.playTogether(newViewAnims); mFilterChildrenAnimator.addListener(new AnimatorListenerAdapter() { /** Orchestrates the animations of the current child views and any new views. */ void doFilteringAnimation(ArrayList<Task> curTasks, ArrayList<TaskViewTransform> curTaskTransforms, final ArrayList<Task> tasks, final ArrayList<TaskViewTransform> taskTransforms) { final RecentsConfiguration config = RecentsConfiguration.getInstance(); // Calculate the transforms to animate out all the existing views if they are not in the // new visible range (or to their final positions in the stack if they are) final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>(); final HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransforms = new HashMap<TaskView, Pair<Integer, TaskViewTransform>>(); int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks, taskTransforms, childViewTransforms, childrenToRemove, config); // If all the current views are in the visible range of the new stack, then don't wait for // views to animate out and animate all the new views into their place final boolean unifyNewViewAnimation = childrenToRemove.isEmpty(); if (unifyNewViewAnimation) { int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms, childViewTransforms, config); duration = Math.max(duration, inDuration); } // Animate all the views to their final transforms for (final TaskView tv : childViewTransforms.keySet()) { Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv); tv.animate().cancel(); tv.animate() .setStartDelay(t.first) .withEndAction(new Runnable() { @Override public void onAnimationEnd(Animator animation) { // Decrement the hw layers ref count decHwLayersRefCount("unfilteredNewViews"); public void run() { childViewTransforms.remove(tv); if (childViewTransforms.isEmpty()) { // Return all the removed children to the view pool for (TaskView tv : childrenToRemove) { mViewPool.returnViewToPool(tv); } if (!unifyNewViewAnimation) { // For views that are not already visible, animate them in childViewTransforms.clear(); int duration = getEnterTransformsForFilterAnimation(tasks, taskTransforms, childViewTransforms, config); for (final TaskView tv : childViewTransforms.keySet()) { Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv); tv.animate().setStartDelay(t.first); tv.updateViewPropertiesToTaskTransform(null, t.second, duration); } } } }); mFilterChildrenAnimator.start(); invalidate(); } }); mFilterChildrenAnimator.playTogether(childViewAnims); mFilterChildrenAnimator.start(); tv.updateViewPropertiesToTaskTransform(null, t.second, duration); } } @Override public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curTasks, Task filteredTask) { // Stash the scroll and filtered task for us to restore to when we unfilter mStashedScroll = getStackScroll(); // Calculate the current task transforms ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curTasks, getStackScroll(), null, true); // Scroll the item to the top of the stack (sans-peek) rect so that we can see it better updateMinMaxScroll(false); float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height(); setStackScrollRaw((int) (newStack.indexOfTask(filteredTask) * overlapHeight)); boundScrollRaw(); // Compute the transforms of the items in the new stack after setting the new scroll final ArrayList<Task> tasks = mStack.getTasks(); final ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(mStack.getTasks(), getStackScroll(), null, true); // Animate doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms); } @Override public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curTasks) { // Calculate the current task transforms final ArrayList<TaskViewTransform> curTaskTransforms = getStackTransforms(curTasks, getStackScroll(), null, true); // Restore the stashed scroll updateMinMaxScroll(false); setStackScrollRaw(mStashedScroll); boundScrollRaw(); // Compute the transforms of the items in the new stack after restoring the stashed scroll final ArrayList<Task> tasks = mStack.getTasks(); final ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, getStackScroll(), null, true); // Animate doFilteringAnimation(curTasks, curTaskTransforms, tasks, taskTransforms); // Clear the saved vars mStashedScroll = 0; Loading
packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +8 −20 Original line number Diff line number Diff line Loading @@ -16,21 +16,13 @@ package com.android.systemui.recents.views; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Outline; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; import com.android.systemui.R; import com.android.systemui.recents.BakedBezierInterpolator; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.Utilities; import com.android.systemui.recents.model.Task; Loading Loading @@ -115,18 +107,6 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. } } /** Returns an animator to animate this task to the specified transform */ Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) { AnimatorSet anims = new AnimatorSet(); anims.playTogether( ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY), ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale), ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale), ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha) ); return anims; } /** Resets this view's properties */ void resetViewProperties() { setTranslationX(0f); Loading @@ -136,12 +116,20 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task. setAlpha(1f); } /** * When we are un/filtering, this method will set up the transform that we are animating to, * in order to hide the task. */ void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) { // Fade the view out and slide it away toTransform.alpha = 0f; toTransform.translationY += 200; } /** * When we are un/filtering, this method will setup the transform that we are animating from, * in order to show the task. */ void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) { // Fade the view in fromTransform.alpha = 0f; Loading