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

Commit 3de85266 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge " Replace setFinalCrop with temporary layer"

parents b3c62410 a2977268
Loading
Loading
Loading
Loading
+51 −1
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED;
import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW;
import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL;
import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;

import android.annotation.CallSuper;
import android.app.Activity;
@@ -264,6 +265,12 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
     */
    private boolean mWillCloseOrEnterPip;

    /** Layer used to constrain the animation to a token's stack bounds. */
    SurfaceControl mAnimationBoundsLayer;

    /** Whether this token needs to create mAnimationBoundsLayer for cropping animations. */
    boolean mNeedsAnimationBoundsLayer;

    AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
            DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
            boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
@@ -1720,6 +1727,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
    }

    /**
     * Creates a layer to apply crop to an animation.
     */
    private SurfaceControl createAnimationBoundsLayer(Transaction t) {
        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.i(TAG, "Creating animation bounds layer");
        final SurfaceControl.Builder builder = makeAnimationLeash()
                .setParent(getAnimationLeashParent())
                .setName(getSurfaceControl() + " - animation-bounds")
                .setSize(getSurfaceWidth(), getSurfaceHeight());
        final SurfaceControl boundsLayer = builder.build();
        t.show(boundsLayer);
        return boundsLayer;
    }

    boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
            boolean isVoiceInteraction) {

@@ -1753,12 +1774,15 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
                adapter = mService.mAppTransition.getRemoteAnimationController()
                        .createAnimationAdapter(this, mTmpPoint, mTmpRect);
            } else {
                final int appStackClipMode = mService.mAppTransition.getAppStackClipMode();
                mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);

                final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
                if (a != null) {
                    adapter = new LocalAnimationAdapter(
                            new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
                                    mService.mAppTransition.canSkipFirstFrame(),
                                    mService.mAppTransition.getAppStackClipMode(),
                                    appStackClipMode,
                                    true /* isAppAnimation */),
                            mService.mSurfaceAnimationRunner);
                    if (a.getZAdjustment() == Animation.ZORDER_TOP) {
@@ -1858,6 +1882,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
    @Override
    public void onAnimationLeashDestroyed(Transaction t) {
        super.onAnimationLeashDestroyed(t);
        if (mAnimationBoundsLayer != null) {
            t.destroy(mAnimationBoundsLayer);
            mAnimationBoundsLayer = null;
        }

        if (mAnimatingAppWindowTokenRegistry != null) {
            mAnimatingAppWindowTokenRegistry.notifyFinished(this);
        }
@@ -1908,6 +1937,26 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        if (mAnimatingAppWindowTokenRegistry != null) {
            mAnimatingAppWindowTokenRegistry.notifyStarting(this);
        }

        // If the animation needs to be cropped then an animation bounds layer is created as a child
        // of the pinned stack or animation layer. The leash is then reparented to this new layer.
        if (mNeedsAnimationBoundsLayer) {
            final TaskStack stack = getStack();
            if (stack == null) {
                return;
            }
            mAnimationBoundsLayer = createAnimationBoundsLayer(t);

            // Set clip rect to stack bounds.
            mTmpRect.setEmpty();
            stack.getBounds(mTmpRect);

            // Crop to stack bounds.
            t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);

            // Reparent leash to animation bounds layer.
            t.reparent(leash, mAnimationBoundsLayer.getHandle());
        }
    }

    /**
@@ -1927,6 +1976,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        mTransit = TRANSIT_UNSET;
        mTransitFlags = 0;
        mNeedsZBoost = false;
        mNeedsAnimationBoundsLayer = false;

        setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
                "AppWindowToken");
+1 −7
Original line number Diff line number Diff line
@@ -99,13 +99,7 @@ public class WindowAnimationSpec implements AnimationSpec {
        tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
        t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
        t.setAlpha(leash, tmp.transformation.getAlpha());
        if (mStackClipMode == STACK_CLIP_NONE) {
            t.setWindowCrop(leash, tmp.transformation.getClipRect());
        } else if (mStackClipMode == STACK_CLIP_AFTER_ANIM) {
            mTmpRect.set(mStackBounds);
            // Offset stack bounds to stack position so the final crop is in screen space.
            mTmpRect.offsetTo(mPosition.x, mPosition.y);
            t.setFinalCrop(leash, mTmpRect);
        if (mStackClipMode == STACK_CLIP_NONE || mStackClipMode == STACK_CLIP_AFTER_ANIM) {
            t.setWindowCrop(leash, tmp.transformation.getClipRect());
        } else {
            mTmpRect.set(mStackBounds);
+118 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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 com.android.server.wm;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.SurfaceControl.Transaction;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;

import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.SurfaceControl;

import com.android.server.wm.WindowTestUtils.TestAppWindowToken;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

/**
 * Animation related tests for the {@link AppWindowToken} class.
 *
 * Build/Install/Run:
 * atest FrameworksServicesTests:com.android.server.wm.AppWindowTokenAnimationTests
 */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class AppWindowTokenAnimationTests extends WindowTestsBase {

    private TestAppWindowToken mToken;

    @Mock
    private Transaction mTransaction;
    @Mock
    private AnimationAdapter mSpec;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        MockitoAnnotations.initMocks(this);

        mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
                ACTIVITY_TYPE_STANDARD);
        mToken.setPendingTransaction(mTransaction);
    }

    @Test
    public void clipAfterAnim_boundsLayerIsCreated() throws Exception {
        mToken.mNeedsAnimationBoundsLayer = true;

        mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
        verify(mTransaction).reparent(eq(mToken.getSurfaceControl()),
                eq(mToken.mSurfaceAnimator.mLeash.getHandle()));
        verify(mTransaction).reparent(eq(mToken.mSurfaceAnimator.mLeash),
                eq(mToken.mAnimationBoundsLayer.getHandle()));
    }

    @Test
    public void clipAfterAnim_boundsLayerIsDestroyed() throws Exception {
        mToken.mNeedsAnimationBoundsLayer = true;
        mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
        final SurfaceControl leash = mToken.mSurfaceAnimator.mLeash;
        final SurfaceControl animationBoundsLayer = mToken.mAnimationBoundsLayer;
        final ArgumentCaptor<SurfaceAnimator.OnAnimationFinishedCallback> callbackCaptor =
                ArgumentCaptor.forClass(
                        SurfaceAnimator.OnAnimationFinishedCallback.class);
        verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());

        callbackCaptor.getValue().onAnimationFinished(mSpec);
        verify(mTransaction).destroy(eq(leash));
        verify(mTransaction).destroy(eq(animationBoundsLayer));
        assertThat(mToken.mNeedsAnimationBoundsLayer).isFalse();
    }

    @Test
    public void clipAfterAnimCancelled_boundsLayerIsDestroyed() throws Exception {
        mToken.mNeedsAnimationBoundsLayer = true;
        mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
        final SurfaceControl leash = mToken.mSurfaceAnimator.mLeash;
        final SurfaceControl animationBoundsLayer = mToken.mAnimationBoundsLayer;

        mToken.mSurfaceAnimator.cancelAnimation();
        verify(mTransaction).destroy(eq(leash));
        verify(mTransaction).destroy(eq(animationBoundsLayer));
        assertThat(mToken.mNeedsAnimationBoundsLayer).isFalse();
    }

    @Test
    public void clipNoneAnim_boundsLayerIsNotCreated() throws Exception {
        mToken.mNeedsAnimationBoundsLayer = false;

        mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
        verify(mTransaction).reparent(eq(mToken.getSurfaceControl()),
                eq(mToken.mSurfaceAnimator.mLeash.getHandle()));
        assertThat(mToken.mAnimationBoundsLayer).isNull();
    }
}
+0 −5
Original line number Diff line number Diff line
@@ -70,8 +70,6 @@ public class WindowAnimationSpecTest {
                true /* isAppAnimation */);
        windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
        verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
        verify(mTransaction).setFinalCrop(eq(mSurfaceControl),
                argThat(rect -> rect.equals(mStackBounds)));
    }

    @Test
@@ -83,9 +81,6 @@ public class WindowAnimationSpecTest {
                true /* isAppAnimation */);
        windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
        verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
        verify(mTransaction).setFinalCrop(eq(mSurfaceControl),
                argThat(rect -> rect.left == 20 && rect.top == 40 && rect.right == 30
                        && rect.bottom == 50));
    }

    @Test
+14 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import android.os.Binder;
import android.os.IBinder;
import android.view.IApplicationToken;
import android.view.IWindow;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.WindowManager;

import static android.app.AppOpsManager.OP_NONE;
@@ -113,6 +115,7 @@ public class WindowTestUtils {
    /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
    public static class TestAppWindowToken extends AppWindowToken {
        boolean mOnTop = false;
        private Transaction mPendingTransactionOverride;

        private TestAppWindowToken(DisplayContent dc) {
            super(dc.mService, new IApplicationToken.Stub() {
@@ -158,6 +161,17 @@ public class WindowTestUtils {
        boolean isOnTop() {
            return mOnTop;
        }

        void setPendingTransaction(Transaction transaction) {
            mPendingTransactionOverride = transaction;
        }

        @Override
        public Transaction getPendingTransaction() {
            return mPendingTransactionOverride == null
                    ? super.getPendingTransaction()
                    : mPendingTransactionOverride;
        }
    }

    static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
Loading