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.display; 18 19 import android.content.Context; 20 import android.hardware.display.BrightnessConfiguration; 21 import android.hardware.display.Curve; 22 import android.hardware.display.DisplayManager; 23 import android.hardware.display.DisplayViewport; 24 import android.hardware.display.IVirtualDisplayCallback; 25 import android.hardware.input.InputManagerInternal; 26 import android.os.Handler; 27 import android.os.IBinder; 28 import android.os.UserHandle; 29 import android.test.AndroidTestCase; 30 import android.test.suitebuilder.annotation.SmallTest; 31 import android.view.SurfaceControl; 32 33 import com.android.server.LocalServices; 34 import com.android.server.SystemService; 35 import com.android.server.display.DisplayDeviceInfo; 36 import com.android.server.display.DisplayManagerService.SyncRoot; 37 import com.android.server.display.VirtualDisplayAdapter.SurfaceControlDisplayFactory; 38 import com.android.server.lights.LightsManager; 39 import com.android.server.wm.WindowManagerInternal; 40 41 import org.mockito.ArgumentCaptor; 42 import org.mockito.Mock; 43 import org.mockito.MockitoAnnotations; 44 45 import java.util.List; 46 47 import static org.mockito.Matchers.any; 48 import static org.mockito.Mockito.verify; 49 import static org.mockito.Mockito.when; 50 import static org.mockito.Mockito.mock; 51 52 @SmallTest 53 public class DisplayManagerServiceTest extends AndroidTestCase { 54 private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1; 55 private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10; 56 57 private final DisplayManagerService.Injector mShortMockedInjector = 58 new DisplayManagerService.Injector() { 59 @Override 60 VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, 61 Context context, Handler handler, DisplayAdapter.Listener listener) { 62 return mMockVirtualDisplayAdapter; 63 } 64 65 @Override 66 long getDefaultDisplayDelayTimeout() { 67 return SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS; 68 } 69 }; 70 private final DisplayManagerService.Injector mBasicInjector = 71 new DisplayManagerService.Injector() { 72 @Override 73 VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, 74 Context context, Handler handler, 75 DisplayAdapter.Listener displayAdapterListener) { 76 return new VirtualDisplayAdapter(syncRoot, context, handler, 77 displayAdapterListener, 78 (String name, boolean secure) -> mMockDisplayToken); 79 } 80 }; 81 82 @Mock InputManagerInternal mMockInputManagerInternal; 83 @Mock IVirtualDisplayCallback.Stub mMockAppToken; 84 @Mock WindowManagerInternal mMockWindowManagerInternal; 85 @Mock LightsManager mMockLightsManager; 86 @Mock VirtualDisplayAdapter mMockVirtualDisplayAdapter; 87 @Mock IBinder mMockDisplayToken; 88 89 @Override 90 protected void setUp() throws Exception { 91 MockitoAnnotations.initMocks(this); 92 93 LocalServices.removeServiceForTest(InputManagerInternal.class); 94 LocalServices.addService(InputManagerInternal.class, mMockInputManagerInternal); 95 LocalServices.removeServiceForTest(WindowManagerInternal.class); 96 LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal); 97 LocalServices.removeServiceForTest(LightsManager.class); 98 LocalServices.addService(LightsManager.class, mMockLightsManager); 99 super.setUp(); 100 } 101 102 @Override 103 protected void tearDown() throws Exception { 104 super.tearDown(); 105 } 106 107 public void testCreateVirtualDisplay_sentToInputManager() throws Exception { 108 DisplayManagerService displayManager = 109 new DisplayManagerService(mContext, mBasicInjector); 110 registerDefaultDisplays(displayManager); 111 displayManager.systemReady(false /* safeMode */, true /* onlyCore */); 112 displayManager.windowManagerAndInputReady(); 113 114 // This is effectively the DisplayManager service published to ServiceManager. 115 DisplayManagerService.BinderService bs = displayManager.new BinderService(); 116 117 String uniqueId = "uniqueId --- Test"; 118 String uniqueIdPrefix = "virtual:" + mContext.getPackageName() + ":"; 119 int width = 600; 120 int height = 800; 121 int dpi = 320; 122 int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH; 123 124 when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); 125 int displayId = bs.createVirtualDisplay(mMockAppToken /* callback */, 126 null /* projection */, "com.android.frameworks.servicestests", 127 "Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */, 128 uniqueId); 129 130 displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); 131 132 // flush the handler 133 displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */); 134 135 ArgumentCaptor<List<DisplayViewport>> virtualViewportCaptor = 136 ArgumentCaptor.forClass(List.class); 137 verify(mMockInputManagerInternal).setDisplayViewports( 138 any(), any(), virtualViewportCaptor.capture()); 139 140 assertEquals(1, virtualViewportCaptor.getValue().size()); 141 DisplayViewport dv = virtualViewportCaptor.getValue().get(0); 142 assertEquals(height, dv.deviceHeight); 143 assertEquals(width, dv.deviceWidth); 144 assertEquals(uniqueIdPrefix + uniqueId, dv.uniqueId); 145 assertEquals(displayId, dv.displayId); 146 } 147 148 public void testCreateVirtualDisplayRotatesWithContent() throws Exception { 149 DisplayManagerService displayManager = 150 new DisplayManagerService(mContext, mBasicInjector); 151 registerDefaultDisplays(displayManager); 152 153 // This is effectively the DisplayManager service published to ServiceManager. 154 DisplayManagerService.BinderService bs = displayManager.new BinderService(); 155 156 String uniqueId = "uniqueId --- Rotates With Content Test"; 157 int width = 600; 158 int height = 800; 159 int dpi = 320; 160 int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT; 161 162 when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); 163 int displayId = bs.createVirtualDisplay(mMockAppToken /* callback */, 164 null /* projection */, "com.android.frameworks.servicestests", 165 "Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */, 166 uniqueId); 167 168 displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); 169 170 // flush the handler 171 displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */); 172 173 DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId); 174 assertNotNull(ddi); 175 assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0); 176 } 177 178 /** 179 * Tests that the virtual display is created along-side the default display. 180 */ 181 public void testStartVirtualDisplayWithDefaultDisplay_Succeeds() throws Exception { 182 DisplayManagerService displayManager = 183 new DisplayManagerService(mContext, mShortMockedInjector); 184 registerDefaultDisplays(displayManager); 185 displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); 186 } 187 188 /** 189 * Tests that we get a Runtime exception when we cannot initialize the default display. 190 */ 191 public void testStartVirtualDisplayWithDefDisplay_NoDefaultDisplay() throws Exception { 192 DisplayManagerService displayManager = 193 new DisplayManagerService(mContext, mShortMockedInjector); 194 Handler handler = displayManager.getDisplayHandler(); 195 handler.runWithScissors(() -> {}, 0 /* now */); 196 197 try { 198 displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); 199 } catch (RuntimeException e) { 200 return; 201 } 202 fail("Expected DisplayManager to throw RuntimeException when it cannot initialize the" 203 + " default display"); 204 } 205 206 /** 207 * Tests that we get a Runtime exception when we cannot initialize the virtual display. 208 */ 209 public void testStartVirtualDisplayWithDefDisplay_NoVirtualDisplayAdapter() throws Exception { 210 DisplayManagerService displayManager = new DisplayManagerService(mContext, 211 new DisplayManagerService.Injector() { 212 @Override 213 VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, 214 Context context, Handler handler, DisplayAdapter.Listener listener) { 215 return null; // return null for the adapter. This should cause a failure. 216 } 217 218 @Override 219 long getDefaultDisplayDelayTimeout() { 220 return SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS; 221 } 222 }); 223 try { 224 displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); 225 } catch (RuntimeException e) { 226 return; 227 } 228 fail("Expected DisplayManager to throw RuntimeException when it cannot initialize the" 229 + " virtual display adapter"); 230 } 231 232 /** 233 * Tests that an exception is raised for too dark a brightness configuration. 234 */ 235 public void testTooDarkBrightnessConfigurationThrowException() { 236 DisplayManagerService displayManager = 237 new DisplayManagerService(mContext, mShortMockedInjector); 238 Curve minimumBrightnessCurve = displayManager.getMinimumBrightnessCurveInternal(); 239 float[] lux = minimumBrightnessCurve.getX(); 240 float[] minimumNits = minimumBrightnessCurve.getY(); 241 float[] nits = new float[minimumNits.length]; 242 // For every control point, assert that making it slightly lower than the minimum throws an 243 // exception. 244 for (int i = 0; i < nits.length; i++) { 245 for (int j = 0; j < nits.length; j++) { 246 nits[j] = minimumNits[j]; 247 if (j == i) { 248 nits[j] -= 0.1f; 249 } 250 if (nits[j] < 0) { 251 nits[j] = 0; 252 } 253 } 254 BrightnessConfiguration config = 255 new BrightnessConfiguration.Builder(lux, nits).build(); 256 Exception thrown = null; 257 try { 258 displayManager.validateBrightnessConfiguration(config); 259 } catch (IllegalArgumentException e) { 260 thrown = e; 261 } 262 assertNotNull("Building too dark a brightness configuration must throw an exception"); 263 } 264 } 265 266 /** 267 * Tests that no exception is raised for not too dark a brightness configuration. 268 */ 269 public void testBrightEnoughBrightnessConfigurationDoesNotThrowException() { 270 DisplayManagerService displayManager = 271 new DisplayManagerService(mContext, mShortMockedInjector); 272 Curve minimumBrightnessCurve = displayManager.getMinimumBrightnessCurveInternal(); 273 float[] lux = minimumBrightnessCurve.getX(); 274 float[] nits = minimumBrightnessCurve.getY(); 275 BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits).build(); 276 displayManager.validateBrightnessConfiguration(config); 277 } 278 279 /** 280 * Tests that null brightness configurations are alright. 281 */ 282 public void testNullBrightnessConfiguration() { 283 DisplayManagerService displayManager = 284 new DisplayManagerService(mContext, mShortMockedInjector); 285 displayManager.validateBrightnessConfiguration(null); 286 } 287 288 private void registerDefaultDisplays(DisplayManagerService displayManager) { 289 Handler handler = displayManager.getDisplayHandler(); 290 // Would prefer to call displayManager.onStart() directly here but it performs binderService 291 // registration which triggers security exceptions when running from a test. 292 handler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS); 293 // flush the handler 294 handler.runWithScissors(() -> {}, 0 /* now */); 295 } 296 } 297