1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.recents.views; 18 19 import com.android.systemui.recents.Constants; 20 import com.android.systemui.recents.RecentsConfiguration; 21 import com.android.systemui.recents.model.Task; 22 23 import java.util.ArrayList; 24 import java.util.HashMap; 25 26 /* The layout logic for a TaskStackView */ 27 public class TaskStackViewFilterAlgorithm { 28 29 RecentsConfiguration mConfig; 30 TaskStackView mStackView; 31 ViewPool<TaskView, Task> mViewPool; 32 33 public TaskStackViewFilterAlgorithm(RecentsConfiguration config, TaskStackView stackView, 34 ViewPool<TaskView, Task> viewPool) { 35 mConfig = config; 36 mStackView = stackView; 37 mViewPool = viewPool; 38 } 39 40 /** Orchestrates the animations of the current child views and any new views. */ 41 void startFilteringAnimation(ArrayList<Task> curTasks, 42 ArrayList<TaskViewTransform> curTaskTransforms, 43 final ArrayList<Task> tasks, 44 final ArrayList<TaskViewTransform> taskTransforms) { 45 // Calculate the transforms to animate out all the existing views if they are not in the 46 // new visible range (or to their final positions in the stack if they are) 47 final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>(); 48 final HashMap<TaskView, TaskViewTransform> childViewTransforms = 49 new HashMap<TaskView, TaskViewTransform>(); 50 int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks, 51 taskTransforms, childViewTransforms, childrenToRemove); 52 53 // If all the current views are in the visible range of the new stack, then don't wait for 54 // views to animate out and animate all the new views into their place 55 final boolean unifyNewViewAnimation = childrenToRemove.isEmpty(); 56 if (unifyNewViewAnimation) { 57 int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms, 58 childViewTransforms); 59 duration = Math.max(duration, inDuration); 60 } 61 62 // Animate all the views to their final transforms 63 for (final TaskView tv : childViewTransforms.keySet()) { 64 TaskViewTransform t = childViewTransforms.get(tv); 65 tv.animate().cancel(); 66 tv.animate() 67 .withEndAction(new Runnable() { 68 @Override 69 public void run() { 70 childViewTransforms.remove(tv); 71 if (childViewTransforms.isEmpty()) { 72 // Return all the removed children to the view pool 73 for (TaskView tv : childrenToRemove) { 74 mViewPool.returnViewToPool(tv); 75 } 76 77 if (!unifyNewViewAnimation) { 78 // For views that are not already visible, animate them in 79 childViewTransforms.clear(); 80 int duration = getEnterTransformsForFilterAnimation(tasks, 81 taskTransforms, childViewTransforms); 82 for (final TaskView tv : childViewTransforms.keySet()) { 83 TaskViewTransform t = childViewTransforms.get(tv); 84 tv.updateViewPropertiesToTaskTransform(t, duration); 85 } 86 } 87 } 88 } 89 }); 90 tv.updateViewPropertiesToTaskTransform(t, duration); 91 } 92 } 93 94 /** 95 * Creates the animations for all the children views that need to be animated in when we are 96 * un/filtering a stack, and returns the duration for these animations. 97 */ 98 int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks, 99 ArrayList<TaskViewTransform> taskTransforms, 100 HashMap<TaskView, TaskViewTransform> childViewTransformsOut) { 101 int offset = 0; 102 int movement = 0; 103 int taskCount = tasks.size(); 104 for (int i = taskCount - 1; i >= 0; i--) { 105 Task task = tasks.get(i); 106 TaskViewTransform toTransform = taskTransforms.get(i); 107 if (toTransform.visible) { 108 TaskView tv = mStackView.getChildViewForTask(task); 109 if (tv == null) { 110 // For views that are not already visible, animate them in 111 tv = mViewPool.pickUpViewFromPool(task, task); 112 113 // Compose a new transform to fade and slide the new task in 114 TaskViewTransform fromTransform = new TaskViewTransform(toTransform); 115 tv.prepareTaskTransformForFilterTaskHidden(fromTransform); 116 tv.updateViewPropertiesToTaskTransform(fromTransform, 0); 117 118 toTransform.startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay; 119 childViewTransformsOut.put(tv, toTransform); 120 121 // Use the movement of the new views to calculate the duration of the animation 122 movement = Math.max(movement, 123 Math.abs(toTransform.translationY - fromTransform.translationY)); 124 offset++; 125 } 126 } 127 } 128 return mConfig.filteringNewViewsAnimDuration; 129 } 130 131 /** 132 * Creates the animations for all the children views that need to be removed or to move views 133 * to their un/filtered position when we are un/filtering a stack, and returns the duration 134 * for these animations. 135 */ 136 int getExitTransformsForFilterAnimation(ArrayList<Task> curTasks, 137 ArrayList<TaskViewTransform> curTaskTransforms, 138 ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms, 139 HashMap<TaskView, TaskViewTransform> childViewTransformsOut, 140 ArrayList<TaskView> childrenToRemoveOut) { 141 // Animate all of the existing views out of view (if they are not in the visible range in 142 // the new stack) or to their final positions in the new stack 143 int offset = 0; 144 int movement = 0; 145 int childCount = mStackView.getChildCount(); 146 for (int i = 0; i < childCount; i++) { 147 TaskView tv = (TaskView) mStackView.getChildAt(i); 148 Task task = tv.getTask(); 149 int taskIndex = tasks.indexOf(task); 150 TaskViewTransform toTransform; 151 152 // If the view is no longer visible, then we should just animate it out 153 boolean willBeInvisible = taskIndex < 0 || !taskTransforms.get(taskIndex).visible; 154 if (willBeInvisible) { 155 if (taskIndex < 0) { 156 toTransform = curTaskTransforms.get(curTasks.indexOf(task)); 157 } else { 158 toTransform = new TaskViewTransform(taskTransforms.get(taskIndex)); 159 } 160 tv.prepareTaskTransformForFilterTaskVisible(toTransform); 161 childrenToRemoveOut.add(tv); 162 } else { 163 toTransform = taskTransforms.get(taskIndex); 164 // Use the movement of the visible views to calculate the duration of the animation 165 movement = Math.max(movement, Math.abs(toTransform.translationY - 166 (int) tv.getTranslationY())); 167 } 168 169 toTransform.startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay; 170 childViewTransformsOut.put(tv, toTransform); 171 offset++; 172 } 173 return mConfig.filteringCurrentViewsAnimDuration; 174 } 175 176 }