OSDN Git Service

Fixing crash when focusing tasks.
authorWinson <winsonc@google.com>
Wed, 24 Feb 2016 20:05:26 +0000 (12:05 -0800)
committerWinson <winsonc@google.com>
Thu, 25 Feb 2016 00:31:10 +0000 (16:31 -0800)
- We call bindVisibleTaskViews() at the new scroll value expecting all
  visible task views at that scroll to be bound synchronously, however,
  the call to computeVisibleTaskTransforms() would not produce the
  correct visible range if the visible range at the current and new
  scroll resulted in gaps (ie. at scroll 0, 0-3 are visible, and at
  scroll s, 5-8 were visible).  As a result, the task view would not be
  bound, causing a later crash.

  Instead of the optimization before, which would assume every task
  after the first non-visible task would also be non-visible, we can
  just update the transforms for all task views.  This ensures that
  all visible task views should be bound, even if they are not in a
  contiguous range.  A global range is still provided in the call to
  allow accessibility to focus the next task when a task is unbound at
  the two ends of the stack.
- Also removing expensive calls to remove all listeners and cancel
  animations that are not even started.

Bug: 27295423

Change-Id: Ib309e9de3095cacb178ae9ff5c53b8ee2c7ddac0

packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java

index e86b92d..72b1cab 100644 (file)
@@ -196,7 +196,7 @@ public class Utilities {
      * are not called.
      */
     public static void cancelAnimationWithoutCallbacks(Animator animator) {
-        if (animator != null) {
+        if (animator != null && animator.isStarted()) {
             removeAnimationListenersRecursive(animator);
             animator.cancel();
         }
index d5f88f7..d71d70f 100644 (file)
@@ -35,6 +35,7 @@ import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.MutableBoolean;
+import android.util.SparseBooleanArray;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -163,12 +164,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     @ViewDebug.ExportedProperty(category="recents")
     private Rect mStackBounds = new Rect();
 
-    @ViewDebug.ExportedProperty(category="recents")
-    private int[] mTmpVisibleRange = new int[2];
     private Rect mTmpRect = new Rect();
     private ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
     private List<TaskView> mTmpTaskViews = new ArrayList<>();
     private TaskViewTransform mTmpTransform = new TaskViewTransform();
+    private int[] mTmpIntPair = new int[2];
 
     // A convenience update listener to request updating clipping of tasks
     private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
@@ -405,15 +405,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
      *                          target stack scrolls will be returned.
      * @param ignoreTasksSet The set of tasks to skip for purposes of calculaing the visible range.
      *                       Transforms will still be calculated for the ignore tasks.
+     * @return the front and back most visible task indices (there may be non visible tasks in
+     *         between this range)
      */
-    boolean computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
+    int[] computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
             ArrayList<Task> tasks, float curStackScroll, float targetStackScroll,
-            int[] visibleRangeOut, ArraySet<Task.TaskKey> ignoreTasksSet) {
+            ArraySet<Task.TaskKey> ignoreTasksSet) {
         int taskCount = tasks.size();
-        int frontMostVisibleIndex = -1;
-        int backMostVisibleIndex = -1;
+        int[] visibleTaskRange = mTmpIntPair;
+        visibleTaskRange[0] = -1;
+        visibleTaskRange[1] = -1;
         boolean useTargetStackScroll = Float.compare(curStackScroll, targetStackScroll) != 0;
-        boolean targetScrollIsInFront = targetStackScroll > curStackScroll;
 
         // We can reuse the task transforms where possible to reduce object allocation
         Utilities.matchTaskListSize(tasks, taskTransforms);
@@ -452,31 +454,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                 continue;
             }
 
+            frontTransform = transform;
+            frontTransformAtTarget = transformAtTarget;
             if (transform.visible) {
-                if (frontMostVisibleIndex < 0) {
-                    frontMostVisibleIndex = i;
-                }
-                backMostVisibleIndex = i;
-            } else if (!targetScrollIsInFront) {
-                if (backMostVisibleIndex != -1) {
-                    // We've reached the end of the visible range, so going down the rest of the
-                    // stack, we can just reset the transforms accordingly
-                    while (i >= 0) {
-                        taskTransforms.get(i).reset();
-                        i--;
-                    }
-                    break;
+                if (visibleTaskRange[0] < 0) {
+                    visibleTaskRange[0] = i;
                 }
+                visibleTaskRange[1] = i;
             }
-
-            frontTransform = transform;
-            frontTransformAtTarget = transformAtTarget;
-        }
-        if (visibleRangeOut != null) {
-            visibleRangeOut[0] = frontMostVisibleIndex;
-            visibleRangeOut[1] = backMostVisibleIndex;
         }
-        return frontMostVisibleIndex != -1 && backMostVisibleIndex != -1;
+        return visibleTaskRange;
     }
 
     /**
@@ -502,13 +489,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
      *                       {@link TaskView}s
      */
     void bindVisibleTaskViews(float targetStackScroll, ArraySet<Task.TaskKey> ignoreTasksSet) {
-        final int[] visibleStackRange = mTmpVisibleRange;
-
         // Get all the task transforms
-        final ArrayList<Task> tasks = mStack.getStackTasks();
-        final boolean isValidVisibleRange = computeVisibleTaskTransforms(mCurrentTaskTransforms,
-                tasks, mStackScroller.getStackScroll(), targetStackScroll, visibleStackRange,
-                ignoreTasksSet);
+        ArrayList<Task> tasks = mStack.getStackTasks();
+        int[] visibleTaskRange = computeVisibleTaskTransforms(mCurrentTaskTransforms, tasks,
+                mStackScroller.getStackScroll(), targetStackScroll, ignoreTasksSet);
 
         // Return all the invisible children to the pool
         mTmpTaskViewMap.clear();
@@ -519,14 +503,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
             TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
             int taskIndex = mStack.indexOfStackTask(task);
+            TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
 
             // Skip ignored tasks
             if (ignoreTasksSet.contains(task.key)) {
                 continue;
             }
 
-            if (task.isFreeformTask() ||
-                    visibleStackRange[1] <= taskIndex && taskIndex <= visibleStackRange[0]) {
+            if (task.isFreeformTask() || transform.visible) {
                 mTmpTaskViewMap.put(task.key, tv);
             } else {
                 if (mTouchExplorationEnabled) {
@@ -538,8 +522,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         }
 
         // Pick up all the newly visible children
-        int lastVisStackIndex = isValidVisibleRange ? visibleStackRange[1] : 0;
-        for (int i = tasks.size() - 1; i >= lastVisStackIndex; i--) {
+        for (int i = tasks.size() - 1; i >= 0; i--) {
             Task task = tasks.get(i);
             TaskViewTransform transform = mCurrentTaskTransforms.get(i);
 
@@ -584,11 +567,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
 
         // Update the focus if the previous focused task was returned to the view pool
         if (lastFocusedTaskIndex != -1) {
-            if (lastFocusedTaskIndex < visibleStackRange[1]) {
-                setFocusedTask(visibleStackRange[1], false /* scrollToTask */,
+            if (lastFocusedTaskIndex < visibleTaskRange[1]) {
+                setFocusedTask(visibleTaskRange[1], false /* scrollToTask */,
                         true /* requestViewFocus */);
             } else {
-                setFocusedTask(visibleStackRange[0], false /* scrollToTask */,
+                setFocusedTask(visibleTaskRange[0], false /* scrollToTask */,
                         true /* requestViewFocus */);
             }
         }