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