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

Commit 3150e574 authored by Winson's avatar Winson
Browse files

Fixing regression in stack task clipping.

- Removing expensive calls to map coordinates of front task to the tasks
  behind it, instead relying on the precalculated task rects that we
  already compute on each stack change update.  To prevent rounding
  issues, the task rects are now float rects.
- Also fixing crash when RecentsActivity starts before the SystemUI
  component (only an issue when pushing SysUI apks)

Change-Id: Ia84e9b9d165c0ce171c7fe3797e561ef24157a0a
parent e51ba45c
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
    RecentsConfiguration mConfig;
    RecentsPackageMonitor mPackageMonitor;
    long mLastTabKeyEventTime;
    boolean mFinishedOnStartup;

    // Top level views
    RecentsView mRecentsView;
@@ -298,6 +299,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mFinishedOnStartup = false;

        // In the case that the activity starts up before the Recents component has initialized
        // (usually when debugging/pushing the SysUI apk), just finish this activity.
        SystemServicesProxy ssp = Recents.getSystemServices();
        if (ssp == null) {
            mFinishedOnStartup = true;
            finish();
            return;
        }

        // Register this activity with the event bus
        EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
@@ -319,7 +330,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
        mScrimViews = new SystemBarScrimViews(this);

        // Bind the search app widget when we first start up
        SystemServicesProxy ssp = Recents.getSystemServices();
        mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);

        // Register the broadcast receiver to handle messages when the screen is turned off
@@ -398,6 +408,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
    protected void onDestroy() {
        super.onDestroy();

        // In the case that the activity finished on startup, just skip the unregistration below
        if (mFinishedOnStartup) {
            return;
        }

        // Unregister the system broadcast receivers
        unregisterReceiver(mSystemBroadcastReceiver);

+4 −4
Original line number Diff line number Diff line
@@ -26,10 +26,10 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
import android.util.MutableBoolean;
import android.view.LayoutInflater;
import android.view.View;
@@ -540,7 +540,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
        Task toTask = new Task();
        TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
                topTask.id, toTask);
        Rect toTaskRect = toTransform.rect;
        RectF toTaskRect = toTransform.rect;
        Bitmap thumbnail;
        if (mThumbnailTransitionBitmapCacheKey != null
                && mThumbnailTransitionBitmapCacheKey.key != null
@@ -554,8 +554,8 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
        }
        if (thumbnail != null) {
            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
                    thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
                    toTaskRect.height(), mHandler, this);
                    thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
                    (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, this);
        }

        // If both the screenshot and thumbnail fails, then just fall back to the default transition
+8 −85
Original line number Diff line number Diff line
@@ -18,13 +18,10 @@ package com.android.systemui.recents.misc;

import android.animation.Animator;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.View;
import android.view.ViewParent;

import java.util.ArrayList;

/* Common code */
public class Utilities {

@@ -45,93 +42,19 @@ public class Utilities {
    }

    /** Scales a rect about its centroid */
    public static void scaleRectAboutCenter(Rect r, float scale) {
    public static void scaleRectAboutCenter(RectF r, float scale) {
        if (scale != 1.0f) {
            int cx = r.centerX();
            int cy = r.centerY();
            float cx = r.centerX();
            float cy = r.centerY();
            r.offset(-cx, -cy);
            r.left = (int) (r.left * scale + 0.5f);
            r.top = (int) (r.top * scale + 0.5f);
            r.right = (int) (r.right * scale + 0.5f);
            r.bottom = (int) (r.bottom * scale + 0.5f);
            r.left *= scale;
            r.top *= scale;
            r.right *= scale;
            r.bottom *= scale;
            r.offset(cx, cy);
        }
    }

    /** Maps a coorindate in a descendant view into the parent. */
    public static float mapCoordInDescendentToSelf(View descendant, View root,
            float[] coord, boolean includeRootScroll) {
        ArrayList<View> ancestorChain = new ArrayList<View>();

        float[] pt = {coord[0], coord[1]};

        View v = descendant;
        while(v != root && v != null) {
            ancestorChain.add(v);
            v = (View) v.getParent();
        }
        ancestorChain.add(root);

        float scale = 1.0f;
        int count = ancestorChain.size();
        for (int i = 0; i < count; i++) {
            View v0 = ancestorChain.get(i);
            // For TextViews, scroll has a meaning which relates to the text position
            // which is very strange... ignore the scroll.
            if (v0 != descendant || includeRootScroll) {
                pt[0] -= v0.getScrollX();
                pt[1] -= v0.getScrollY();
            }

            v0.getMatrix().mapPoints(pt);
            pt[0] += v0.getLeft();
            pt[1] += v0.getTop();
            scale *= v0.getScaleX();
        }

        coord[0] = pt[0];
        coord[1] = pt[1];
        return scale;
    }

    /** Maps a coordinate in the root to a descendent. */
    public static float mapCoordInSelfToDescendent(View descendant, View root,
            float[] coord, Matrix tmpInverseMatrix) {
        ArrayList<View> ancestorChain = new ArrayList<View>();

        float[] pt = {coord[0], coord[1]};

        View v = descendant;
        while(v != root) {
            ancestorChain.add(v);
            v = (View) v.getParent();
        }
        ancestorChain.add(root);

        float scale = 1.0f;
        int count = ancestorChain.size();
        tmpInverseMatrix.set(Matrix.IDENTITY_MATRIX);
        for (int i = count - 1; i >= 0; i--) {
            View ancestor = ancestorChain.get(i);
            View next = i > 0 ? ancestorChain.get(i-1) : null;

            pt[0] += ancestor.getScrollX();
            pt[1] += ancestor.getScrollY();

            if (next != null) {
                pt[0] -= next.getLeft();
                pt[1] -= next.getTop();
                next.getMatrix().invert(tmpInverseMatrix);
                tmpInverseMatrix.mapPoints(pt);
                scale *= next.getScaleX();
            }
        }

        coord[0] = pt[0];
        coord[1] = pt[1];
        return scale;
    }

    /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
    public static float computeContrastBetweenColors(int bg, int fg) {
        float bgR = Color.red(bg) / 255f;
+4 −4
Original line number Diff line number Diff line
@@ -594,8 +594,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV

        final int left = pts[0] + offsetX;
        final int top = pts[1] + offsetY;
        final Rect rect = new Rect(left, top, left + transform.rect.width(),
                top + transform.rect.height());
        final Rect rect = new Rect(left, top, left + (int) transform.rect.width(),
                top + (int) transform.rect.height());

        return new AppTransitionAnimationSpec(taskId, b, rect);
    }
@@ -622,7 +622,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
            // and then offset to the expected transform rect, but bound this to just
            // outside the display rect (to ensure we don't animate from too far away)
            sourceView = stackView;
            offsetX = transform.rect.left;
            offsetX = (int) transform.rect.left;
            offsetY = getMeasuredHeight();
        } else {
            sourceView = tv.mThumbnailView;
@@ -656,7 +656,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
                    animStartedListener, destinationStack);
            opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
                    Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
                    offsetX, offsetY, transform.rect.width(), transform.rect.height(),
                    offsetX, offsetY, (int) transform.rect.width(), (int) transform.rect.height(),
                    sourceView.getHandler(), animStartedListener);
        } else {
            opts = ActivityOptions.makeBasic();
+27 −26
Original line number Diff line number Diff line
@@ -20,8 +20,8 @@ import android.animation.ValueAnimator;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -89,11 +89,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    boolean mStartEnterAnimationRequestedAfterLayout;
    boolean mStartEnterAnimationCompleted;
    ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;

    Rect mTaskStackBounds = new Rect();
    int[] mTmpVisibleRange = new int[2];
    float[] mTmpCoord = new float[2];
    Matrix mTmpMatrix = new Matrix();
    Rect mTmpRect = new Rect();
    RectF mTmpTaskRect = new RectF();
    TaskViewTransform mTmpTransform = new TaskViewTransform();
    HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>();
    ArrayList<TaskView> mTaskViews = new ArrayList<>();
@@ -412,23 +412,24 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        return false;
    }

    /** Updates the clip for each of the task views. */
    /**
     * Updates the clip for each of the task views from back to front.
     */
    void clipTaskViews() {
        // Update the clip on each task child
        List<TaskView> taskViews = getTaskViews();
        TaskView tmpTv = null;
        int taskViewCount = taskViews.size();
        for (int i = 0; i < taskViewCount - 1; i++) {
        for (int i = 0; i < taskViewCount; i++) {
            TaskView tv = taskViews.get(i);
            TaskView nextTv = null;
            TaskView tmpTv = null;
            TaskView frontTv = null;
            int clipBottom = 0;
            if (tv.shouldClipViewInStack()) {
            if (i < (taskViewCount - 1) && tv.shouldClipViewInStack()) {
                // Find the next view to clip against
                int nextIndex = i;
                while (nextIndex < (taskViewCount - 1)) {
                    tmpTv = taskViews.get(++nextIndex);
                    if (tmpTv != null && tmpTv.shouldClipViewInStack()) {
                        nextTv = tmpTv;
                for (int j = i + 1; j < taskViewCount; j++) {
                    tmpTv = taskViews.get(j);
                    if (tmpTv.shouldClipViewInStack()) {
                        frontTv = tmpTv;
                        break;
                    }
                }
@@ -436,22 +437,22 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                // Clip against the next view, this is just an approximation since we are
                // stacked and we can make assumptions about the visibility of the this
                // task relative to the ones in front of it.
                if (nextTv != null) {
                    // Map the top edge of next task view into the local space of the current
                    // task view to find the clip amount in local space
                    mTmpCoord[0] = mTmpCoord[1] = 0;
                    Utilities.mapCoordInDescendentToSelf(nextTv, this, mTmpCoord, false);
                    Utilities.mapCoordInSelfToDescendent(tv, this, mTmpCoord, mTmpMatrix);
                    clipBottom = (int) Math.floor(tv.getMeasuredHeight() - mTmpCoord[1]
                            - nextTv.getPaddingTop() - 1);
                if (frontTv != null) {
                    mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
                    mTmpTaskRect.offset(0, tv.getTranslationY());
                    Utilities.scaleRectAboutCenter(mTmpTaskRect, tv.getScaleX());
                    float taskBottom = mTmpTaskRect.bottom;
                    mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
                    mTmpTaskRect.offset(0, frontTv.getTranslationY());
                    Utilities.scaleRectAboutCenter(mTmpTaskRect, frontTv.getScaleX());
                    float frontTaskTop = mTmpTaskRect.top;
                    if (frontTaskTop < taskBottom) {
                        // Map the stack view space coordinate (the rects) to view space
                        clipBottom = (int) ((taskBottom - frontTaskTop) / tv.getScaleX()) - 1;
                    }
                }
            tv.getViewBounds().setClipBottom(clipBottom);
            }
        if (taskViewCount > 0) {
            // The front most task should never be clipped
            TaskView tv = taskViews.get(taskViewCount - 1);
            tv.getViewBounds().setClipBottom(0);
            tv.getViewBounds().setClipBottom(clipBottom);
        }
        mStackViewsClipDirty = false;
    }
Loading