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

Commit 258a02dd authored by Jorge Gil's avatar Jorge Gil Committed by Android (Google) Code Review
Browse files

Merge changes I2277a4c5,I6d742c37,I0ebfc278 into main

* changes:
  Defer loading decoration app icon/name until it's needed
  Add traces for caption's SCVH setView vs relayout
  Optimize window decor inset source updates
parents f759d696 7dd9577c
Loading
Loading
Loading
Loading
+29 −22
Original line number Diff line number Diff line
@@ -154,15 +154,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
                windowContainerTransactionSupplier, surfaceControlSupplier,
                surfaceControlViewHostFactory);

        mHandler = handler;
        mChoreographer = choreographer;
        mSyncQueue = syncQueue;
        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;

        Trace.beginSection("DesktopModeWindowDecoration#loadAppInfo");
        loadAppInfo();
        Trace.endSection();
    }

    void setCaptionListeners(
@@ -245,6 +240,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                );
            } else if (mRelayoutParams.mLayoutResId
                    == R.layout.desktop_mode_app_controls_window_decor) {
                loadAppInfoIfNeeded();
                mWindowDecorViewHolder = new DesktopModeAppControlsWindowDecorationViewHolder(
                        mResult.mRootView,
                        mOnCaptionTouchListener,
@@ -457,7 +453,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        return mDragResizeListener != null && mDragResizeListener.isHandlingDragResize();
    }

    private void loadAppInfo() {
    private void loadAppInfoIfNeeded() {
        // TODO(b/337370277): move this to another thread.
        try {
            Trace.beginSection("DesktopModeWindowDecoration#loadAppInfoIfNeeded");
            if (mAppIconBitmap != null && mAppName != null) {
                return;
            }
            final ActivityInfo activityInfo = mTaskInfo.topActivityInfo;
            if (activityInfo == null) {
                Log.e(TAG, "Top activity info not found in task");
@@ -473,6 +475,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            mAppIconBitmap = factory.createScaledBitmap(appIconDrawable, MODE_DEFAULT);
            final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
            mAppName = pm.getApplicationLabel(applicationInfo);
        } finally {
            Trace.endSection();
        }
    }

    private void closeDragResizeListener() {
@@ -489,6 +494,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
     */
    private void createResizeVeilIfNeeded() {
        if (mResizeVeil != null) return;
        loadAppInfoIfNeeded();
        mResizeVeil = new ResizeVeil(mContext, mDisplayController, mAppIconBitmap, mTaskInfo,
                mTaskSurface, mSurfaceControlTransactionSupplier);
    }
@@ -625,6 +631,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
     * Create and display handle menu window.
     */
    void createHandleMenu() {
        loadAppInfoIfNeeded();
        mHandleMenu = new HandleMenu.Builder(this)
                .setAppIcon(mAppIconBitmap)
                .setAppName(mAppName)
@@ -649,10 +656,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    }

    @Override
    void releaseViews() {
    void releaseViews(WindowContainerTransaction wct) {
        closeHandleMenu();
        closeMaximizeMenu();
        super.releaseViews();
        super.releaseViews(wct);
    }

    /**
+86 −29
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.wm.shell.windowdecor;

import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.statusBars;

import android.annotation.NonNull;
@@ -41,11 +43,11 @@ import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
import android.window.SurfaceSyncGroup;
import android.window.TaskConstants;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

import com.android.wm.shell.ShellTaskOrganizer;
@@ -54,7 +56,9 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

/**
@@ -131,8 +135,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
    TaskDragResizer mTaskDragResizer;
    private boolean mIsCaptionVisible;

    /** The most recent set of insets applied to this window decoration. */
    private WindowDecorationInsets mWindowDecorationInsets;
    private final Binder mOwner = new Binder();
    private final Rect mCaptionInsetsRect = new Rect();
    private final float[] mTmpColor = new float[3];

    WindowDecoration(
@@ -203,7 +208,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        mLayoutResId = params.mLayoutResId;

        if (!mTaskInfo.isVisible) {
            releaseViews();
            releaseViews(wct);
            finishT.hide(mTaskSurface);
            return;
        }
@@ -226,7 +231,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
                || mDisplay.getDisplayId() != mTaskInfo.displayId
                || oldLayoutResId != mLayoutResId
                || oldNightMode != newNightMode) {
            releaseViews();
            releaseViews(wct);

            if (!obtainDisplayOrRegisterListener()) {
                outResult.mRootView = null;
@@ -300,8 +305,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
            // Caption inset is the full width of the task with the |captionHeight| and
            // positioned at the top of the task bounds, also in absolute coordinates.
            // So just reuse the task bounds and adjust the bottom coordinate.
            mCaptionInsetsRect.set(taskBounds);
            mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + outResult.mCaptionHeight;
            final Rect captionInsetsRect = new Rect(taskBounds);
            captionInsetsRect.bottom = captionInsetsRect.top + outResult.mCaptionHeight;

            // Caption bounding rectangles: these are optional, and are used to present finer
            // insets than traditional |Insets| to apps about where their content is occluded.
@@ -313,7 +318,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
            } else {
                // The customizable region can at most be equal to the caption bar.
                if (params.hasInputFeatureSpy()) {
                    outResult.mCustomizableCaptionRegion.set(mCaptionInsetsRect);
                    outResult.mCustomizableCaptionRegion.set(captionInsetsRect);
                }
                boundingRects = new Rect[numOfElements];
                for (int i = 0; i < numOfElements; i++) {
@@ -322,7 +327,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
                    final int elementWidthPx =
                            resources.getDimensionPixelSize(element.mWidthResId);
                    boundingRects[i] =
                            calculateBoundingRect(element, elementWidthPx, mCaptionInsetsRect);
                            calculateBoundingRect(element, elementWidthPx, captionInsetsRect);
                    // Subtract the regions used by the caption elements, the rest is
                    // customizable.
                    if (params.hasInputFeatureSpy()) {
@@ -331,18 +336,19 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
                    }
                }
            }
            // Add this caption as an inset source.
            wct.addInsetsSource(mTaskInfo.token,
                    mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect,
                    boundingRects);
            wct.addInsetsSource(mTaskInfo.token,
                    mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures(),
                    mCaptionInsetsRect, null /* boundingRects */);

            final WindowDecorationInsets newInsets = new WindowDecorationInsets(
                    mTaskInfo.token, mOwner, captionInsetsRect, boundingRects);
            if (!newInsets.equals(mWindowDecorationInsets)) {
                // Add or update this caption as an insets source.
                mWindowDecorationInsets = newInsets;
                mWindowDecorationInsets.addOrUpdate(wct);
            }
        } else {
            wct.removeInsetsSource(mTaskInfo.token, mOwner, 0 /* index */,
                    WindowInsets.Type.captionBar());
            wct.removeInsetsSource(mTaskInfo.token, mOwner, 0 /* index */,
                    WindowInsets.Type.mandatorySystemGestures());
            if (mWindowDecorationInsets != null) {
                mWindowDecorationInsets.remove(wct);
                mWindowDecorationInsets = null;
            }
        }

        // Task surface itself
@@ -398,17 +404,21 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        lp.setTrustedOverlay();
        lp.inputFeatures = params.mInputFeatures;
        if (mViewHost == null) {
            Trace.beginSection("CaptionViewHostLayout-new");
            mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
                    mCaptionWindowManager);
            if (params.mApplyStartTransactionOnDraw) {
                mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
            }
            mViewHost.setView(outResult.mRootView, lp);
            Trace.endSection();
        } else {
            Trace.beginSection("CaptionViewHostLayout-relayout");
            if (params.mApplyStartTransactionOnDraw) {
                mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
            }
            mViewHost.relayout(lp);
            Trace.endSection();
        }
        Trace.endSection(); // CaptionViewHostLayout
    }
@@ -481,7 +491,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        return true;
    }

    void releaseViews() {
    void releaseViews(WindowContainerTransaction wct) {
        if (mViewHost != null) {
            mViewHost.release();
            mViewHost = null;
@@ -507,19 +517,21 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
            t.apply();
        }

        final WindowContainerTransaction wct = mWindowContainerTransactionSupplier.get();
        wct.removeInsetsSource(mTaskInfo.token,
                mOwner, 0 /* index */, WindowInsets.Type.captionBar());
        wct.removeInsetsSource(mTaskInfo.token,
                mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures());
        mTaskOrganizer.applyTransaction(wct);
        if (mWindowDecorationInsets != null) {
            mWindowDecorationInsets.remove(wct);
            mWindowDecorationInsets = null;
        }
    }

    @Override
    public void close() {
        Trace.beginSection("WindowDecoration#close");
        mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
        releaseViews();
        final WindowContainerTransaction wct = mWindowContainerTransactionSupplier.get();
        releaseViews(wct);
        mTaskOrganizer.applyTransaction(wct);
        mTaskSurface.release();
        Trace.endSection();
    }

    static int loadDimensionPixelSize(Resources resources, int resourceId) {
@@ -594,8 +606,12 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>

        final int captionHeight = loadDimensionPixelSize(mContext.getResources(), captionHeightId);
        final Rect captionInsets = new Rect(0, 0, 0, captionHeight);
        wct.addInsetsSource(mTaskInfo.token, mOwner, 0 /* index */, WindowInsets.Type.captionBar(),
                captionInsets, null /* boundingRects */);
        final WindowDecorationInsets newInsets = new WindowDecorationInsets(mTaskInfo.token,
                mOwner, captionInsets, null /* boundingRets */);
        if (!newInsets.equals(mWindowDecorationInsets)) {
            mWindowDecorationInsets = newInsets;
            mWindowDecorationInsets.addOrUpdate(wct);
        }
    }

    static class RelayoutParams {
@@ -677,6 +693,47 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        }
    }

    private static class WindowDecorationInsets {
        private static final int INDEX = 0;
        private final WindowContainerToken mToken;
        private final Binder mOwner;
        private final Rect mFrame;
        private final Rect[] mBoundingRects;

        private WindowDecorationInsets(WindowContainerToken token, Binder owner, Rect frame,
                Rect[] boundingRects) {
            mToken = token;
            mOwner = owner;
            mFrame = frame;
            mBoundingRects = boundingRects;
        }

        void addOrUpdate(WindowContainerTransaction wct) {
            wct.addInsetsSource(mToken, mOwner, INDEX, captionBar(), mFrame, mBoundingRects);
            wct.addInsetsSource(mToken, mOwner, INDEX, mandatorySystemGestures(), mFrame,
                    mBoundingRects);
        }

        void remove(WindowContainerTransaction wct) {
            wct.removeInsetsSource(mToken, mOwner, INDEX, captionBar());
            wct.removeInsetsSource(mToken, mOwner, INDEX, mandatorySystemGestures());
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof WindowDecoration.WindowDecorationInsets that)) return false;
            return Objects.equals(mToken, that.mToken) && Objects.equals(mOwner,
                    that.mOwner) && Objects.equals(mFrame, that.mFrame)
                    && Objects.deepEquals(mBoundingRects, that.mBoundingRects);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mToken, mOwner, mFrame, Arrays.hashCode(mBoundingRects));
        }
    }

    /**
     * Subclass for additional windows associated with this WindowDecoration
     */
+143 −4
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.same;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.quality.Strictness.LENIENT;
@@ -64,6 +65,7 @@ import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager.LayoutParams;
import android.window.SurfaceSyncGroup;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

import androidx.test.filters.SmallTest;
@@ -610,32 +612,168 @@ public class WindowDecorationTests extends ShellTestCase {
        mockitoSession.finishMocking();
    }

    @Test
    public void testRelayout_captionHidden_insetsRemoved() {
        final Display defaultDisplay = mock(Display.class);
        doReturn(defaultDisplay).when(mMockDisplayController)
                .getDisplay(Display.DEFAULT_DISPLAY);

        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
                .setDisplayId(Display.DEFAULT_DISPLAY)
                .setVisible(true)
                .setBounds(new Rect(0, 0, 1000, 1000))
                .build();
        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);

        // Run it once so that insets are added.
        mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, captionBar()).setVisible(true);
        windowDecor.relayout(taskInfo);

        // Run it again so that insets are removed.
        mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, captionBar()).setVisible(false);
        windowDecor.relayout(taskInfo);

        verify(mMockWindowContainerTransaction).removeInsetsSource(eq(taskInfo.token), any(),
                eq(0) /* index */, eq(captionBar()));
        verify(mMockWindowContainerTransaction).removeInsetsSource(eq(taskInfo.token), any(),
                eq(0) /* index */, eq(mandatorySystemGestures()));
    }

    @Test
    public void testInsetsRemovedWhenCaptionIsHidden() {
    public void testRelayout_captionHidden_neverWasVisible_insetsNotRemoved() {
        final Display defaultDisplay = mock(Display.class);
        doReturn(defaultDisplay).when(mMockDisplayController)
                .getDisplay(Display.DEFAULT_DISPLAY);

        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
                .setDisplayId(Display.DEFAULT_DISPLAY)
                .setVisible(true)
                .setBounds(new Rect(0, 0, 1000, 1000))
                .build();
        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);

        // Hidden from the beginning, so no insets were ever added.
        mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, captionBar()).setVisible(false);
        windowDecor.relayout(taskInfo);

        // Never added.
        verify(mMockWindowContainerTransaction, never()).addInsetsSource(eq(taskInfo.token), any(),
                eq(0) /* index */, eq(captionBar()), any(), any());
        verify(mMockWindowContainerTransaction, never()).addInsetsSource(eq(taskInfo.token), any(),
                eq(0) /* index */, eq(mandatorySystemGestures()), any(), any());
        // No need to remove them if they were never added.
        verify(mMockWindowContainerTransaction, never()).removeInsetsSource(eq(taskInfo.token),
                any(), eq(0) /* index */, eq(captionBar()));
        verify(mMockWindowContainerTransaction, never()).removeInsetsSource(eq(taskInfo.token),
                any(), eq(0) /* index */, eq(mandatorySystemGestures()));
    }

    @Test
    public void testClose_withExistingInsets_insetsRemoved() {
        final Display defaultDisplay = mock(Display.class);
        doReturn(defaultDisplay).when(mMockDisplayController)
                .getDisplay(Display.DEFAULT_DISPLAY);

        final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
                new ActivityManager.TaskDescription.Builder();
        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
                .setDisplayId(Display.DEFAULT_DISPLAY)
                .setTaskDescriptionBuilder(taskDescriptionBuilder)
                .setVisible(true)
                .setBounds(new Rect(0, 0, 1000, 1000))
                .build();
        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);

        // Relayout will add insets.
        mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, captionBar()).setVisible(true);
        windowDecor.relayout(taskInfo);
        verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
                eq(0) /* index */, eq(captionBar()), any(), any());
        verify(mMockWindowContainerTransaction).addInsetsSource(eq(taskInfo.token), any(),
                eq(0) /* index */, eq(mandatorySystemGestures()), any(), any());

        windowDecor.close();

        // Insets should be removed.
        verify(mMockWindowContainerTransaction).removeInsetsSource(eq(taskInfo.token), any(),
                eq(0) /* index */, eq(captionBar()));
        verify(mMockWindowContainerTransaction).removeInsetsSource(eq(taskInfo.token), any(),
                eq(0) /* index */, eq(mandatorySystemGestures()));
    }

    @Test
    public void testClose_withoutExistingInsets_insetsNotRemoved() {
        final Display defaultDisplay = mock(Display.class);
        doReturn(defaultDisplay).when(mMockDisplayController)
                .getDisplay(Display.DEFAULT_DISPLAY);

        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
                .setDisplayId(Display.DEFAULT_DISPLAY)
                .setVisible(true)
                .setBounds(new Rect(0, 0, 1000, 1000))
                .build();
        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);

        windowDecor.close();

        // No need to remove insets.
        verify(mMockWindowContainerTransaction, never()).removeInsetsSource(eq(taskInfo.token),
                any(), eq(0) /* index */, eq(captionBar()));
        verify(mMockWindowContainerTransaction, never()).removeInsetsSource(eq(taskInfo.token),
                any(), eq(0) /* index */, eq(mandatorySystemGestures()));
    }

    @Test
    public void testRelayout_captionFrameChanged_insetsReapplied() {
        final Display defaultDisplay = mock(Display.class);
        doReturn(defaultDisplay).when(mMockDisplayController)
                .getDisplay(Display.DEFAULT_DISPLAY);
        mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, captionBar()).setVisible(true);
        final WindowContainerToken token = TestRunningTaskInfoBuilder.createMockWCToken();
        final TestRunningTaskInfoBuilder builder = new TestRunningTaskInfoBuilder()
                .setDisplayId(Display.DEFAULT_DISPLAY)
                .setVisible(true);

        // Relayout twice with different bounds.
        final ActivityManager.RunningTaskInfo firstTaskInfo =
                builder.setToken(token).setBounds(new Rect(0, 0, 1000, 1000)).build();
        final TestWindowDecoration windowDecor = createWindowDecoration(firstTaskInfo);
        windowDecor.relayout(firstTaskInfo);
        final ActivityManager.RunningTaskInfo secondTaskInfo =
                builder.setToken(token).setBounds(new Rect(50, 50, 1000, 1000)).build();
        windowDecor.relayout(secondTaskInfo);

        // Insets should be applied twice.
        verify(mMockWindowContainerTransaction, times(2)).addInsetsSource(eq(token), any(),
                eq(0) /* index */, eq(captionBar()), any(), any());
        verify(mMockWindowContainerTransaction, times(2)).addInsetsSource(eq(token), any(),
                eq(0) /* index */, eq(mandatorySystemGestures()), any(), any());
    }

    @Test
    public void testRelayout_captionFrameUnchanged_insetsNotApplied() {
        final Display defaultDisplay = mock(Display.class);
        doReturn(defaultDisplay).when(mMockDisplayController)
                .getDisplay(Display.DEFAULT_DISPLAY);
        mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, captionBar()).setVisible(true);
        final WindowContainerToken token = TestRunningTaskInfoBuilder.createMockWCToken();
        final TestRunningTaskInfoBuilder builder = new TestRunningTaskInfoBuilder()
                .setDisplayId(Display.DEFAULT_DISPLAY)
                .setVisible(true);

        // Relayout twice with the same bounds.
        final ActivityManager.RunningTaskInfo firstTaskInfo =
                builder.setToken(token).setBounds(new Rect(0, 0, 1000, 1000)).build();
        final TestWindowDecoration windowDecor = createWindowDecoration(firstTaskInfo);
        windowDecor.relayout(firstTaskInfo);
        final ActivityManager.RunningTaskInfo secondTaskInfo =
                builder.setToken(token).setBounds(new Rect(0, 0, 1000, 1000)).build();
        windowDecor.relayout(secondTaskInfo);

        // Insets should only need to be applied once.
        verify(mMockWindowContainerTransaction, times(1)).addInsetsSource(eq(token), any(),
                eq(0) /* index */, eq(captionBar()), any(), any());
        verify(mMockWindowContainerTransaction, times(1)).addInsetsSource(eq(token), any(),
                eq(0) /* index */, eq(mandatorySystemGestures()), any(), any());
    }

    @Test
    public void testTaskPositionAndCropNotSetWhenFalse() {
        final Display defaultDisplay = mock(Display.class);
@@ -763,6 +901,7 @@ public class WindowDecorationTests extends ShellTestCase {

        void relayout(ActivityManager.RunningTaskInfo taskInfo,
                boolean applyStartTransactionOnDraw) {
            mRelayoutParams.mRunningTaskInfo = taskInfo;
            mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
            relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
                    mMockWindowContainerTransaction, mMockView, mRelayoutResult);