Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4387027 authored by Winson's avatar Winson
Browse files

Fixing crash when focusing tasks.

- 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
parent 12858a6e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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();
        }
+24 −41
Original line number Diff line number Diff line
@@ -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;
            }

            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;
                }
            }

            frontTransform = transform;
            frontTransformAtTarget = transformAtTarget;
            if (transform.visible) {
                if (visibleTaskRange[0] < 0) {
                    visibleTaskRange[0] = i;
                }
                visibleTaskRange[1] = i;
            }
        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 */);
            }
        }