1 /* 2 * Copyright (C) 2020 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 static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotEquals; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.Mockito.any; 24 import static org.mockito.Mockito.eq; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.reset; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.app.PropertyInvalidatedCache; 31 import android.graphics.Point; 32 import android.util.SparseArray; 33 import android.view.Display; 34 import android.view.DisplayInfo; 35 import android.view.Surface; 36 import android.view.SurfaceControl; 37 38 import androidx.test.filters.SmallTest; 39 40 import com.android.server.display.layout.Layout; 41 42 import org.junit.Before; 43 import org.junit.Ignore; 44 import org.junit.Test; 45 46 import java.io.InputStream; 47 import java.io.OutputStream; 48 49 @SmallTest 50 public class LogicalDisplayTest { 51 private static final int DISPLAY_ID = 0; 52 private static final int LAYER_STACK = 0; 53 private static final int DISPLAY_WIDTH = 100; 54 private static final int DISPLAY_HEIGHT = 200; 55 private static final int MODE_ID = 1; 56 57 private LogicalDisplay mLogicalDisplay; 58 private DisplayDevice mDisplayDevice; 59 private DisplayDeviceRepository mDeviceRepo; 60 private final DisplayDeviceInfo mDisplayDeviceInfo = new DisplayDeviceInfo(); 61 62 @Before setUp()63 public void setUp() { 64 // Share classloader to allow package private access. 65 System.setProperty("dexmaker.share_classloader", "true"); 66 mDisplayDevice = mock(DisplayDevice.class); 67 mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice); 68 69 mDisplayDeviceInfo.copyFrom(new DisplayDeviceInfo()); 70 mDisplayDeviceInfo.width = DISPLAY_WIDTH; 71 mDisplayDeviceInfo.height = DISPLAY_HEIGHT; 72 mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; 73 mDisplayDeviceInfo.modeId = MODE_ID; 74 mDisplayDeviceInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID, 75 DISPLAY_WIDTH, DISPLAY_HEIGHT, /* refreshRate= */ 60)}; 76 when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(mDisplayDeviceInfo); 77 78 // Disable binder caches in this process. 79 PropertyInvalidatedCache.disableForTestMode(); 80 81 mDeviceRepo = new DisplayDeviceRepository( 82 new DisplayManagerService.SyncRoot(), 83 new PersistentDataStore(new PersistentDataStore.Injector() { 84 @Override 85 public InputStream openRead() { 86 return null; 87 } 88 89 @Override 90 public OutputStream startWrite() { 91 return null; 92 } 93 94 @Override 95 public void finishWrite(OutputStream os, boolean success) {} 96 })); 97 mDeviceRepo.onDisplayDeviceEvent(mDisplayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); 98 mLogicalDisplay.updateLocked(mDeviceRepo); 99 } 100 101 @Test testGetDisplayPosition()102 public void testGetDisplayPosition() { 103 Point expectedPosition = new Point(); 104 105 SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); 106 mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); 107 assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); 108 109 expectedPosition.set(20, 40); 110 mLogicalDisplay.setDisplayOffsetsLocked(20, 40); 111 mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); 112 assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); 113 114 DisplayInfo displayInfo = new DisplayInfo(); 115 displayInfo.logicalWidth = DISPLAY_WIDTH; 116 displayInfo.logicalHeight = DISPLAY_HEIGHT; 117 // Rotation doesn't matter when the FLAG_ROTATES_WITH_CONTENT is absent. 118 displayInfo.rotation = Surface.ROTATION_90; 119 mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo); 120 mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); 121 assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); 122 123 expectedPosition.set(40, -20); 124 mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; 125 mLogicalDisplay.updateLocked(mDeviceRepo); 126 displayInfo.logicalWidth = DISPLAY_HEIGHT; 127 displayInfo.logicalHeight = DISPLAY_WIDTH; 128 displayInfo.rotation = Surface.ROTATION_90; 129 mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo); 130 mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); 131 assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); 132 } 133 134 // TODO: b/288880734 - fix test after display tests migration 135 @Test 136 @Ignore testDisplayInputFlags()137 public void testDisplayInputFlags() { 138 SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); 139 mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); 140 verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT)); 141 reset(t); 142 143 mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_NONE; 144 mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); 145 verify(t).setDisplayFlags(any(), eq(0)); 146 reset(t); 147 148 mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_VIRTUAL; 149 mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); 150 verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT)); 151 reset(t); 152 153 mLogicalDisplay.setEnabledLocked(false); 154 mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); 155 verify(t).setDisplayFlags(any(), eq(0)); 156 reset(t); 157 158 mLogicalDisplay.setEnabledLocked(true); 159 mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; 160 mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); 161 verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT)); 162 reset(t); 163 } 164 165 @Test testRearDisplaysArePresentationDisplaysThatDestroyContentOnRemoval()166 public void testRearDisplaysArePresentationDisplaysThatDestroyContentOnRemoval() { 167 // Assert that the display isn't a presentation display by default, with a default remove 168 // mode 169 assertEquals(0, mLogicalDisplay.getDisplayInfoLocked().flags); 170 assertEquals(Display.REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY, 171 mLogicalDisplay.getDisplayInfoLocked().removeMode); 172 173 // Update position and test to see that it's been updated to a rear, presentation display 174 // that destroys content on removal 175 mLogicalDisplay.setDevicePositionLocked(Layout.Display.POSITION_REAR); 176 mLogicalDisplay.updateLocked(mDeviceRepo); 177 assertEquals(Display.FLAG_REAR | Display.FLAG_PRESENTATION, 178 mLogicalDisplay.getDisplayInfoLocked().flags); 179 assertEquals(Display.REMOVE_MODE_DESTROY_CONTENT, 180 mLogicalDisplay.getDisplayInfoLocked().removeMode); 181 182 // And then check the unsetting the position resets both 183 mLogicalDisplay.setDevicePositionLocked(Layout.Display.POSITION_UNKNOWN); 184 mLogicalDisplay.updateLocked(mDeviceRepo); 185 assertEquals(0, mLogicalDisplay.getDisplayInfoLocked().flags); 186 assertEquals(Display.REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY, 187 mLogicalDisplay.getDisplayInfoLocked().removeMode); 188 } 189 190 @Test testUpdateLayoutLimitedRefreshRate()191 public void testUpdateLayoutLimitedRefreshRate() { 192 SurfaceControl.RefreshRateRange layoutLimitedRefreshRate = 193 new SurfaceControl.RefreshRateRange(0, 120); 194 DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked(); 195 mLogicalDisplay.updateLayoutLimitedRefreshRateLocked(layoutLimitedRefreshRate); 196 DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked(); 197 // Display info should only be updated when updateLocked is called 198 assertEquals(info2, info1); 199 200 mLogicalDisplay.updateLocked(mDeviceRepo); 201 DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked(); 202 assertNotEquals(info3, info2); 203 assertEquals(layoutLimitedRefreshRate, info3.layoutLimitedRefreshRate); 204 } 205 206 @Test testUpdateLayoutLimitedRefreshRate_setsDirtyFlag()207 public void testUpdateLayoutLimitedRefreshRate_setsDirtyFlag() { 208 SurfaceControl.RefreshRateRange layoutLimitedRefreshRate = 209 new SurfaceControl.RefreshRateRange(0, 120); 210 assertFalse(mLogicalDisplay.isDirtyLocked()); 211 212 mLogicalDisplay.updateLayoutLimitedRefreshRateLocked(layoutLimitedRefreshRate); 213 assertTrue(mLogicalDisplay.isDirtyLocked()); 214 215 mLogicalDisplay.updateLocked(mDeviceRepo); 216 assertFalse(mLogicalDisplay.isDirtyLocked()); 217 } 218 219 @Test testUpdateRefreshRateThermalThrottling()220 public void testUpdateRefreshRateThermalThrottling() { 221 SparseArray<SurfaceControl.RefreshRateRange> refreshRanges = new SparseArray<>(); 222 refreshRanges.put(0, new SurfaceControl.RefreshRateRange(0, 120)); 223 DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked(); 224 mLogicalDisplay.updateThermalRefreshRateThrottling(refreshRanges); 225 DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked(); 226 // Display info should only be updated when updateLocked is called 227 assertEquals(info2, info1); 228 229 mLogicalDisplay.updateLocked(mDeviceRepo); 230 DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked(); 231 assertNotEquals(info3, info2); 232 assertTrue(refreshRanges.contentEquals(info3.thermalRefreshRateThrottling)); 233 } 234 235 @Test testUpdateRefreshRateThermalThrottling_setsDirtyFlag()236 public void testUpdateRefreshRateThermalThrottling_setsDirtyFlag() { 237 SparseArray<SurfaceControl.RefreshRateRange> refreshRanges = new SparseArray<>(); 238 refreshRanges.put(0, new SurfaceControl.RefreshRateRange(0, 120)); 239 assertFalse(mLogicalDisplay.isDirtyLocked()); 240 241 mLogicalDisplay.updateThermalRefreshRateThrottling(refreshRanges); 242 assertTrue(mLogicalDisplay.isDirtyLocked()); 243 244 mLogicalDisplay.updateLocked(mDeviceRepo); 245 assertFalse(mLogicalDisplay.isDirtyLocked()); 246 } 247 248 @Test testUpdateDisplayGroupIdLocked()249 public void testUpdateDisplayGroupIdLocked() { 250 int newId = 999; 251 DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked(); 252 mLogicalDisplay.updateDisplayGroupIdLocked(newId); 253 DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked(); 254 // Display info should only be updated when updateLocked is called 255 assertEquals(info2, info1); 256 257 mLogicalDisplay.updateLocked(mDeviceRepo); 258 DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked(); 259 assertNotEquals(info3, info2); 260 assertEquals(newId, info3.displayGroupId); 261 } 262 263 @Test testUpdateDisplayGroupIdLocked_setsDirtyFlag()264 public void testUpdateDisplayGroupIdLocked_setsDirtyFlag() { 265 assertFalse(mLogicalDisplay.isDirtyLocked()); 266 267 mLogicalDisplay.updateDisplayGroupIdLocked(99); 268 assertTrue(mLogicalDisplay.isDirtyLocked()); 269 270 mLogicalDisplay.updateLocked(mDeviceRepo); 271 assertFalse(mLogicalDisplay.isDirtyLocked()); 272 } 273 274 @Test testSetThermalBrightnessThrottlingDataId()275 public void testSetThermalBrightnessThrottlingDataId() { 276 String brightnessThrottlingDataId = "throttling_data_id"; 277 DisplayInfo info1 = mLogicalDisplay.getDisplayInfoLocked(); 278 mLogicalDisplay.setThermalBrightnessThrottlingDataIdLocked(brightnessThrottlingDataId); 279 DisplayInfo info2 = mLogicalDisplay.getDisplayInfoLocked(); 280 // Display info should only be updated when updateLocked is called 281 assertEquals(info2, info1); 282 283 mLogicalDisplay.updateLocked(mDeviceRepo); 284 DisplayInfo info3 = mLogicalDisplay.getDisplayInfoLocked(); 285 assertNotEquals(info3, info2); 286 assertEquals(brightnessThrottlingDataId, info3.thermalBrightnessThrottlingDataId); 287 } 288 289 @Test testSetThermalBrightnessThrottlingDataId_setsDirtyFlag()290 public void testSetThermalBrightnessThrottlingDataId_setsDirtyFlag() { 291 assertFalse(mLogicalDisplay.isDirtyLocked()); 292 293 mLogicalDisplay.setThermalBrightnessThrottlingDataIdLocked("99"); 294 assertTrue(mLogicalDisplay.isDirtyLocked()); 295 296 mLogicalDisplay.updateLocked(mDeviceRepo); 297 assertFalse(mLogicalDisplay.isDirtyLocked()); 298 } 299 } 300