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