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 import java.util.List; 26 27 /* The layout logic for a TaskStackView */ 28 public class TaskStackViewFilterAlgorithm { 29 30 RecentsConfiguration mConfig; 31 TaskStackView mStackView; 32 ViewPool<TaskView, Task> mViewPool; 33 34 public TaskStackViewFilterAlgorithm(RecentsConfiguration config, TaskStackView stackView, 35 ViewPool<TaskView, Task> viewPool) { 36 mConfig = config; 37 mStackView = stackView; 38 mViewPool = viewPool; 39 } 40 41 /** Orchestrates the animations of the current child views and any new views. */ 42 void startFilteringAnimation(ArrayList<Task> curTasks, 43 ArrayList<TaskViewTransform> curTaskTransforms, 44 final ArrayList<Task> tasks, 45 final ArrayList<TaskViewTransform> taskTransforms) { 46 // Calculate the transforms to animate out all the existing views if they are not in the 47 // new visible range (or to their final positions in the stack if they are) 48 final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>(); 49 final HashMap<TaskView, TaskViewTransform> childViewTransforms = 50 new HashMap<TaskView, TaskViewTransform>(); 51 int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks, 52 taskTransforms, childViewTransforms, childrenToRemove); 53 54 // If all the current views are in the visible range of the new stack, then don't wait for 55 // views to animate out and animate all the new views into their place 56 final boolean unifyNewViewAnimation = childrenToRemove.isEmpty(); 57 if (unifyNewViewAnimation) { 58 int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms, 59 childViewTransforms); 60 duration = Math.max(duration, inDuration); 61 } 62 63 // Animate all the views to their final transforms 64 for (final TaskView tv : childViewTransforms.keySet()) { 65 TaskViewTransform t = childViewTransforms.get(tv); 66 tv.animate().cancel(); 67 tv.animate() 68 .withEndAction(new Runnable() { 69 @Override 70 public void run() { 71 childViewTransforms.remove(tv); 72 if (childViewTransforms.isEmpty()) { 73 // Return all the removed children to the view pool 74 for (TaskView tv : childrenToRemove) { 75 mViewPool.returnViewToPool(tv); 76 } 77 78 if (!unifyNewViewAnimation) { 79 // For views that are not already visible, animate them in 80 childViewTransforms.clear(); 81 int duration = getEnterTransformsForFilterAnimation(tasks, 82 taskTransforms, childViewTransforms); 83 for (final TaskView tv : childViewTransforms.keySet()) { 84 TaskViewTransform t = childViewTransforms.get(tv); 85 tv.updateViewPropertiesToTaskTransform(t, duration); 86 } 87 } 88 } 89 } 90 }); 91 tv.updateViewPropertiesToTaskTransform(t, duration); 92 } 93 } 94 95 /** 96 * Creates the animations for all the children views that need to be animated in when we are 97 * un/filtering a stack, and returns the duration for these animations. 98 */ 99 int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks, 100 ArrayList<TaskViewTransform> taskTransforms, 101 HashMap<TaskView, TaskViewTransform> childViewTransformsOut) { 102 int offset = 0; 103 int movement = 0; 104 int taskCount = tasks.size(); 105 for (int i = taskCount - 1; i >= 0; i--) { 106 Task task = tasks.get(i); 107 TaskViewTransform toTransform = taskTransforms.get(i); 108 if (toTransform.visible) { 109 TaskView tv = mStackView.getChildViewForTask(task); 110 if (tv == null) { 111 // For views that are not already visible, animate them in 112 tv = mViewPool.pickUpViewFromPool(task, task); 113 114 // Compose a new transform to fade and slide the new task in 115 TaskViewTransform fromTransform = new TaskViewTransform(toTransform); 116 tv.prepareTaskTransformForFilterTaskHidden(fromTransform); 117 tv.updateViewPropertiesToTaskTransform(fromTransform, 0); 118 119 toTransform.startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay; 120 childViewTransformsOut.put(tv, toTransform); 121 122 // Use the movement of the new views to calculate the duration of the animation 123 movement = Math.max(movement, 124 Math.abs(toTransform.translationY - fromTransform.translationY)); 125 offset++; 126 } 127 } 128 } 129 return mConfig.filteringNewViewsAnimDuration; 130 } 131 132 /** 133 * Creates the animations for all the children views that need to be removed or to move views 134 * to their un/filtered position when we are un/filtering a stack, and returns the duration 135 * for these animations. 136 */ 137 int getExitTransformsForFilterAnimation(ArrayList<Task> curTasks, 138 ArrayList<TaskViewTransform> curTaskTransforms, 139 ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms, 140 HashMap<TaskView, TaskViewTransform> childViewTransformsOut, 141 ArrayList<TaskView> childrenToRemoveOut) { 142 // Animate all of the existing views out of view (if they are not in the visible range in 143 // the new stack) or to their final positions in the new stack 144 int offset = 0; 145 int movement = 0; 146 List<TaskView> taskViews = mStackView.getTaskViews(); 147 int taskViewCount = taskViews.size(); 148 for (int i = 0; i < taskViewCount; i++) { 149 TaskView tv = taskViews.get(i); 150 Task task = tv.getTask(); 151 int taskIndex = tasks.indexOf(task); 152 TaskViewTransform toTransform; 153 154 // If the view is no longer visible, then we should just animate it out 155 boolean willBeInvisible = taskIndex < 0 || !taskTransforms.get(taskIndex).visible; 156 if (willBeInvisible) { 157 if (taskIndex < 0) { 158 toTransform = curTaskTransforms.get(curTasks.indexOf(task)); 159 } else { 160 toTransform = new TaskViewTransform(taskTransforms.get(taskIndex)); 161 } 162 tv.prepareTaskTransformForFilterTaskVisible(toTransform); 163 childrenToRemoveOut.add(tv); 164 } else { 165 toTransform = taskTransforms.get(taskIndex); 166 // Use the movement of the visible views to calculate the duration of the animation 167 movement = Math.max(movement, Math.abs(toTransform.translationY - 168 (int) tv.getTranslationY())); 169 } 170 171 toTransform.startDelay = offset * Constants.Values.TaskStackView.FilterStartDelay; 172 childViewTransformsOut.put(tv, toTransform); 173 offset++; 174 } 175 return mConfig.filteringCurrentViewsAnimDuration; 176 } 177 178 }