1 /*
2  * Copyright (C) 2017 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.mock;
20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
21 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
22 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
25 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER;
26 
27 import static org.junit.Assert.assertNotNull;
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.ArgumentMatchers.anyBoolean;
30 import static org.mockito.ArgumentMatchers.eq;
31 import static org.mockito.Mockito.when;
32 
33 import android.graphics.Rect;
34 import android.platform.test.annotations.Presubmit;
35 import android.view.SurfaceControl;
36 import android.view.SurfaceSession;
37 
38 import com.android.server.wm.SurfaceAnimator.AnimationType;
39 import com.android.server.testutils.StubTransaction;
40 
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 
45 /**
46  * Build/Install/Run:
47  *  atest WmTests:DimmerTests
48  */
49 @Presubmit
50 @RunWith(WindowTestRunner.class)
51 public class DimmerTests extends WindowTestsBase {
52 
53     private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
54         final SurfaceControl mControl = mock(SurfaceControl.class);
55         final SurfaceControl.Transaction mPendingTransaction = spy(StubTransaction.class);
56         final SurfaceControl.Transaction mSyncTransaction = spy(StubTransaction.class);
57 
TestWindowContainer(WindowManagerService wm)58         TestWindowContainer(WindowManagerService wm) {
59             super(wm);
60         }
61 
62         @Override
getSurfaceControl()63         public SurfaceControl getSurfaceControl() {
64             return mControl;
65         }
66 
67         @Override
getSyncTransaction()68         public SurfaceControl.Transaction getSyncTransaction() {
69             return mSyncTransaction;
70         }
71 
72         @Override
getPendingTransaction()73         public SurfaceControl.Transaction getPendingTransaction() {
74             return mPendingTransaction;
75         }
76     }
77 
78     private static class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> {
79         final SurfaceSession mSession = new SurfaceSession();
80         final SurfaceControl mHostControl = mock(SurfaceControl.class);
81         final SurfaceControl.Transaction mHostTransaction = spy(StubTransaction.class);
82 
MockSurfaceBuildingContainer(WindowManagerService wm)83         MockSurfaceBuildingContainer(WindowManagerService wm) {
84             super(wm);
85         }
86 
87         class MockSurfaceBuilder extends SurfaceControl.Builder {
MockSurfaceBuilder(SurfaceSession ss)88             MockSurfaceBuilder(SurfaceSession ss) {
89                 super(ss);
90             }
91 
92             @Override
build()93             public SurfaceControl build() {
94                 SurfaceControl mSc = mock(SurfaceControl.class);
95                 when(mSc.isValid()).thenReturn(true);
96                 return mSc;
97             }
98         }
99 
100         @Override
makeChildSurface(WindowContainer child)101         SurfaceControl.Builder makeChildSurface(WindowContainer child) {
102             return new MockSurfaceBuilder(mSession);
103         }
104 
105         @Override
getSurfaceControl()106         public SurfaceControl getSurfaceControl() {
107             return mHostControl;
108         }
109 
110         @Override
getSyncTransaction()111         public SurfaceControl.Transaction getSyncTransaction() {
112             return mHostTransaction;
113         }
114 
115         @Override
getPendingTransaction()116         public SurfaceControl.Transaction getPendingTransaction() {
117             return mHostTransaction;
118         }
119     }
120 
121     private MockSurfaceBuildingContainer mHost;
122     private Dimmer mDimmer;
123     private SurfaceControl.Transaction mTransaction;
124     private Dimmer.SurfaceAnimatorStarter mSurfaceAnimatorStarter;
125 
126     private static class SurfaceAnimatorStarterImpl implements Dimmer.SurfaceAnimatorStarter {
127         @Override
startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t, AnimationAdapter anim, boolean hidden, @AnimationType int type)128         public void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t,
129                 AnimationAdapter anim, boolean hidden, @AnimationType int type) {
130             surfaceAnimator.mStaticAnimationFinishedCallback.onAnimationFinished(type, anim);
131         }
132     }
133 
134     @Before
setUp()135     public void setUp() throws Exception {
136         mHost = new MockSurfaceBuildingContainer(mWm);
137         mSurfaceAnimatorStarter = spy(new SurfaceAnimatorStarterImpl());
138         mTransaction = spy(StubTransaction.class);
139         mDimmer = new Dimmer(mHost, mSurfaceAnimatorStarter);
140     }
141 
142     @Test
testUpdateDimsAppliesCrop()143     public void testUpdateDimsAppliesCrop() {
144         TestWindowContainer child = new TestWindowContainer(mWm);
145         mHost.addChild(child, 0);
146 
147         final float alpha = 0.8f;
148         mDimmer.dimAbove(child, alpha);
149 
150         int width = 100;
151         int height = 300;
152         mDimmer.mDimState.mDimBounds.set(0, 0, width, height);
153         mDimmer.updateDims(mTransaction);
154 
155         verify(mTransaction).setWindowCrop(getDimLayer(), width, height);
156         verify(mTransaction).show(getDimLayer());
157     }
158 
159     @Test
testDimAboveWithChildCreatesSurfaceAboveChild()160     public void testDimAboveWithChildCreatesSurfaceAboveChild() {
161         TestWindowContainer child = new TestWindowContainer(mWm);
162         mHost.addChild(child, 0);
163 
164         final float alpha = 0.8f;
165         mDimmer.dimAbove(child, alpha);
166         SurfaceControl dimLayer = getDimLayer();
167 
168         assertNotNull("Dimmer should have created a surface", dimLayer);
169 
170         verify(mHost.getPendingTransaction()).setAlpha(dimLayer, alpha);
171         verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, child.mControl, 1);
172     }
173 
174     @Test
testDimBelowWithChildSurfaceCreatesSurfaceBelowChild()175     public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild() {
176         TestWindowContainer child = new TestWindowContainer(mWm);
177         mHost.addChild(child, 0);
178 
179         final float alpha = 0.8f;
180         mDimmer.dimBelow(child, alpha, 0);
181         SurfaceControl dimLayer = getDimLayer();
182 
183         assertNotNull("Dimmer should have created a surface", dimLayer);
184 
185         verify(mHost.getPendingTransaction()).setAlpha(dimLayer, alpha);
186         verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, child.mControl, -1);
187     }
188 
189     @Test
testDimBelowWithChildSurfaceDestroyedWhenReset()190     public void testDimBelowWithChildSurfaceDestroyedWhenReset() {
191         TestWindowContainer child = new TestWindowContainer(mWm);
192         mHost.addChild(child, 0);
193 
194         final float alpha = 0.8f;
195         mDimmer.dimAbove(child, alpha);
196         SurfaceControl dimLayer = getDimLayer();
197         mDimmer.resetDimStates();
198 
199         mDimmer.updateDims(mTransaction);
200         verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any(
201                 SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(),
202                 eq(ANIMATION_TYPE_DIMMER));
203         verify(mHost.getPendingTransaction()).remove(dimLayer);
204     }
205 
206     @Test
testDimBelowWithChildSurfaceNotDestroyedWhenPersisted()207     public void testDimBelowWithChildSurfaceNotDestroyedWhenPersisted() {
208         TestWindowContainer child = new TestWindowContainer(mWm);
209         mHost.addChild(child, 0);
210 
211         final float alpha = 0.8f;
212         mDimmer.dimAbove(child, alpha);
213         SurfaceControl dimLayer = getDimLayer();
214         mDimmer.resetDimStates();
215         mDimmer.dimAbove(child, alpha);
216 
217         mDimmer.updateDims(mTransaction);
218         verify(mTransaction).show(dimLayer);
219         verify(mTransaction, never()).remove(dimLayer);
220     }
221 
222     @Test
testDimUpdateWhileDimming()223     public void testDimUpdateWhileDimming() {
224         TestWindowContainer child = new TestWindowContainer(mWm);
225         mHost.addChild(child, 0);
226 
227         final float alpha = 0.8f;
228         mDimmer.dimAbove(child, alpha);
229         final Rect bounds = mDimmer.mDimState.mDimBounds;
230 
231         SurfaceControl dimLayer = getDimLayer();
232         bounds.set(0, 0, 10, 10);
233         mDimmer.updateDims(mTransaction);
234         verify(mTransaction).setWindowCrop(dimLayer, bounds.width(), bounds.height());
235         verify(mTransaction, times(1)).show(dimLayer);
236         verify(mTransaction).setPosition(dimLayer, 0, 0);
237 
238         bounds.set(10, 10, 30, 30);
239         mDimmer.updateDims(mTransaction);
240         verify(mTransaction).setWindowCrop(dimLayer, bounds.width(), bounds.height());
241         verify(mTransaction).setPosition(dimLayer, 10, 10);
242     }
243 
244     @Test
testRemoveDimImmediately()245     public void testRemoveDimImmediately() {
246         TestWindowContainer child = new TestWindowContainer(mWm);
247         mHost.addChild(child, 0);
248 
249         mDimmer.dimAbove(child, 1);
250         SurfaceControl dimLayer = getDimLayer();
251         mDimmer.updateDims(mTransaction);
252         verify(mTransaction, times(1)).show(dimLayer);
253 
254         reset(mSurfaceAnimatorStarter);
255         mDimmer.dontAnimateExit();
256         mDimmer.resetDimStates();
257         mDimmer.updateDims(mTransaction);
258         verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any(
259                 SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(),
260                 eq(ANIMATION_TYPE_DIMMER));
261         verify(mTransaction).remove(dimLayer);
262     }
263 
264     @Test
testDimmerWithBlurUpdatesTransaction()265     public void testDimmerWithBlurUpdatesTransaction() {
266         TestWindowContainer child = new TestWindowContainer(mWm);
267         mHost.addChild(child, 0);
268 
269         final int blurRadius = 50;
270         mDimmer.dimBelow(child, 0, blurRadius);
271         SurfaceControl dimLayer = getDimLayer();
272 
273         assertNotNull("Dimmer should have created a surface", dimLayer);
274 
275         verify(mHost.getPendingTransaction()).setBackgroundBlurRadius(dimLayer, blurRadius);
276         verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, child.mControl, -1);
277     }
278 
getDimLayer()279     private SurfaceControl getDimLayer() {
280         return mDimmer.mDimState.mDimLayer;
281     }
282 }
283