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

Commit 2f7d2925 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Supply app transition specs with a future

Because we retain activity surfaces now, the app transition specs
which were calculated/generated after the onPause() call when going
from recents -> app were too slow. Instead, supply a cross-process
future, which gets fetched when the window manager is about to be
ready to execute the app transition. In practice, this still gets
executed immediately after the onPause call.

If we have a retained surface, this adds some latency, but since we
absolutely need the specs to execute the transition, we have that
latency no matter where exactly we generate the specs.

If we don't have a retained surface, the specs are not calculated on
the critical path, so it's faster.

Bug: 19940527
Change-Id: I80d2c6f6b3a6568a70339619ecefbc3bd8409bd8
parent 8382f98f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -259,6 +259,7 @@ LOCAL_SRC_FILES += \
	core/java/android/view/accessibility/IAccessibilityManager.aidl \
	core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \
	core/java/android/view/IApplicationToken.aidl \
	core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl \
	core/java/android/view/IAssetAtlas.aidl \
	core/java/android/view/IGraphicsStats.aidl \
	core/java/android/view/IInputFilter.aidl \
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.view.AppTransitionAnimationSpec;

/**
 * A cross-process future to fetch the specifications for app transitions.
 *
 * {@hide}
 */
interface IAppTransitionAnimationSpecsFuture {
    AppTransitionAnimationSpec[] get();
}
+10 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
import android.view.IWindowSession;
@@ -140,6 +141,15 @@ interface IWindowManager
    void overridePendingAppTransitionMultiThumb(in AppTransitionAnimationSpec[] specs,
            IRemoteCallback startedCallback, IRemoteCallback finishedCallback, boolean scaleUp);
    void overridePendingAppTransitionInPlace(String packageName, int anim);

    /**
     * Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is
     * used for recents, where generating the thumbnails of the specs takes a non-trivial amount of
     * time, so we want to move that off the critical path for starting the new activity.
     */
    void overridePendingAppTransitionMultiThumbFuture(
            IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback startedCallback,
            boolean scaleUp);
    void executeAppTransition();
    void setAppStartingWindow(IBinder token, String pkg, int theme,
            in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
+4 −11
Original line number Diff line number Diff line
@@ -104,9 +104,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
    // Runnables to finish the Recents activity
    FinishRecentsRunnable mFinishLaunchHomeRunnable;

    // Runnable to be executed after we paused ourselves
    Runnable mAfterPauseRunnable;

    // The trigger to automatically launch the current task
    DozeTrigger mIterateTrigger = new DozeTrigger(500, new Runnable() {
        @Override
@@ -426,9 +423,10 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
    @Override
    protected void onPause() {
        super.onPause();
        if (mAfterPauseRunnable != null) {
            mRecentsView.post(mAfterPauseRunnable);
            mAfterPauseRunnable = null;

        if (Constants.DebugFlags.App.EnableFastToggleRecents) {
            // Stop the fast-toggle dozer
            mIterateTrigger.stopDozing();
        }

        if (Constants.DebugFlags.App.EnableFastToggleRecents) {
@@ -591,11 +589,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
        mFinishLaunchHomeRunnable.run();
    }

    @Override
    public void runAfterPause(Runnable r) {
        mAfterPauseRunnable = r;
    }

    /**** EventBus events ****/

    public final void onBusEvent(ToggleRecentsEvent event) {
+57 −50
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.recents.views;

import android.app.ActivityOptions;
import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -30,6 +31,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -38,6 +40,8 @@ import android.view.WindowManagerGlobal;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
@@ -81,7 +85,6 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
        public void onTaskViewClicked();
        public void onTaskLaunchFailed();
        public void onAllTaskViewsDismissed();
        public void runAfterPause(Runnable r);
    }

    LayoutInflater mInflater;
@@ -104,6 +107,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV

    Rect mSystemInsets = new Rect();

    @GuardedBy("this")
    List<AppTransitionAnimationSpec> mAppTransitionAnimationSpecs;

    public RecentsView(Context context) {
        super(context);
    }
@@ -412,56 +418,37 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
        }
    }

    private void postDrawHeaderThumbnailTransitionRunnable(final TaskStackView view,
            final TaskView clickedView, final int offsetX, final int offsetY,
            final float stackScroll,
            final ActivityOptions.OnAnimationStartedListener animStartedListener,
            final int destinationStack) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                overrideDrawHeaderThumbnailTransition(view, clickedView, offsetX, offsetY,
                        stackScroll, animStartedListener, destinationStack);

            }
        };

        mCb.runAfterPause(r);
    }

    private void overrideDrawHeaderThumbnailTransition(TaskStackView stackView,
            TaskView clickedTask, int offsetX, int offsetY, float stackScroll,
            final ActivityOptions.OnAnimationStartedListener animStartedListener,
            int destinationStack) {
        List<AppTransitionAnimationSpec> specs = getAppTransitionAnimationSpecs(stackView,
                clickedTask, offsetX, offsetY, stackScroll, destinationStack);
        if (specs == null) {
            return;
        }

        IRemoteCallback.Stub callback = new IRemoteCallback.Stub() {
    private IAppTransitionAnimationSpecsFuture getAppTransitionFuture(final TaskStackView stackView,
            final TaskView clickedTask, final int offsetX, final int offsetY,
            final float stackScroll, final int destinationStack) {
        return new IAppTransitionAnimationSpecsFuture.Stub() {
            @Override
            public void sendResult(Bundle data) throws RemoteException {
            public AppTransitionAnimationSpec[] get() throws RemoteException {
                post(new Runnable() {
                    @Override
                    public void run() {
                        if (animStartedListener != null) {
                            animStartedListener.onAnimationStarted();
                        synchronized (RecentsView.this) {
                            mAppTransitionAnimationSpecs = getAppTransitionAnimationSpecs(stackView,
                                    clickedTask, offsetX, offsetY, stackScroll, destinationStack);
                            RecentsView.this.notifyAll();
                        }
                    }
                });
            }
        };

        AppTransitionAnimationSpec[] specsArray =
                new AppTransitionAnimationSpec[specs.size()];
                synchronized (RecentsView.this) {
                    while (mAppTransitionAnimationSpecs == null) {
                        try {
            WindowManagerGlobal.getWindowManagerService().overridePendingAppTransitionMultiThumb(
                    specs.toArray(specsArray), callback, null, true /* scaleUp */);

        } catch (RemoteException e) {
            Log.w(TAG, "Error overriding app transition", e);
                            RecentsView.this.wait();
                        } catch (InterruptedException e) {}
                    }
                    if (mAppTransitionAnimationSpecs == null) {
                        return null;
                    }
                    AppTransitionAnimationSpec[] specs
                            = new AppTransitionAnimationSpec[mAppTransitionAnimationSpecs.size()];
                    return mAppTransitionAnimationSpecs.toArray(specs);
                }
            }
        };
    }

    private List<AppTransitionAnimationSpec> getAppTransitionAnimationSpecs(TaskStackView stackView,
@@ -613,8 +600,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
        // Compute the thumbnail to scale up from
        final SystemServicesProxy ssp = Recents.getSystemServices();
        boolean screenPinningRequested = false;
        ActivityOptions opts = null;
        ActivityOptions opts = ActivityOptions.makeBasic();
        ActivityOptions.OnAnimationStartedListener animStartedListener = null;
        final IAppTransitionAnimationSpecsFuture transitionFuture;
        if (task.thumbnail != null && task.thumbnail.getWidth() > 0 &&
                task.thumbnail.getHeight() > 0) {
            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
@@ -636,21 +624,18 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
                    }
                }
            };
            postDrawHeaderThumbnailTransitionRunnable(stackView, tv, offsetX, offsetY, stackScroll,
                    animStartedListener, destinationStack);
            opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
                    Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
                    offsetX, offsetY, (int) transform.rect.width(), (int) transform.rect.height(),
                    sourceView.getHandler(), animStartedListener);
            transitionFuture = getAppTransitionFuture(stackView, tv, offsetX, offsetY, stackScroll,
                    destinationStack);
            screenPinningRequested = true;
        } else {
            opts = ActivityOptions.makeBasic();
            transitionFuture = null;
        }
        if (boundsValid) {
            opts.setBounds(bounds.isEmpty() ? null : bounds);
        }
        final ActivityOptions launchOpts = opts;
        final boolean finalScreenPinningRequested = screenPinningRequested;
        final OnAnimationStartedListener finalAnimStartedListener = animStartedListener;
        final Runnable launchRunnable = new Runnable() {
            @Override
            public void run() {
@@ -678,6 +663,28 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
                        MetricsLogger.count(getContext(), "overview_task_launch_failed", 1);
                    }
                }
                if (transitionFuture != null) {
                    IRemoteCallback.Stub callback = new IRemoteCallback.Stub() {
                        @Override
                        public void sendResult(Bundle data) throws RemoteException {
                            post(new Runnable() {
                                @Override
                                public void run() {
                                    if (finalAnimStartedListener != null) {
                                        finalAnimStartedListener.onAnimationStarted();
                                    }
                                }
                            });
                        }
                    };
                    try {
                        WindowManagerGlobal.getWindowManagerService()
                                .overridePendingAppTransitionMultiThumbFuture(transitionFuture,
                                        callback, true /* scaleUp */);
                    } catch (RemoteException e) {
                        Log.w(TAG, "Failed to override transition: " + e);
                    }
                }
            }
        };

Loading