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
17package com.android.server.display;
18
19import android.content.Context;
20import android.hardware.display.BrightnessConfiguration;
21import android.hardware.display.Curve;
22import android.hardware.display.DisplayManager;
23import android.hardware.display.DisplayViewport;
24import android.hardware.display.IVirtualDisplayCallback;
25import android.hardware.input.InputManagerInternal;
26import android.os.Handler;
27import android.os.IBinder;
28import android.os.UserHandle;
29import android.test.AndroidTestCase;
30import android.test.suitebuilder.annotation.SmallTest;
31import android.view.SurfaceControl;
32
33import com.android.server.LocalServices;
34import com.android.server.SystemService;
35import com.android.server.display.DisplayDeviceInfo;
36import com.android.server.display.DisplayManagerService.SyncRoot;
37import com.android.server.display.VirtualDisplayAdapter.SurfaceControlDisplayFactory;
38import com.android.server.lights.LightsManager;
39import com.android.server.wm.WindowManagerInternal;
40
41import org.mockito.ArgumentCaptor;
42import org.mockito.Mock;
43import org.mockito.MockitoAnnotations;
44
45import java.util.List;
46
47import static org.mockito.Matchers.any;
48import static org.mockito.Mockito.verify;
49import static org.mockito.Mockito.when;
50import static org.mockito.Mockito.mock;
51
52@SmallTest
53public 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