1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
20 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.ArgumentMatchers.eq;
26 import static org.mockito.ArgumentMatchers.intThat;
27 
28 import android.platform.test.annotations.Presubmit;
29 import android.view.SurfaceControl;
30 
31 import androidx.test.filters.SmallTest;
32 
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 import org.mockito.ArgumentCaptor;
37 import org.mockito.Mock;
38 import org.mockito.MockitoAnnotations;
39 
40 
41 /**
42  * Animation related tests for the {@link ActivityRecord} class.
43  *
44  * Build/Install/Run:
45  *  atest AppWindowTokenAnimationTests
46  */
47 @SmallTest
48 @Presubmit
49 @RunWith(WindowTestRunner.class)
50 public class AppWindowTokenAnimationTests extends WindowTestsBase {
51 
52     private ActivityRecord mActivity;
53 
54     @Mock
55     private AnimationAdapter mSpec;
56 
57     @Before
setUp()58     public void setUp() throws Exception {
59         MockitoAnnotations.initMocks(this);
60 
61         mActivity = createActivityRecord(mDisplayContent);
62     }
63 
64     @Test
clipAfterAnim_boundsLayerIsCreated()65     public void clipAfterAnim_boundsLayerIsCreated() {
66         mActivity.mNeedsAnimationBoundsLayer = true;
67 
68         mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
69                 ANIMATION_TYPE_APP_TRANSITION);
70         verify(mTransaction).reparent(eq(mActivity.getSurfaceControl()),
71                 eq(mActivity.mSurfaceAnimator.mLeash));
72         verify(mTransaction).reparent(eq(mActivity.mSurfaceAnimator.mLeash),
73                 eq(mActivity.mAnimationBoundsLayer));
74     }
75 
76     @Test
clipAfterAnim_boundsLayerZBoosted()77     public void clipAfterAnim_boundsLayerZBoosted() {
78         final Task task = mActivity.getTask();
79         final ActivityRecord topActivity = createActivityRecord(task);
80         task.assignChildLayers(mTransaction);
81 
82         assertThat(topActivity.getLastLayer()).isGreaterThan(mActivity.getLastLayer());
83 
84         mActivity.mNeedsAnimationBoundsLayer = true;
85         mActivity.mNeedsZBoost = true;
86         mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
87                 ANIMATION_TYPE_APP_TRANSITION);
88 
89         verify(mTransaction).setLayer(eq(mActivity.mAnimationBoundsLayer),
90                 intThat(layer -> layer > topActivity.getLastLayer()));
91 
92         // The layer should be restored after the animation leash is removed.
93         mActivity.onAnimationLeashLost(mTransaction);
94         assertThat(mActivity.mNeedsZBoost).isFalse();
95         assertThat(topActivity.getLastLayer()).isGreaterThan(mActivity.getLastLayer());
96     }
97 
98     @Test
clipAfterAnim_boundsLayerIsDestroyed()99     public void clipAfterAnim_boundsLayerIsDestroyed() {
100         mActivity.mNeedsAnimationBoundsLayer = true;
101         mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
102                 ANIMATION_TYPE_APP_TRANSITION);
103         final SurfaceControl leash = mActivity.mSurfaceAnimator.mLeash;
104         final SurfaceControl animationBoundsLayer = mActivity.mAnimationBoundsLayer;
105         final ArgumentCaptor<SurfaceAnimator.OnAnimationFinishedCallback> callbackCaptor =
106                 ArgumentCaptor.forClass(
107                         SurfaceAnimator.OnAnimationFinishedCallback.class);
108         verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION),
109                 callbackCaptor.capture());
110 
111         callbackCaptor.getValue().onAnimationFinished(
112                 ANIMATION_TYPE_APP_TRANSITION, mSpec);
113         verify(mTransaction).remove(eq(leash));
114         verify(mTransaction).remove(eq(animationBoundsLayer));
115         assertThat(mActivity.mNeedsAnimationBoundsLayer).isFalse();
116     }
117 
118     @Test
clipAfterAnimCancelled_boundsLayerIsDestroyed()119     public void clipAfterAnimCancelled_boundsLayerIsDestroyed() {
120         mActivity.mNeedsAnimationBoundsLayer = true;
121         mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
122                 ANIMATION_TYPE_APP_TRANSITION);
123         final SurfaceControl leash = mActivity.mSurfaceAnimator.mLeash;
124         final SurfaceControl animationBoundsLayer = mActivity.mAnimationBoundsLayer;
125 
126         mActivity.mSurfaceAnimator.cancelAnimation();
127         verify(mTransaction).remove(eq(leash));
128         verify(mTransaction).remove(eq(animationBoundsLayer));
129         assertThat(mActivity.mNeedsAnimationBoundsLayer).isFalse();
130     }
131 
132     @Test
clipNoneAnim_boundsLayerIsNotCreated()133     public void clipNoneAnim_boundsLayerIsNotCreated() {
134         mActivity.mNeedsAnimationBoundsLayer = false;
135 
136         mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
137                 ANIMATION_TYPE_APP_TRANSITION);
138         verify(mTransaction).reparent(eq(mActivity.getSurfaceControl()),
139                 eq(mActivity.mSurfaceAnimator.mLeash));
140         assertThat(mActivity.mAnimationBoundsLayer).isNull();
141     }
142 }
143