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

Commit 900fb48d authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Make entering recents a lot faster

- Precache the bitmap for the window animation in the preload phase
- Remove some post's so we have a faster path from UP -> startActivity
- Don't dim the headers in the first frame drawn, because layer
creation is slow. Instead, do it in the second frame, when the window
animation is already running.

All these changes combined make going to recents about 40-50ms faster.

Change-Id: I3e4060af1ac57b3f359fe7f86f9e3814c6490323
parent 658807a8
Loading
Loading
Loading
Loading
+106 −36
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -40,6 +41,7 @@ import android.util.Pair;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;

import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
@@ -184,12 +186,16 @@ public class Recents extends SystemUI

    // Header (for transition)
    TaskViewHeader mHeaderBar;
    final Object mHeaderBarLock = new Object();
    TaskStackView mDummyStackView;

    // Variables to keep track of if we need to start recents after binding
    boolean mTriggeredFromAltTab;
    long mLastToggleTime;

    Bitmap mThumbnailTransitionBitmapCache;
    Task mThumbnailTransitionBitmapCacheKey;

    public Recents() {
    }

@@ -360,13 +366,16 @@ public class Recents extends SystemUI
    void preloadRecentsInternal() {
        // Preload only the raw task list into a new load plan (which will be consumed by the
        // RecentsActivity)
        ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
        MutableBoolean topTaskHome = new MutableBoolean(true);
        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
        sInstanceLoadPlan = loader.createLoadPlan(mContext);

        ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
        MutableBoolean isTopTaskHome = new MutableBoolean(true);
        if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
            sInstanceLoadPlan.preloadRawTasks(isTopTaskHome.value);
        if (topTask != null && !mSystemServicesProxy.isRecentsTopMost(topTask, topTaskHome)) {
            sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
            loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
            TaskStack top = sInstanceLoadPlan.getAllTaskStacks().get(0);
            preCacheThumbnailTransitionBitmapAsync(topTask, top, mDummyStackView,
                    topTaskHome.value);
        }
    }

@@ -513,6 +522,7 @@ public class Recents extends SystemUI
        algo.computeRects(mWindowRect.width(), mWindowRect.height(), taskStackBounds);
        Rect taskViewSize = algo.getUntransformedTaskViewSize();
        int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
        synchronized (mHeaderBarLock) {
            mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null,
                    false);
            mHeaderBar.measure(
@@ -520,6 +530,7 @@ public class Recents extends SystemUI
                    View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY));
            mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight);
        }
    }

    /** Prepares the search bar app widget */
    void reloadSearchBarAppWidget(Context context, SystemServicesProxy ssp) {
@@ -607,15 +618,84 @@ public class Recents extends SystemUI
     */
    ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask,
            TaskStack stack, TaskStackView stackView) {

        // Update the destination rect
        Task toTask = new Task();
        TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
                topTask.id, toTask);
        if (toTransform != null && toTask.key != null) {
        Rect toTaskRect = toTransform.rect;
        Bitmap thumbnail;
        if (mThumbnailTransitionBitmapCacheKey != null
                && mThumbnailTransitionBitmapCacheKey.key != null
                && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) {
            thumbnail = mThumbnailTransitionBitmapCache;
            mThumbnailTransitionBitmapCacheKey = null;
            mThumbnailTransitionBitmapCache = null;
        } else {
            preloadIcon(topTask);
            thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
        }
        if (thumbnail != null) {
            mStartAnimationTriggered = false;
            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
                    thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
                    toTaskRect.height(), mHandler, this);
        }

        // If both the screenshot and thumbnail fails, then just fall back to the default transition
        return getUnknownTransitionActivityOptions();
    }

    /**
     * Preloads the icon of a task.
     */
    void preloadIcon(ActivityManager.RunningTaskInfo task) {

        // Ensure that we load the running task's icon
        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
        launchOpts.runningTaskId = task.id;
        launchOpts.loadThumbnails = false;
        launchOpts.onlyLoadForCache = true;
        RecentsTaskLoader.getInstance().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
    }

    /**
     * Caches the header thumbnail used for a window animation asynchronously into
     * {@link #mThumbnailTransitionBitmapCache}.
     */
    void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask,
            TaskStack stack, TaskStackView stackView, boolean isTopTaskHome) {
        preloadIcon(topTask);

        // Update the destination rect
        mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, isTopTaskHome);
        final Task toTask = new Task();
        final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
                topTask.id, toTask);
        new AsyncTask<Void, Void, Bitmap>() {
            @Override
            protected Bitmap doInBackground(Void... params) {
                return drawThumbnailTransitionBitmap(toTask, toTransform);
            }

            @Override
            protected void onPostExecute(Bitmap bitmap) {
                mThumbnailTransitionBitmapCache = bitmap;
                mThumbnailTransitionBitmapCacheKey = toTask;
            }
        }.execute();
    }

    /**
     * Draws the header of a task used for the window animation into a bitmap.
     */
    Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
        if (toTransform != null && toTask.key != null) {
            Bitmap thumbnail;
            synchronized (mHeaderBarLock) {
                int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
                int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
            Bitmap thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
                thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
                        Bitmap.Config.ARGB_8888);
                if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
                    thumbnail.eraseColor(0xFFff0000);
@@ -626,16 +706,10 @@ public class Recents extends SystemUI
                    mHeaderBar.draw(c);
                    c.setBitmap(null);
                }
            Bitmap thumbnailImmutable = thumbnail.createAshmemBitmap();

            mStartAnimationTriggered = false;
            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
                    thumbnailImmutable, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
                    toTaskRect.height(), mHandler, this);
            }

        // If both the screenshot and thumbnail fails, then just fall back to the default transition
        return getUnknownTransitionActivityOptions();
            return thumbnail.createAshmemBitmap();
        }
        return null;
    }

    /** Returns the transition rect for the given task id. */
@@ -694,7 +768,9 @@ public class Recents extends SystemUI
            return;
        }

        if (!sInstanceLoadPlan.hasTasks()) {
            loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
        }
        ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
        TaskStack stack = stacks.get(0);

@@ -706,12 +782,6 @@ public class Recents extends SystemUI
        boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;

        if (useThumbnailTransition) {
            // Ensure that we load the running task's icon
            RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
            launchOpts.runningTaskId = topTask.id;
            launchOpts.loadThumbnails = false;
            launchOpts.onlyLoadForCache = true;
            loader.loadTasks(mContext, sInstanceLoadPlan, launchOpts);

            // Try starting with a thumbnail transition
            ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
+4 −0
Original line number Diff line number Diff line
@@ -441,6 +441,10 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
        if (mConfig.launchedHasConfigurationChanged) {
            onEnterAnimationTriggered();
        }

        if (!mConfig.launchedHasConfigurationChanged) {
            mRecentsView.disableLayersForOneFrame();
        }
    }

    @Override
+7 −0
Original line number Diff line number Diff line
@@ -431,6 +431,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
        return false;
    }

    public void disableLayersForOneFrame() {
        List<TaskStackView> stackViews = getTaskStackViews();
        for (int i = 0; i < stackViews.size(); i++) {
            stackViews.get(i).disableLayersForOneFrame();
        }
    }

    /**** TaskStackView.TaskStackCallbacks Implementation ****/

    @Override
+19 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.recents.views;
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.view.LayoutInflater;
@@ -63,7 +64,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal

        public void onTaskResize(Task t);
    }

    RecentsConfiguration mConfig;

    TaskStack mStack;
@@ -81,7 +81,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    boolean mDismissAllButtonAnimating;
    int mFocusedTaskIndex = -1;
    int mPrevAccessibilityFocusedIndex = -1;

    // Optimizations
    int mStackViewsAnimationDuration;
    boolean mStackViewsDirty = true;
@@ -99,6 +98,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    ArrayList<TaskView> mTaskViews = new ArrayList<TaskView>();
    List<TaskView> mImmutableTaskViews = new ArrayList<TaskView>();
    LayoutInflater mInflater;
    boolean mLayersDisabled;

    // A convenience update listener to request updating clipping of tasks
    ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
@@ -375,7 +375,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal

                if (tv == null) {
                    tv = mViewPool.pickUpViewFromPool(task, task);

                    if (mLayersDisabled) {
                        tv.disableLayersForOneFrame();
                    }
                    if (mStackViewsAnimationDuration > 0) {
                        // For items in the list, put them in start animating them from the
                        // approriate ends of the list where they are expected to appear
@@ -1031,6 +1033,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        mUIDozeTrigger.poke();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        mLayersDisabled = false;
        super.dispatchDraw(canvas);
    }

    public void disableLayersForOneFrame() {
        mLayersDisabled = true;
        List<TaskView> taskViews = getTaskViews();
        for (int i = 0; i < taskViews.size(); i++) {
            taskViews.get(i).disableLayersForOneFrame();
        }
    }

    /**** TaskStackCallbacks Implementation ****/

    @Override
+4 −0
Original line number Diff line number Diff line
@@ -650,6 +650,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
        }
    }

    public void disableLayersForOneFrame() {
        mHeaderView.disableLayersForOneFrame();
    }

    /**** TaskCallbacks Implementation ****/

    /** Binds this task view to the task */
Loading