blob: 885feeabbe068fc5ddd41604dc84fb5b1da92840 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.display;
import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
import static android.Manifest.permission.MANAGE_DISPLAYS;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PropertyInvalidatedCache;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Rect;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.Curve;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
import android.hardware.display.HdrConversionMode;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.MessageQueue;
import android.os.Process;
import android.os.RemoteException;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.DisplayWindowPolicyController;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.display.DisplayManagerService.DeviceStateListener;
import com.android.server.display.DisplayManagerService.SyncRoot;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.input.InputManagerInternal;
import com.android.server.lights.LightsManager;
import com.android.server.pm.UserManagerInternal;
import com.android.server.sensors.SensorManagerInternal;
import com.android.server.wm.WindowManagerInternal;
import com.google.common.truth.Expect;
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.LongStream;
// TODO(b/297170420) Parameterize the test.
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DisplayManagerServiceTest {
private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10;
private static final float FLOAT_TOLERANCE = 0.01f;
private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";
private static final String PACKAGE_NAME = "com.android.frameworks.displayservicetests";
private static final long STANDARD_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED
| DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
private static final long STANDARD_AND_CONNECTION_DISPLAY_EVENTS =
STANDARD_DISPLAY_EVENTS | DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED;
private static final String EVENT_DISPLAY_ADDED = "EVENT_DISPLAY_ADDED";
private static final String EVENT_DISPLAY_REMOVED = "EVENT_DISPLAY_REMOVED";
private static final String EVENT_DISPLAY_CHANGED = "EVENT_DISPLAY_CHANGED";
private static final String EVENT_DISPLAY_BRIGHTNESS_CHANGED =
"EVENT_DISPLAY_BRIGHTNESS_CHANGED";
private static final String EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED =
"EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED";
private static final String EVENT_DISPLAY_CONNECTED = "EVENT_DISPLAY_CONNECTED";
private static final String EVENT_DISPLAY_DISCONNECTED = "EVENT_DISPLAY_DISCONNECTED";
private static final String DISPLAY_GROUP_EVENT_ADDED = "DISPLAY_GROUP_EVENT_ADDED";
private static final String DISPLAY_GROUP_EVENT_REMOVED = "DISPLAY_GROUP_EVENT_REMOVED";
private static final String DISPLAY_GROUP_EVENT_CHANGED = "DISPLAY_GROUP_EVENT_CHANGED";
@Rule(order = 0)
public TestRule compatChangeRule = new PlatformCompatChangeRule();
@Rule(order = 1)
public Expect expect = Expect.create();
private Context mContext;
private Resources mResources;
private int mHdrConversionMode;
private int mPreferredHdrOutputType;
private final DisplayManagerService.Injector mShortMockedInjector =
new DisplayManagerService.Injector() {
@Override
VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot,
Context context, Handler handler, DisplayAdapter.Listener listener) {
return mMockVirtualDisplayAdapter;
}
@Override
LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context,
Handler handler, DisplayAdapter.Listener displayAdapterListener) {
return new LocalDisplayAdapter(syncRoot, context, handler,
displayAdapterListener, new LocalDisplayAdapter.Injector() {
@Override
public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() {
return mSurfaceControlProxy;
}
});
}
@Override
long getDefaultDisplayDelayTimeout() {
return SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS;
}
};
class BasicInjector extends DisplayManagerService.Injector {
@Override
IMediaProjectionManager getProjectionService() {
return mMockProjectionService;
}
@Override
DisplayManagerFlags getFlags() {
return mMockFlags;
}
@Override
VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
Handler handler, DisplayAdapter.Listener displayAdapterListener) {
return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
new VirtualDisplayAdapter.SurfaceControlDisplayFactory() {
@Override
public IBinder createDisplay(String name, boolean secure,
float requestedRefreshRate) {
return mMockDisplayToken;
}
@Override
public void destroyDisplay(IBinder displayToken) {
}
});
}
@Override
LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context,
Handler handler, DisplayAdapter.Listener displayAdapterListener) {
return new LocalDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
new LocalDisplayAdapter.Injector() {
@Override
public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() {
return mSurfaceControlProxy;
}
});
}
@Override
int setHdrConversionMode(int conversionMode, int preferredHdrOutputType,
int[] autoHdrTypes) {
mHdrConversionMode = conversionMode;
mPreferredHdrOutputType = preferredHdrOutputType;
return Display.HdrCapabilities.HDR_TYPE_INVALID;
}
@Override
int[] getSupportedHdrOutputTypes() {
return new int[]{};
}
@Override
int[] getHdrOutputTypesWithLatency() {
return new int[]{Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION};
}
boolean getHdrOutputConversionSupport() {
return true;
}
}
private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
@Mock IMediaProjectionManager mMockProjectionService;
@Mock IVirtualDeviceManager mIVirtualDeviceManager;
@Mock InputManagerInternal mMockInputManagerInternal;
@Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
@Mock IVirtualDisplayCallback.Stub mMockAppToken;
@Mock IVirtualDisplayCallback.Stub mMockAppToken2;
@Mock IVirtualDisplayCallback.Stub mMockAppToken3;
@Mock WindowManagerInternal mMockWindowManagerInternal;
@Mock LightsManager mMockLightsManager;
@Mock VirtualDisplayAdapter mMockVirtualDisplayAdapter;
@Mock LocalDisplayAdapter.SurfaceControlProxy mSurfaceControlProxy;
@Mock IBinder mMockDisplayToken;
@Mock SensorManagerInternal mMockSensorManagerInternal;
@Mock SensorManager mSensorManager;
@Mock DisplayDeviceConfig mMockDisplayDeviceConfig;
@Mock PackageManagerInternal mMockPackageManagerInternal;
@Mock UserManagerInternal mMockUserManagerInternal;
@Captor ArgumentCaptor<ContentRecordingSession> mContentRecordingSessionCaptor;
@Mock DisplayManagerFlags mMockFlags;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(false);
LocalServices.removeServiceForTest(InputManagerInternal.class);
LocalServices.addService(InputManagerInternal.class, mMockInputManagerInternal);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal);
LocalServices.removeServiceForTest(LightsManager.class);
LocalServices.addService(LightsManager.class, mMockLightsManager);
LocalServices.removeServiceForTest(SensorManagerInternal.class);
LocalServices.addService(SensorManagerInternal.class, mMockSensorManagerInternal);
LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
LocalServices.addService(
VirtualDeviceManagerInternal.class, mMockVirtualDeviceManagerInternal);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
LocalServices.removeServiceForTest(UserManagerInternal.class);
LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
// TODO: b/287945043
Display display = mock(Display.class);
when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments());
when(display.getBrightnessInfo()).thenReturn(mock(BrightnessInfo.class));
mContext = spy(new ContextWrapper(
ApplicationProvider.getApplicationContext().createDisplayContext(display)));
mResources = Mockito.spy(mContext.getResources());
manageDisplaysPermission(/* granted= */ false);
when(mContext.getResources()).thenReturn(mResources);
VirtualDeviceManager vdm = new VirtualDeviceManager(mIVirtualDeviceManager, mContext);
when(mContext.getSystemService(VirtualDeviceManager.class)).thenReturn(vdm);
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
setUpDisplay();
}
private void setUpDisplay() {
long[] ids = new long[] {100};
when(mSurfaceControlProxy.getPhysicalDisplayIds()).thenReturn(ids);
when(mSurfaceControlProxy.getPhysicalDisplayToken(anyLong()))
.thenReturn(mMockDisplayToken);
SurfaceControl.StaticDisplayInfo staticDisplayInfo = new SurfaceControl.StaticDisplayInfo();
staticDisplayInfo.isInternal = true;
when(mSurfaceControlProxy.getStaticDisplayInfo(anyLong()))
.thenReturn(staticDisplayInfo);
SurfaceControl.DynamicDisplayInfo dynamicDisplayMode =
new SurfaceControl.DynamicDisplayInfo();
SurfaceControl.DisplayMode displayMode = new SurfaceControl.DisplayMode();
displayMode.width = 100;
displayMode.height = 200;
displayMode.supportedHdrTypes = new int[]{1, 2};
dynamicDisplayMode.supportedDisplayModes = new SurfaceControl.DisplayMode[] {displayMode};
when(mSurfaceControlProxy.getDynamicDisplayInfo(anyLong()))
.thenReturn(dynamicDisplayMode);
when(mSurfaceControlProxy.getDesiredDisplayModeSpecs(mMockDisplayToken))
.thenReturn(new SurfaceControl.DesiredDisplayModeSpecs());
}
@Test
public void testCreateVirtualDisplay_sentToInputManager() throws RemoteException {
// This is to update the display device config such that DisplayManagerService can ignore
// the usage of SensorManager, which is available only after the PowerManagerService
// is ready.
resetConfigToIgnoreSensorManager();
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
displayManager.systemReady(false /* safeMode */);
displayManager.windowManagerAndInputReady();
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService bs = displayManager.new BinderService();
String uniqueId = "uniqueId --- Test";
String uniqueIdPrefix = UNIQUE_ID_PREFIX + mContext.getPackageName() + ":";
int width = 600;
int height = 800;
int dpi = 320;
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setUniqueId(uniqueId);
builder.setFlags(flags);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
ArgumentCaptor<List<DisplayViewport>> viewportCaptor = ArgumentCaptor.forClass(List.class);
verify(mMockInputManagerInternal).setDisplayViewports(viewportCaptor.capture());
List<DisplayViewport> viewports = viewportCaptor.getValue();
// Expect to receive at least 2 viewports: at least 1 internal, and 1 virtual
assertTrue(viewports.size() >= 2);
DisplayViewport virtualViewport = null;
DisplayViewport internalViewport = null;
for (int i = 0; i < viewports.size(); i++) {
DisplayViewport v = viewports.get(i);
switch (v.type) {
case DisplayViewport.VIEWPORT_INTERNAL: {
// If more than one internal viewport, this will get overwritten several times,
// which for the purposes of this test is fine.
internalViewport = v;
assertTrue(internalViewport.valid);
break;
}
case DisplayViewport.VIEWPORT_EXTERNAL: {
// External view port is present for auto devices in the form of instrument
// cluster.
break;
}
case DisplayViewport.VIEWPORT_VIRTUAL: {
virtualViewport = v;
break;
}
}
}
// INTERNAL viewport gets created upon access.
assertNotNull(internalViewport);
assertNotNull(virtualViewport);
// VIRTUAL
assertEquals(height, virtualViewport.deviceHeight);
assertEquals(width, virtualViewport.deviceWidth);
assertEquals(uniqueIdPrefix + uniqueId, virtualViewport.uniqueId);
assertEquals(displayId, virtualViewport.displayId);
}
@Test
public void testPhysicalViewports() {
// This is to update the display device config such that DisplayManagerService can ignore
// the usage of SensorManager, which is available only after the PowerManagerService
// is ready.
resetConfigToIgnoreSensorManager();
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
displayManager.systemReady(false /* safeMode */);
displayManager.windowManagerAndInputReady();
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService bs = displayManager.new BinderService();
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final int[] displayIds = bs.getDisplayIds(/* includeDisabled= */ true);
final int size = displayIds.length;
assertTrue(size > 0);
Map<Integer, Integer> expectedDisplayTypeToViewPortTypeMapping = Map.of(
Display.TYPE_INTERNAL, DisplayViewport.VIEWPORT_INTERNAL,
Display.TYPE_EXTERNAL, DisplayViewport.VIEWPORT_EXTERNAL
);
for (int i = 0; i < size; i++) {
DisplayInfo info = bs.getDisplayInfo(displayIds[i]);
assertTrue(expectedDisplayTypeToViewPortTypeMapping.keySet().contains(info.type));
}
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
ArgumentCaptor<List<DisplayViewport>> viewportCaptor = ArgumentCaptor.forClass(List.class);
verify(mMockInputManagerInternal).setDisplayViewports(viewportCaptor.capture());
List<DisplayViewport> viewports = viewportCaptor.getValue();
// Due to the nature of foldables, we may have a different number of viewports than
// displays, just verify there's at least one.
final int viewportSize = viewports.size();
assertTrue(viewportSize > 0);
// Now verify that each viewport's displayId is valid.
Arrays.sort(displayIds);
for (int i = 0; i < viewportSize; i++) {
DisplayViewport viewport = viewports.get(i);
assertNotNull(viewport);
DisplayInfo displayInfo = bs.getDisplayInfo(viewport.displayId);
assertTrue(expectedDisplayTypeToViewPortTypeMapping.get(displayInfo.type)
== viewport.type);
assertTrue(viewport.valid);
assertTrue(Arrays.binarySearch(displayIds, viewport.displayId) >= 0);
}
}
@Test
public void testCreateVirtualDisplayRotatesWithContent() throws Exception {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService bs = displayManager.new BinderService();
String uniqueId = "uniqueId --- Rotates With Content Test";
int width = 600;
int height = 800;
int dpi = 320;
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setFlags(flags);
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
assertNotNull(ddi);
assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0);
}
@Test
public void testCreateVirtualRotatesWithContent() throws RemoteException {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService bs = displayManager.new BinderService();
String uniqueId = "uniqueId --- Rotates with Content Test";
int width = 600;
int height = 800;
int dpi = 320;
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setFlags(flags);
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
/* projection= */ null, PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
assertNotNull(ddi);
assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0);
}
@Test
public void testCreateVirtualDisplayOwnFocus() throws RemoteException {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService bs = displayManager.new BinderService();
String uniqueId = "uniqueId --- Own Focus Test";
int width = 600;
int height = 800;
int dpi = 320;
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS
| DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
PackageManager.PERMISSION_GRANTED);
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setFlags(flags);
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
/* projection= */ null, PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
assertNotNull(ddi);
assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) != 0);
}
@Test
public void testCreateVirtualDisplayOwnFocus_nonTrustedDisplay() throws RemoteException {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService bs = displayManager.new BinderService();
String uniqueId = "uniqueId --- Own Focus Test -- nonTrustedDisplay";
int width = 600;
int height = 800;
int dpi = 320;
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setFlags(flags);
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
/* projection= */ null, PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
assertNotNull(ddi);
assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) == 0);
}
/**
* Tests that the virtual display is created along-side the default display.
*/
@Test
public void testStartVirtualDisplayWithDefaultDisplay_Succeeds() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
}
/**
* Tests that we send the device state to window manager
*/
@Test
public void testOnStateChanged_sendsStateChangedEventToWm() throws Exception {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
registerDefaultDisplays(displayManager);
displayManager.windowManagerAndInputReady();
displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
DeviceStateListener listener = displayManager.new DeviceStateListener();
Handler handler = displayManager.getDisplayHandler();
IDisplayManagerCallback displayChangesCallback = registerDisplayChangeCallback(
displayManager);
listener.onStateChanged(123);
waitForIdleHandler(handler);
InOrder inOrder = inOrder(mMockWindowManagerInternal, displayChangesCallback);
// Verify there are no display events before WM call
inOrder.verify(displayChangesCallback, never()).onDisplayEvent(anyInt(), anyInt());
inOrder.verify(mMockWindowManagerInternal).onDisplayManagerReceivedDeviceState(123);
}
/**
* Tests that there should be a display change notification to WindowManager to update its own
* internal state for things like display cutout when nonOverrideDisplayInfo is changed.
*/
@Test
public void testShouldNotifyChangeWhenNonOverrideDisplayInfoChanged() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
// Add the FakeDisplayDevice
FakeDisplayDevice displayDevice = new FakeDisplayDevice();
DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
displayDeviceInfo.width = 100;
displayDeviceInfo.height = 200;
displayDeviceInfo.supportedModes = new Display.Mode[1];
displayDeviceInfo.supportedModes[0] = new Display.Mode(1, 100, 200, 60f);
displayDeviceInfo.modeId = 1;
final Rect zeroRect = new Rect();
displayDeviceInfo.displayCutout = new DisplayCutout(
Insets.of(0, 10, 0, 0),
zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect);
displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY;
displayDeviceInfo.address = new TestUtils.TestDisplayAddress();
displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
// Find the display id of the added FakeDisplayDevice
DisplayManagerService.BinderService bs = displayManager.new BinderService();
int displayId = getDisplayIdForDisplayDevice(displayManager, bs, displayDevice);
// Setup override DisplayInfo
DisplayInfo overrideInfo = bs.getDisplayInfo(displayId);
displayManager.setDisplayInfoOverrideFromWindowManagerInternal(displayId, overrideInfo);
FakeDisplayManagerCallback callback = registerDisplayListenerCallback(
displayManager, bs, displayDevice);
// Simulate DisplayDevice change
DisplayDeviceInfo displayDeviceInfo2 = new DisplayDeviceInfo();
displayDeviceInfo2.copyFrom(displayDeviceInfo);
displayDeviceInfo2.displayCutout = null;
displayDevice.setDisplayDeviceInfo(displayDeviceInfo2);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_CHANGED);
}
/**
* Tests that we get a Runtime exception when we cannot initialize the default display.
*/
@Test
public void testStartVirtualDisplayWithDefDisplay_NoDefaultDisplay() throws Exception {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
try {
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
} catch (RuntimeException e) {
return;
}
fail("Expected DisplayManager to throw RuntimeException when it cannot initialize the"
+ " default display");
}
/**
* Tests that we get a Runtime exception when we cannot initialize the virtual display.
*/
@Test
public void testStartVirtualDisplayWithDefDisplay_NoVirtualDisplayAdapter() {
DisplayManagerService displayManager = new DisplayManagerService(mContext,
new DisplayManagerService.Injector() {
@Override
VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot,
Context context, Handler handler, DisplayAdapter.Listener listener) {
return null; // return null for the adapter. This should cause a failure.
}
@Override
long getDefaultDisplayDelayTimeout() {
return SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS;
}
});
try {
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
} catch (RuntimeException e) {
return;
}
fail("Expected DisplayManager to throw RuntimeException when it cannot initialize the"
+ " virtual display adapter");
}
/**
* Tests that an exception is raised for too dark a brightness configuration.
*/
@Test
public void testTooDarkBrightnessConfigurationThrowException() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
Curve minimumBrightnessCurve = displayManager.getMinimumBrightnessCurveInternal();
float[] lux = minimumBrightnessCurve.getX();
float[] minimumNits = minimumBrightnessCurve.getY();
float[] nits = new float[minimumNits.length];
// For every control point, assert that making it slightly lower than the minimum throws an
// exception.
for (int i = 0; i < nits.length; i++) {
for (int j = 0; j < nits.length; j++) {
nits[j] = minimumNits[j];
if (j == i) {
nits[j] -= 0.1f;
}
if (nits[j] < 0) {
nits[j] = 0;
}
}
BrightnessConfiguration config =
new BrightnessConfiguration.Builder(lux, nits).build();
Exception thrown = null;
try {
displayManager.validateBrightnessConfiguration(config);
} catch (IllegalArgumentException e) {
thrown = e;
}
assertNotNull("Building too dark a brightness configuration must throw an exception");
}
}
/**
* Tests that no exception is raised for not too dark a brightness configuration.
*/
@Test
public void testBrightEnoughBrightnessConfigurationDoesNotThrowException() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
Curve minimumBrightnessCurve = displayManager.getMinimumBrightnessCurveInternal();
float[] lux = minimumBrightnessCurve.getX();
float[] nits = minimumBrightnessCurve.getY();
BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits).build();
displayManager.validateBrightnessConfiguration(config);
}
/**
* Tests that null brightness configurations are alright.
*/
@Test
public void testNullBrightnessConfiguration() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
displayManager.validateBrightnessConfiguration(null);
}
/**
* Tests that collection of display color sampling results are sensible.
*/
@Test
public void testDisplayedContentSampling() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
registerDefaultDisplays(displayManager);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(0);
assertNotNull(ddi);
DisplayedContentSamplingAttributes attr =
displayManager.getDisplayedContentSamplingAttributesInternal(0);
if (attr == null) return; //sampling not supported on device, skip remainder of test.
boolean enabled = displayManager.setDisplayedContentSamplingEnabledInternal(0, true, 0, 0);
assertTrue(enabled);
displayManager.setDisplayedContentSamplingEnabledInternal(0, false, 0, 0);
DisplayedContentSample sample = displayManager.getDisplayedContentSampleInternal(0, 0, 0);
assertNotNull(sample);
long numPixels = ddi.width * ddi.height * sample.getNumFrames();
long[] samples = sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL0);
assertTrue(samples.length == 0 || LongStream.of(samples).sum() == numPixels);
samples = sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL1);
assertTrue(samples.length == 0 || LongStream.of(samples).sum() == numPixels);
samples = sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL2);
assertTrue(samples.length == 0 || LongStream.of(samples).sum() == numPixels);
samples = sample.getSampleComponent(DisplayedContentSample.ColorComponent.CHANNEL3);
assertTrue(samples.length == 0 || LongStream.of(samples).sum() == numPixels);
}
/**
* Tests that the virtual display is created with
* {@link VirtualDisplayConfig.Builder#setDisplayIdToMirror(int)}
*/
@Test
@FlakyTest(bugId = 127687569)
public void testCreateVirtualDisplay_displayIdToMirror() throws Exception {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
DisplayManagerService.LocalService localDisplayManager = displayManager.new LocalService();
final String uniqueId = "uniqueId --- displayIdToMirrorTest";
final int width = 600;
final int height = 800;
final int dpi = 320;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setUniqueId(uniqueId);
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
// The second virtual display requests to mirror the first virtual display.
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
final VirtualDisplayConfig.Builder builder2 = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi).setUniqueId(uniqueId2);
builder2.setUniqueId(uniqueId2);
builder2.setDisplayIdToMirror(firstDisplayId);
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
mMockAppToken2 /* callback */, null /* projection */,
PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
// The displayId to mirror should be a default display if there is none initially.
assertEquals(localDisplayManager.getDisplayIdToMirror(firstDisplayId),
Display.DEFAULT_DISPLAY);
assertEquals(localDisplayManager.getDisplayIdToMirror(secondDisplayId),
firstDisplayId);
}
/** Tests that the virtual device is created in a device display group. */
@Test
public void createVirtualDisplay_addsDisplaysToDeviceDisplayGroups() throws Exception {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
registerDefaultDisplays(displayManager);
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Create a first virtual display. A display group should be created for this display on the
// virtual device.
final VirtualDisplayConfig.Builder builder1 =
new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
.setUniqueId("uniqueId --- device display group 1");
int displayId1 =
localService.createVirtualDisplay(
builder1.build(),
mMockAppToken2 /* callback */,
virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
// Create a second virtual display. This should be added to the previously created display
// group.
final VirtualDisplayConfig.Builder builder2 =
new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
.setUniqueId("uniqueId --- device display group 1");
int displayId2 =
localService.createVirtualDisplay(
builder2.build(),
mMockAppToken /* callback */,
virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
assertEquals(
"Both displays should be added to the same displayGroup.",
displayGroupId1,
displayGroupId2);
}
/**
* Tests that the virtual display is not added to the device display group when
* VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is set.
*/
@Test
public void createVirtualDisplay_addsDisplaysToOwnDisplayGroups() throws Exception {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
registerDefaultDisplays(displayManager);
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Create a first virtual display. A display group should be created for this display on the
// virtual device.
final VirtualDisplayConfig.Builder builder1 =
new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
.setUniqueId("uniqueId --- device display group");
int displayId1 =
localService.createVirtualDisplay(
builder1.build(),
mMockAppToken /* callback */,
virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
// Create a second virtual display. With the flag VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP,
// the display should not be added to the previously created display group.
final VirtualDisplayConfig.Builder builder2 =
new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
.setFlags(VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP)
.setUniqueId("uniqueId --- own display group");
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
int displayId2 =
localService.createVirtualDisplay(
builder2.build(),
mMockAppToken2 /* callback */,
virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
assertNotEquals(
"Display 1 should be in the device display group and display 2 in its own display"
+ " group.",
displayGroupId1,
displayGroupId2);
}
@Test
public void displaysInDeviceOrOwnDisplayGroupShouldPreserveAlwaysUnlockedFlag()
throws Exception {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
registerDefaultDisplays(displayManager);
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
when(mMockAppToken3.asBinder()).thenReturn(mMockAppToken3);
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
// Allow an ALWAYS_UNLOCKED display to be created.
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY))
.thenReturn(PackageManager.PERMISSION_GRANTED);
when(mContext.checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY))
.thenReturn(PackageManager.PERMISSION_GRANTED);
// Create a virtual display in a device display group.
final VirtualDisplayConfig deviceDisplayGroupDisplayConfig =
new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
.setUniqueId("uniqueId --- device display group 1")
.setFlags(VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED)
.build();
int deviceDisplayGroupDisplayId =
localService.createVirtualDisplay(
deviceDisplayGroupDisplayConfig,
mMockAppToken /* callback */,
virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
// Check that FLAG_ALWAYS_UNLOCKED is set.
assertNotEquals(
"FLAG_ALWAYS_UNLOCKED should be set for displays created in a device display"
+ " group.",
(displayManager.getDisplayDeviceInfoInternal(deviceDisplayGroupDisplayId).flags
& DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED),
0);
// Create a virtual display in its own display group.
final VirtualDisplayConfig ownDisplayGroupConfig =
new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
.setUniqueId("uniqueId --- own display group 1")
.setFlags(
VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED
| VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP)
.build();
int ownDisplayGroupDisplayId =
localService.createVirtualDisplay(
ownDisplayGroupConfig,
mMockAppToken2 /* callback */,
virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
// Check that FLAG_ALWAYS_UNLOCKED is set.
assertNotEquals(
"FLAG_ALWAYS_UNLOCKED should be set for displays created in their own display"
+ " group.",
(displayManager.getDisplayDeviceInfoInternal(ownDisplayGroupDisplayId).flags
& DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED),
0);
// Create a virtual display in a device display group.
final VirtualDisplayConfig defaultDisplayGroupConfig =
new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
.setUniqueId("uniqueId --- default display group 1")
.setFlags(VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED)
.build();
int defaultDisplayGroupDisplayId =
localService.createVirtualDisplay(
defaultDisplayGroupConfig,
mMockAppToken3 /* callback */,
null /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class),
PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
// Check that FLAG_ALWAYS_UNLOCKED is not set.
assertEquals(
"FLAG_ALWAYS_UNLOCKED should not be set for displays created in the default"
+ " display group.",
(displayManager.getDisplayDeviceInfoInternal(defaultDisplayGroupDisplayId).flags
& DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED),
0);
}
@Test
public void testGetDisplayIdToMirror() throws Exception {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
DisplayManagerService.LocalService localDisplayManager = displayManager.new LocalService();
final String uniqueId = "uniqueId --- displayIdToMirrorTest";
final int width = 600;
final int height = 800;
final int dpi = 320;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi)
.setUniqueId(uniqueId)
.setFlags(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
// The second virtual display requests to mirror the first virtual display.
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
final VirtualDisplayConfig.Builder builder2 = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi)
.setUniqueId(uniqueId2)
.setWindowManagerMirroringEnabled(true);
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
mMockAppToken2 /* callback */, null /* projection */,
PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
// The displayId to mirror should be a invalid since the display had flag OWN_CONTENT_ONLY
assertEquals(localDisplayManager.getDisplayIdToMirror(firstDisplayId),
Display.INVALID_DISPLAY);
// The second display has mirroring managed by WindowManager so the mirror displayId should
// be invalid.
assertEquals(localDisplayManager.getDisplayIdToMirror(secondDisplayId),
Display.INVALID_DISPLAY);
}
@Test
public void testCreateVirtualDisplay_isValidProjection_notValid()
throws RemoteException {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IMediaProjection projection = mock(IMediaProjection.class);
doReturn(false).when(projection).isValid();
when(mMockProjectionService
.setContentRecordingSession(any(ContentRecordingSession.class), eq(projection)))
.thenReturn(true);
doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection));
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setUniqueId("uniqueId --- isValid false");
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
displayManager.windowManagerAndInputReady();
// Pass in a non-null projection.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, projection, PACKAGE_NAME);
// VirtualDisplay is created for mirroring.
assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY);
verify(mMockProjectionService, atLeastOnce()).setContentRecordingSession(
any(ContentRecordingSession.class), nullable(IMediaProjection.class));
// But mirroring doesn't begin.
verify(mMockProjectionService, atLeastOnce()).setContentRecordingSession(
mContentRecordingSessionCaptor.capture(), nullable(IMediaProjection.class));
ContentRecordingSession session = mContentRecordingSessionCaptor.getValue();
assertThat(session.isWaitingForConsent()).isTrue();
}
@Test
public void testCreateVirtualDisplay_setContentRecordingSessionSuccess()
throws RemoteException {
final int displayToRecord = 50;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IMediaProjection projection = mock(IMediaProjection.class);
doReturn(true).when(projection).isValid();
when(mMockProjectionService
.setContentRecordingSession(any(ContentRecordingSession.class), eq(projection)))
.thenReturn(true);
doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection));
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setUniqueId("uniqueId --- setContentRecordingSession true");
builder.setDisplayIdToMirror(displayToRecord);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
displayManager.windowManagerAndInputReady();
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, projection, PACKAGE_NAME);
assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY);
verify(mMockProjectionService, atLeastOnce()).setContentRecordingSession(
mContentRecordingSessionCaptor.capture(), nullable(IMediaProjection.class));
ContentRecordingSession session = mContentRecordingSessionCaptor.getValue();
assertThat(session.getContentToRecord()).isEqualTo(RECORD_CONTENT_DISPLAY);
assertThat(session.getVirtualDisplayId()).isEqualTo(displayId);
assertThat(session.getDisplayToRecord()).isEqualTo(displayToRecord);
assertThat(session.isWaitingForConsent()).isFalse();
}
@Test
public void testCreateVirtualDisplay_setContentRecordingSessionFail() throws RemoteException {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IMediaProjection projection = mock(IMediaProjection.class);
doReturn(true).when(projection).isValid();
when(mMockProjectionService
.setContentRecordingSession(any(ContentRecordingSession.class), eq(projection)))
.thenReturn(false);
doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection));
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setUniqueId("uniqueId --- setContentRecordingSession false");
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
displayManager.windowManagerAndInputReady();
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, projection, PACKAGE_NAME);
assertThat(displayId).isEqualTo(Display.INVALID_DISPLAY);
}
@Test
public void testCreateVirtualDisplay_setContentRecordingSession_taskSession()
throws RemoteException {
final int displayToRecord = 50;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IMediaProjection projection = mock(IMediaProjection.class);
doReturn(true).when(projection).isValid();
when(mMockProjectionService
.setContentRecordingSession(any(ContentRecordingSession.class), eq(projection)))
.thenReturn(true);
doReturn(mock(IBinder.class)).when(projection).getLaunchCookie();
doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection));
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setUniqueId("uniqueId --- setContentRecordingSession false");
builder.setDisplayIdToMirror(displayToRecord);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
displayManager.windowManagerAndInputReady();
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, projection, PACKAGE_NAME);
assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY);
verify(mMockProjectionService, atLeastOnce()).setContentRecordingSession(
mContentRecordingSessionCaptor.capture(), nullable(IMediaProjection.class));
ContentRecordingSession session = mContentRecordingSessionCaptor.getValue();
assertThat(session.getContentToRecord()).isEqualTo(RECORD_CONTENT_TASK);
assertThat(session.getVirtualDisplayId()).isEqualTo(displayId);
assertThat(session.getTokenToRecord()).isNotNull();
}
@Test
public void testCreateVirtualDisplay_setContentRecordingSession_noProjection_noFlags()
throws RemoteException {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
// Set no flags for the VirtualDisplay.
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setUniqueId("uniqueId --- setContentRecordingSession false");
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
displayManager.windowManagerAndInputReady();
// Pass in a null projection.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
// VirtualDisplay is created but not for mirroring.
assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY);
verify(mMockProjectionService, never()).setContentRecordingSession(
any(ContentRecordingSession.class), nullable(IMediaProjection.class));
}
@Test
public void testCreateVirtualDisplay_setContentRecordingSession_noProjection_noMirroringFlag()
throws RemoteException {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
// Set a non-mirroring flag for the VirtualDisplay.
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setUniqueId("uniqueId --- setContentRecordingSession false");
builder.setFlags(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
displayManager.windowManagerAndInputReady();
// Pass in a null projection.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
// VirtualDisplay is created but not for mirroring.
assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY);
verify(mMockProjectionService, never()).setContentRecordingSession(
any(ContentRecordingSession.class), nullable(IMediaProjection.class));
}
@Test
public void testCreateVirtualDisplay_setContentRecordingSession_projection_noMirroringFlag()
throws RemoteException {
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
IMediaProjection projection = mock(IMediaProjection.class);
doReturn(true).when(projection).isValid();
when(mMockProjectionService
.setContentRecordingSession(any(ContentRecordingSession.class), eq(projection)))
.thenReturn(true);
doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection));
// Set no flags for the VirtualDisplay.
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setUniqueId("uniqueId --- setContentRecordingSession false");
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
displayManager.windowManagerAndInputReady();
// Pass in a non-null projection.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, projection, PACKAGE_NAME);
// VirtualDisplay is created for mirroring.
assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY);
verify(mMockProjectionService, atLeastOnce()).setContentRecordingSession(
any(ContentRecordingSession.class), nullable(IMediaProjection.class));
}
/**
* Tests that the virtual display is created with
* {@link VirtualDisplayConfig.Builder#setSurface(Surface)}
*/
@Test
@FlakyTest(bugId = 127687569)
public void testCreateVirtualDisplay_setSurface() throws Exception {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final String uniqueId = "uniqueId --- setSurface";
final int width = 600;
final int height = 800;
final int dpi = 320;
final Surface surface = new Surface();
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setSurface(surface);
builder.setUniqueId(uniqueId);
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
assertEquals(displayManager.getVirtualDisplaySurfaceInternal(mMockAppToken), surface);
}
/**
* Tests that specifying VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is allowed when the permission
* ADD_TRUSTED_DISPLAY is granted.
*/
@Test
public void testOwnDisplayGroup_allowCreationWithAddTrustedDisplayPermission()
throws RemoteException {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
PackageManager.PERMISSION_GRANTED);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setFlags(DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP);
builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
assertNotNull(ddi);
assertNotEquals(0, ddi.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
}
/**
* Tests that specifying VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is blocked when the permission
* ADD_TRUSTED_DISPLAY is denied.
*/
@Test
public void testOwnDisplayGroup_withoutAddTrustedDisplayPermission_throwsSecurityException() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
PackageManager.PERMISSION_DENIED);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setFlags(DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP);
builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
try {
bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME);
fail("Creating virtual display with VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP without "
+ "ADD_TRUSTED_DISPLAY permission should throw SecurityException.");
} catch (SecurityException e) {
// SecurityException is expected
}
}
/**
* Tests that specifying VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP is allowed when called with
* a virtual device, even if ADD_TRUSTED_DISPLAY is not granted.
*/
@Test
public void testOwnDisplayGroup_allowCreationWithVirtualDevice() throws Exception {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
registerDefaultDisplays(displayManager);
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
PackageManager.PERMISSION_DENIED);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
builder.setFlags(DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP);
builder.setUniqueId("uniqueId --- OWN_DISPLAY_GROUP");
IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
when(virtualDevice.getDeviceId()).thenReturn(1);
when(mIVirtualDeviceManager.isValidVirtualDeviceId(1)).thenReturn(true);
int displayId = localService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
mock(DisplayWindowPolicyController.class), PACKAGE_NAME);
verify(mMockProjectionService, never()).setContentRecordingSession(any(),
nullable(IMediaProjection.class));
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
assertNotNull(ddi);
assertNotEquals(0, ddi.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
}
/**
* Tests that there is a display change notification if the frame rate override
* list is updated.
*/
@Test
public void testShouldNotifyChangeWhenDisplayInfoFrameRateOverrideChanged() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
FakeDisplayManagerCallback callback = registerDisplayListenerCallback(displayManager,
displayManagerBinderService, displayDevice);
int myUid = Process.myUid();
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
});
waitForIdleHandler(displayManager.getDisplayHandler());
assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED);
callback.clear();
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
new DisplayEventReceiver.FrameRateOverride(1234, 30f),
});
waitForIdleHandler(displayManager.getDisplayHandler());
assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_CHANGED);
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(myUid, 20f),
new DisplayEventReceiver.FrameRateOverride(1234, 30f),
new DisplayEventReceiver.FrameRateOverride(5678, 30f),
});
waitForIdleHandler(displayManager.getDisplayHandler());
assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED);
callback.clear();
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(1234, 30f),
new DisplayEventReceiver.FrameRateOverride(5678, 30f),
});
waitForIdleHandler(displayManager.getDisplayHandler());
assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED);
callback.clear();
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(5678, 30f),
});
waitForIdleHandler(displayManager.getDisplayHandler());
assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_CHANGED);
}
/**
* Tests that the DisplayInfo is updated correctly with a frame rate override
*/
@Test
public void testDisplayInfoFrameRateOverride() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f, 30f, 20f});
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(
Process.myUid(), 20f),
new DisplayEventReceiver.FrameRateOverride(
Process.myUid() + 1, 30f)
});
displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
// Changing the mode to 30Hz should not override the refresh rate to 20Hz anymore
// as 20 is not a divider of 30.
updateModeId(displayManager, displayDevice, 2);
displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(30f, displayInfo.getRefreshRate(), 0.01f);
}
/**
* Tests that the frame rate override is returning the correct value from
* DisplayInfo#getRefreshRate
*/
@Test
public void testDisplayInfoNonNativeFrameRateOverride() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f});
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(
Process.myUid(), 20f)
});
displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
}
/**
* Tests that the mode reflects the frame rate override is in compat mode
*/
@Test
@DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
public void testDisplayInfoFrameRateOverrideModeCompat() {
testDisplayInfoFrameRateOverrideModeCompat(/*compatChangeEnabled*/ false);
}
/**
* Tests that the mode reflects the physical display refresh rate when not in compat mode.
*/
@Test
@EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
public void testDisplayInfoFrameRateOverrideMode() {
testDisplayInfoFrameRateOverrideModeCompat(/*compatChangeEnabled*/ true);
}
/**
* Tests that the mode reflects the frame rate override is in compat mode and accordingly to the
* allowNonNativeRefreshRateOverride policy.
*/
@Test
@DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
public void testDisplayInfoNonNativeFrameRateOverrideModeCompat() {
testDisplayInfoNonNativeFrameRateOverrideMode(/*compatChangeEnabled*/ false);
}
/**
* Tests that the mode reflects the physical display refresh rate when not in compat mode.
*/
@Test
@EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
public void testDisplayInfoNonNativeFrameRateOverrideMode() {
testDisplayInfoNonNativeFrameRateOverrideMode(/*compatChangeEnabled*/ true);
}
/**
* Tests that there is a display change notification if the render frame rate is updated
*/
@Test
public void testShouldNotifyChangeWhenDisplayInfoRenderFrameRateChanged() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
FakeDisplayManagerCallback callback = registerDisplayListenerCallback(displayManager,
displayManagerBinderService, displayDevice);
updateRenderFrameRate(displayManager, displayDevice, 30f);
waitForIdleHandler(displayManager.getDisplayHandler());
assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED);
callback.clear();
updateRenderFrameRate(displayManager, displayDevice, 30f);
waitForIdleHandler(displayManager.getDisplayHandler());
assertThat(callback.receivedEvents()).doesNotContain(EVENT_DISPLAY_CHANGED);
updateRenderFrameRate(displayManager, displayDevice, 20f);
waitForIdleHandler(displayManager.getDisplayHandler());
assertThat(callback.receivedEvents()).contains(EVENT_DISPLAY_CHANGED);
callback.clear();
}
/**
* Tests that the DisplayInfo is updated correctly with a render frame rate
*/
@Test
public void testDisplayInfoRenderFrameRate() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f, 30f, 20f});
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
updateRenderFrameRate(displayManager, displayDevice, 20f);
displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
}
/**
* Tests that the mode reflects the render frame rate is in compat mode
*/
@Test
@DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
public void testDisplayInfoRenderFrameRateModeCompat() {
testDisplayInfoRenderFrameRateModeCompat(/*compatChangeEnabled*/ false);
}
/**
* Tests that the mode reflects the physical display refresh rate when not in compat mode.
*/
@Test
@EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
public void testDisplayInfoRenderFrameRateMode() {
testDisplayInfoRenderFrameRateModeCompat(/*compatChangeEnabled*/ true);
}
/**
* Tests that EVENT_DISPLAY_ADDED is sent when a display is added.
*/
@Test
public void testShouldNotifyDisplayAdded_WhenNewDisplayDeviceIsAdded() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
// register display listener callback
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
displayManagerBinderService.registerCallbackWithEventMask(
callback, STANDARD_DISPLAY_EVENTS);
waitForIdleHandler(handler);
createFakeDisplayDevice(displayManager, new float[]{60f});
waitForIdleHandler(handler);
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_ADDED);
}
/**
* Tests that EVENT_DISPLAY_ADDED is not sent when a display is added and the
* client has a callback which is not subscribed to this event type.
*/
@Test
public void testShouldNotNotifyDisplayAdded_WhenClientIsNotSubscribed() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
// register display listener callback
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
long allEventsExceptDisplayAdded = STANDARD_DISPLAY_EVENTS
& ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED;
displayManagerBinderService.registerCallbackWithEventMask(callback,
allEventsExceptDisplayAdded);
waitForIdleHandler(handler);
createFakeDisplayDevice(displayManager, new float[]{60f});
waitForIdleHandler(handler);
assertThat(callback.receivedEvents()).isEmpty();
}
/**
* Tests that EVENT_DISPLAY_REMOVED is sent when a display is removed.
*/
@Test
public void testShouldNotifyDisplayRemoved_WhenDisplayDeviceIsRemoved() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f});
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
waitForIdleHandler(handler);
FakeDisplayManagerCallback callback = registerDisplayListenerCallback(
displayManager, displayManagerBinderService, displayDevice);
waitForIdleHandler(handler);
display.setPrimaryDisplayDeviceLocked(null);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
waitForIdleHandler(handler);
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_REMOVED);
}
/**
* Tests that EVENT_DISPLAY_REMOVED is not sent when a display is added and the
* client has a callback which is not subscribed to this event type.
*/
@Test
public void testShouldNotNotifyDisplayRemoved_WhenClientIsNotSubscribed() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f});
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
waitForIdleHandler(handler);
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
long allEventsExceptDisplayRemoved = STANDARD_DISPLAY_EVENTS
& ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
displayManagerBinderService.registerCallbackWithEventMask(callback,
allEventsExceptDisplayRemoved);
waitForIdleHandler(handler);
display.setPrimaryDisplayDeviceLocked(null);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
waitForIdleHandler(handler);
assertThat(callback.receivedEvents()).isEmpty();
}
@Test
public void testSettingTwoBrightnessConfigurationsOnMultiDisplay() {
DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
// get the first two internal displays
Display[] displays = displayManager.getDisplays();
Display internalDisplayOne = null;
Display internalDisplayTwo = null;
for (Display display : displays) {
if (display.getType() == Display.TYPE_INTERNAL) {
if (internalDisplayOne == null) {
internalDisplayOne = display;
} else {
internalDisplayTwo = display;
break;
}
}
}
// return if there are fewer than 2 displays on this device
if (internalDisplayOne == null || internalDisplayTwo == null) {
return;
}
final String uniqueDisplayIdOne = internalDisplayOne.getUniqueId();
final String uniqueDisplayIdTwo = internalDisplayTwo.getUniqueId();
BrightnessConfiguration configOne =
new BrightnessConfiguration.Builder(
new float[]{0.0f, 12345.0f}, new float[]{15.0f, 400.0f})
.setDescription("model:1").build();
BrightnessConfiguration configTwo =
new BrightnessConfiguration.Builder(
new float[]{0.0f, 6789.0f}, new float[]{12.0f, 300.0f})
.setDescription("model:2").build();
displayManager.setBrightnessConfigurationForDisplay(configOne,
uniqueDisplayIdOne);
displayManager.setBrightnessConfigurationForDisplay(configTwo,
uniqueDisplayIdTwo);
BrightnessConfiguration configFromOne =
displayManager.getBrightnessConfigurationForDisplay(uniqueDisplayIdOne);
BrightnessConfiguration configFromTwo =
displayManager.getBrightnessConfigurationForDisplay(uniqueDisplayIdTwo);
assertNotNull(configFromOne);
assertEquals(configOne, configFromOne);
assertEquals(configTwo, configFromTwo);
}
@Test
public void testHdrConversionModeEquals() {
assertEquals(
new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_FORCE, 2),
new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_FORCE, 2));
assertNotEquals(
new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_FORCE, 2),
new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_FORCE, 3));
assertEquals(
new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM),
new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM));
assertNotEquals(
new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_FORCE, 2),
new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM));
}
@Test
public void testCreateHdrConversionMode_withInvalidArguments_throwsException() {
assertThrows(
"preferredHdrOutputType must not be set if the conversion mode is "
+ "HDR_CONVERSION_PASSTHROUGH",
IllegalArgumentException.class,
() -> new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_PASSTHROUGH,
Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION));
}
@Test
public void testSetHdrConversionModeInternal_withInvalidArguments_throwsException() {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
assertThrows("Expected DisplayManager to throw IllegalArgumentException when "
+ "preferredHdrOutputType is set and the conversion mode is "
+ "HDR_CONVERSION_SYSTEM",
IllegalArgumentException.class,
() -> displayManager.setHdrConversionModeInternal(new HdrConversionMode(
HdrConversionMode.HDR_CONVERSION_SYSTEM,
Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION)));
}
@Test
public void testSetAndGetHdrConversionModeInternal() {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
final HdrConversionMode mode = new HdrConversionMode(
HdrConversionMode.HDR_CONVERSION_FORCE,
Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION);
displayManager.setHdrConversionModeInternal(mode);
assertEquals(mode, displayManager.getHdrConversionModeSettingInternal());
assertEquals(mode.getConversionMode(), mHdrConversionMode);
assertEquals(mode.getPreferredHdrOutputType(), mPreferredHdrOutputType);
}
@Test
public void testHdrConversionMode_withMinimalPostProcessing() {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f, 30f, 20f});
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
final HdrConversionMode mode = new HdrConversionMode(
HdrConversionMode.HDR_CONVERSION_FORCE,
Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION);
displayManager.setHdrConversionModeInternal(mode);
assertEquals(mode, displayManager.getHdrConversionModeSettingInternal());
displayManager.setMinimalPostProcessingAllowed(true);
displayManager.setDisplayPropertiesInternal(displayId, false /* hasContent */,
30.0f /* requestedRefreshRate */,
displayDevice.getDisplayDeviceInfoLocked().modeId /* requestedModeId */,
30.0f /* requestedMinRefreshRate */, 120.0f /* requestedMaxRefreshRate */,
true /* preferMinimalPostProcessing */, false /* disableHdrConversion */,
true /* inTraversal */);
assertEquals(new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_PASSTHROUGH),
displayManager.getHdrConversionModeInternal());
displayManager.setDisplayPropertiesInternal(displayId, false /* hasContent */,
30.0f /* requestedRefreshRate */,
displayDevice.getDisplayDeviceInfoLocked().modeId /* requestedModeId */,
30.0f /* requestedMinRefreshRate */, 120.0f /* requestedMaxRefreshRate */,
false /* preferMinimalPostProcessing */, false /* disableHdrConversion */,
true /* inTraversal */);
assertEquals(mode, displayManager.getHdrConversionModeInternal());
}
@Test
public void testReturnsRefreshRateForDisplayAndSensor_proximitySensorSet() {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
displayManager.overrideSensorManager(mSensorManager);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
displayDevice.mDisplayDeviceConfig = mMockDisplayDeviceConfig;
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
String testSensorName = "testName";
String testSensorType = "testType";
Sensor testSensor = TestUtils.createSensor(testSensorType, testSensorName);
DisplayDeviceConfig.SensorData sensorData = new DisplayDeviceConfig.SensorData();
sensorData.type = testSensorType;
sensorData.name = testSensorName;
sensorData.minRefreshRate = 10f;
sensorData.maxRefreshRate = 100f;
when(mMockDisplayDeviceConfig.getProximitySensor()).thenReturn(sensorData);
when(mSensorManager.getSensorList(Sensor.TYPE_ALL)).thenReturn(Collections.singletonList(
testSensor));
SurfaceControl.RefreshRateRange result = localService.getRefreshRateForDisplayAndSensor(
displayId, testSensorName, testSensorType);
assertNotNull(result);
assertEquals(result.min, sensorData.minRefreshRate, FLOAT_TOLERANCE);
assertEquals(result.max, sensorData.maxRefreshRate, FLOAT_TOLERANCE);
}
@Test
public void testReturnsRefreshRateForDisplayAndSensor_proximitySensorNotSet() {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
displayManager.overrideSensorManager(mSensorManager);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
displayDevice.mDisplayDeviceConfig = mMockDisplayDeviceConfig;
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
String testSensorName = "testName";
String testSensorType = "testType";
Sensor testSensor = TestUtils.createSensor(testSensorType, testSensorName);
DisplayDeviceConfig.SensorData sensorData = new DisplayDeviceConfig.SensorData();
sensorData.type = testSensorType;
sensorData.name = testSensorName;
sensorData.minRefreshRate = 10f;
sensorData.maxRefreshRate = 100f;
when(mMockDisplayDeviceConfig.getProximitySensor()).thenReturn(null);
when(mSensorManager.getSensorList(Sensor.TYPE_ALL)).thenReturn(Collections.singletonList(
testSensor));
SurfaceControl.RefreshRateRange result = localService.getRefreshRateForDisplayAndSensor(
displayId, testSensorName, testSensorType);
assertNull(result);
}
@Test
public void testConnectExternalDisplay_withoutDisplayManagement_shouldAddDisplay() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(false);
manageDisplaysPermission(/* granted= */ true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
callback.waitForExpectedEvent();
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
assertThat(display.isEnabledLocked()).isTrue();
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_ADDED);
}
@Test
public void testConnectExternalDisplay_withDisplayManagement_shouldDisableDisplay() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
manageDisplaysPermission(/* granted= */ true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerInternal localService = displayManager.new LocalService();
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
localService.registerDisplayGroupListener(callback);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
// Create default display device
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
callback.waitForExpectedEvent();
callback.clear();
callback.expectsEvent(EVENT_DISPLAY_CONNECTED);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
callback.waitForExpectedEvent();
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
assertThat(display.isEnabledLocked()).isFalse();
assertThat(callback.receivedEvents()).containsExactly(DISPLAY_GROUP_EVENT_ADDED,
EVENT_DISPLAY_CONNECTED).inOrder();
}
@Test
public void testConnectInternalDisplay_withDisplayManagement_shouldConnectAndAddDisplay() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
manageDisplaysPermission(/* granted= */ true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
callback.waitForExpectedEvent();
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_CONNECTED,
EVENT_DISPLAY_ADDED).inOrder();
}
@Test
public void testEnableExternalDisplay_withDisplayManagement_shouldSignalDisplayAdded() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
manageDisplaysPermission(/* granted= */ true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
// Create default display device
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
callback.waitForExpectedEvent();
callback.expectsEvent(EVENT_DISPLAY_CONNECTED);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
callback.waitForExpectedEvent();
callback.clear();
callback.expectsEvent(EVENT_DISPLAY_ADDED);
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
displayManager.enableConnectedDisplay(display.getDisplayIdLocked(), /* enabled= */ true);
callback.waitForExpectedEvent();
assertThat(display.isEnabledLocked()).isTrue();
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_ADDED).inOrder();
}
@Test
public void testEnableExternalDisplay_withoutPermission_shouldThrowException() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
// Create default display device
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
callback.waitForExpectedEvent();
bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
// Withouts permission, we cannot get the CONNECTED event.
waitForIdleHandler(displayManager.getDisplayHandler());
callback.clear();
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
int displayId = display.getDisplayIdLocked();
assertThrows(SecurityException.class, () -> bs.enableConnectedDisplay(displayId));
}
@Test
public void testEnableInternalDisplay_withManageDisplays_shouldSignalAdded() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
callback.waitForExpectedEvent();
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
callback.expectsEvent(EVENT_DISPLAY_REMOVED);
logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ false);
logicalDisplayMapper.updateLogicalDisplays();
callback.waitForExpectedEvent();
callback.clear();
callback.expectsEvent(EVENT_DISPLAY_ADDED);
logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ true);
logicalDisplayMapper.updateLogicalDisplays();
callback.waitForExpectedEvent();
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_ADDED);
}
@Test
public void testDisableInternalDisplay_withDisplayManagement_shouldSignalRemove() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
callback.waitForExpectedEvent();
callback.clear();
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
callback.expectsEvent(EVENT_DISPLAY_REMOVED);
logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ false);
logicalDisplayMapper.updateLogicalDisplays();
callback.waitForExpectedEvent();
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_REMOVED);
}
@Test
public void testDisableExternalDisplay_shouldSignalDisplayRemoved() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
DisplayManagerInternal localService = displayManager.new LocalService();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
localService.registerDisplayGroupListener(callback);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
// Create default display device
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
callback.waitForExpectedEvent();
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ true);
logicalDisplayMapper.updateLogicalDisplays();
callback.waitForExpectedEvent();
callback.clear();
callback.expectsEvent(EVENT_DISPLAY_REMOVED);
logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ false);
logicalDisplayMapper.updateLogicalDisplays();
callback.waitForExpectedEvent();
assertThat(display.isEnabledLocked()).isFalse();
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_REMOVED);
}
@Test
public void testDisableExternalDisplay_withoutPermission_shouldThrowException() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
// Create default display device
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
callback.waitForExpectedEvent();
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
int displayId = display.getDisplayIdLocked();
logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ true);
logicalDisplayMapper.updateLogicalDisplays();
callback.waitForExpectedEvent();
callback.clear();
assertThrows(SecurityException.class, () -> bs.disableConnectedDisplay(displayId));
}
@Test
public void testRemoveExternalDisplay_whenDisabled_shouldSignalDisconnected() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
manageDisplaysPermission(/* granted= */ true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
DisplayManagerInternal localService = displayManager.new LocalService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
localService.registerDisplayGroupListener(callback);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
// Create default display device'
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
callback.waitForExpectedEvent();
callback.expectsEvent(EVENT_DISPLAY_CONNECTED);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
callback.waitForExpectedEvent();
callback.clear();
LogicalDisplay display = logicalDisplayMapper.getDisplayLocked(displayDevice);
int groupId = display.getDisplayInfoLocked().displayGroupId;
DisplayGroup group = logicalDisplayMapper.getDisplayGroupLocked(groupId);
assertThat(group.getSizeLocked()).isEqualTo(1);
callback.expectsEvent(DISPLAY_GROUP_EVENT_REMOVED);
display.setPrimaryDisplayDeviceLocked(null);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
callback.waitForExpectedEvent();
assertThat(group.getSizeLocked()).isEqualTo(0);
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_DISCONNECTED,
DISPLAY_GROUP_EVENT_REMOVED);
}
@Test
public void testRegisterCallback_withoutPermission_shouldThrow() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
assertThrows(SecurityException.class, () -> bs.registerCallbackWithEventMask(callback,
STANDARD_AND_CONNECTION_DISPLAY_EVENTS));
}
@Test
public void testRemoveExternalDisplay_whenEnabled_shouldSignalRemovedAndDisconnected() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
manageDisplaysPermission(/* granted= */ true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
callback.expectsEvent(EVENT_DISPLAY_CONNECTED);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
callback.waitForExpectedEvent();
callback.expectsEvent(EVENT_DISPLAY_ADDED);
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
int displayId = display.getDisplayIdLocked();
displayManager.enableConnectedDisplay(displayId, /* enabled= */ true);
callback.waitForExpectedEvent();
callback.clear();
callback.expectsEvent(EVENT_DISPLAY_DISCONNECTED);
display.setPrimaryDisplayDeviceLocked(null);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
callback.waitForExpectedEvent();
assertThat(logicalDisplayMapper.getDisplayLocked(displayId, true)).isNull();
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_REMOVED,
EVENT_DISPLAY_DISCONNECTED).inOrder();
}
@Test
public void testRemoveInternalDisplay_whenEnabled_shouldSignalRemovedAndDisconnected() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
manageDisplaysPermission(/* granted= */ true);
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService bs = displayManager.new BinderService();
LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
callback.expectsEvent(EVENT_DISPLAY_ADDED);
FakeDisplayDevice displayDevice =
createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
LogicalDisplay display =
logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
callback.waitForExpectedEvent();
callback.clear();
callback.expectsEvent(EVENT_DISPLAY_DISCONNECTED);
display.setPrimaryDisplayDeviceLocked(null);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
callback.waitForExpectedEvent();
assertThat(logicalDisplayMapper.getDisplayLocked(displayDevice,
/* includeDisabled= */ true)).isNull();
assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_REMOVED,
EVENT_DISPLAY_DISCONNECTED);
}
private void testDisplayInfoFrameRateOverrideModeCompat(boolean compatChangeEnabled) {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f, 30f, 20f});
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(
Process.myUid(), 20f),
new DisplayEventReceiver.FrameRateOverride(
Process.myUid() + 1, 30f)
});
displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
Display.Mode expectedMode;
if (compatChangeEnabled) {
expectedMode = new Display.Mode(1, 100, 200, 60f);
} else {
expectedMode = new Display.Mode(3, 100, 200, 20f);
}
assertEquals(expectedMode, displayInfo.getMode());
}
private void testDisplayInfoRenderFrameRateModeCompat(boolean compatChangeEnabled) {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f, 30f, 20f});
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
updateRenderFrameRate(displayManager, displayDevice, 20f);
displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
Display.Mode expectedMode;
if (compatChangeEnabled) {
expectedMode = new Display.Mode(1, 100, 200, 60f);
} else {
expectedMode = new Display.Mode(3, 100, 200, 20f);
}
assertEquals(expectedMode, displayInfo.getMode());
}
private void testDisplayInfoNonNativeFrameRateOverrideMode(boolean compatChangeEnabled) {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
DisplayManagerService.BinderService displayManagerBinderService =
displayManager.new BinderService();
registerDefaultDisplays(displayManager);
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f});
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(
Process.myUid(), 20f)
});
displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
Display.Mode expectedMode;
if (compatChangeEnabled) {
expectedMode = new Display.Mode(1, 100, 200, 60f);
} else {
expectedMode = new Display.Mode(255, 100, 200, 20f);
}
assertEquals(expectedMode, displayInfo.getMode());
}
private int getDisplayIdForDisplayDevice(
DisplayManagerService displayManager,
DisplayManagerService.BinderService displayManagerBinderService,
FakeDisplayDevice displayDevice) {
final int[] displayIds = displayManagerBinderService.getDisplayIds(
/* includeDisabled= */ true);
assertTrue(displayIds.length > 0);
int displayId = Display.INVALID_DISPLAY;
for (int i = 0; i < displayIds.length; i++) {
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayIds[i]);
if (displayDevice.getDisplayDeviceInfoLocked().equals(ddi)) {
displayId = displayIds[i];
break;
}
}
assertFalse(displayId == Display.INVALID_DISPLAY);
return displayId;
}
private void updateDisplayDeviceInfo(DisplayManagerService displayManager,
FakeDisplayDevice displayDevice,
DisplayDeviceInfo displayDeviceInfo) {
displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
}
private void updateFrameRateOverride(DisplayManagerService displayManager,
FakeDisplayDevice displayDevice,
DisplayEventReceiver.FrameRateOverride[] frameRateOverrides) {
DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
displayDeviceInfo.copyFrom(displayDevice.getDisplayDeviceInfoLocked());
displayDeviceInfo.frameRateOverrides = frameRateOverrides;
updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo);
}
private void updateRenderFrameRate(DisplayManagerService displayManager,
FakeDisplayDevice displayDevice,
float renderFrameRate) {
DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
displayDeviceInfo.copyFrom(displayDevice.getDisplayDeviceInfoLocked());
displayDeviceInfo.renderFrameRate = renderFrameRate;
updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo);
}
private void updateModeId(DisplayManagerService displayManager,
FakeDisplayDevice displayDevice,
int modeId) {
DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
displayDeviceInfo.copyFrom(displayDevice.getDisplayDeviceInfoLocked());
displayDeviceInfo.modeId = modeId;
updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo);
}
private IDisplayManagerCallback registerDisplayChangeCallback(
DisplayManagerService displayManager) {
IDisplayManagerCallback displayChangesCallback = mock(IDisplayManagerCallback.class);
when(displayChangesCallback.asBinder()).thenReturn(new Binder());
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
binderService.registerCallback(displayChangesCallback);
return displayChangesCallback;
}
private FakeDisplayManagerCallback registerDisplayListenerCallback(
DisplayManagerService displayManager,
DisplayManagerService.BinderService displayManagerBinderService,
FakeDisplayDevice displayDevice) {
return registerDisplayListenerCallback(displayManager, displayManagerBinderService,
displayDevice, STANDARD_DISPLAY_EVENTS);
}
private FakeDisplayManagerCallback registerDisplayListenerCallback(
DisplayManagerService displayManager,
DisplayManagerService.BinderService displayManagerBinderService,
FakeDisplayDevice displayDevice,
long displayEventsMask) {
// Find the display id of the added FakeDisplayDevice
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
// register display listener callback
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
displayManagerBinderService.registerCallbackWithEventMask(
callback, displayEventsMask);
return callback;
}
private FakeDisplayDevice createFakeDisplayDevice(DisplayManagerService displayManager,
float[] refreshRates) {
return createFakeDisplayDevice(displayManager, refreshRates, Display.TYPE_UNKNOWN);
}
private FakeDisplayDevice createFakeDisplayDevice(DisplayManagerService displayManager,
float[] refreshRates,
int displayType) {
FakeDisplayDevice displayDevice = new FakeDisplayDevice();
DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
int width = 100;
int height = 200;
displayDeviceInfo.supportedModes = new Display.Mode[refreshRates.length];
for (int i = 0; i < refreshRates.length; i++) {
displayDeviceInfo.supportedModes[i] =
new Display.Mode(i + 1, width, height, refreshRates[i]);
}
displayDeviceInfo.modeId = 1;
displayDeviceInfo.type = displayType;
displayDeviceInfo.renderFrameRate = displayDeviceInfo.supportedModes[0].getRefreshRate();
displayDeviceInfo.width = width;
displayDeviceInfo.height = height;
final Rect zeroRect = new Rect();
displayDeviceInfo.displayCutout = new DisplayCutout(
Insets.of(0, 10, 0, 0),
zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect);
displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY;
if (displayType == Display.TYPE_EXTERNAL) {
displayDeviceInfo.flags |= DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
}
displayDeviceInfo.address = new TestUtils.TestDisplayAddress();
displayDevice.setDisplayDeviceInfo(displayDeviceInfo);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
return displayDevice;
}
private void registerDefaultDisplays(DisplayManagerService displayManager) {
Handler handler = displayManager.getDisplayHandler();
// Would prefer to call displayManager.onStart() directly here but it performs binderService
// registration which triggers security exceptions when running from a test.
handler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);
waitForIdleHandler(handler);
}
private void waitForIdleHandler(Handler handler) {
waitForIdleHandler(handler, Duration.ofSeconds(1));
}
private void waitForIdleHandler(Handler handler, Duration timeout) {
final MessageQueue queue = handler.getLooper().getQueue();
final CountDownLatch latch = new CountDownLatch(1);
queue.addIdleHandler(() -> {
latch.countDown();
// Remove idle handler
return false;
});
try {
latch.await(timeout.toMillis(), TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
fail("Interrupted unexpectedly: " + e);
}
}
private void resetConfigToIgnoreSensorManager() {
doReturn(new int[]{-1}).when(mResources).getIntArray(R.array
.config_ambientThresholdsOfPeakRefreshRate);
doReturn(new int[]{-1}).when(mResources).getIntArray(R.array
.config_brightnessThresholdsOfPeakRefreshRate);
doReturn(new int[]{-1}).when(mResources).getIntArray(R.array
.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
doReturn(new int[]{-1}).when(mResources).getIntArray(R.array
.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
}
private void manageDisplaysPermission(boolean granted) {
if (granted) {
doNothing().when(mContext).enforceCallingOrSelfPermission(eq(MANAGE_DISPLAYS), any());
} else {
doThrow(new SecurityException("MANAGE_DISPLAYS permission denied")).when(mContext)
.enforceCallingOrSelfPermission(eq(MANAGE_DISPLAYS), any());
}
}
private static class FakeDisplayManagerCallback extends IDisplayManagerCallback.Stub
implements DisplayManagerInternal.DisplayGroupListener {
int mDisplayId;
List<String> mReceivedEvents = new ArrayList<>();
@Nullable
private String mExpectedEvent;
@NonNull
private volatile CountDownLatch mLatch = new CountDownLatch(0);
FakeDisplayManagerCallback(int displayId) {
mDisplayId = displayId;
}
FakeDisplayManagerCallback() {
mDisplayId = -1;
}
void expectsEvent(@NonNull String event) {
mExpectedEvent = event;
mLatch = new CountDownLatch(1);
}
void waitForExpectedEvent() {
waitForExpectedEvent(Duration.ofSeconds(1));
}
void waitForExpectedEvent(Duration timeout) {
try {
assertWithMessage("Event '" + mExpectedEvent + "' is received.")
.that(mLatch.await(timeout.toMillis(), TimeUnit.MILLISECONDS)).isTrue();
} catch (InterruptedException ex) {
throw new AssertionError("Waiting for expected event interrupted", ex);
}
}
private void eventSeen(String event) {
if (event.equals(mExpectedEvent)) {
mLatch.countDown();
}
}
@Override
public void onDisplayEvent(int displayId, int event) {
if (mDisplayId != -1 && displayId != mDisplayId) {
return;
}
// We convert the event to a string for two reasons:
// 1 - The error produced is a lot easier to read
// 2 - The values used for display and group events are the same, strings are used to
// differentiate them easily.
String eventName = eventTypeToString(event);
mReceivedEvents.add(eventName);
eventSeen(eventName);
}
@Override
public void onDisplayGroupAdded(int groupId) {
mReceivedEvents.add(DISPLAY_GROUP_EVENT_ADDED);
eventSeen(DISPLAY_GROUP_EVENT_ADDED);
}
@Override
public void onDisplayGroupRemoved(int groupId) {
mReceivedEvents.add(DISPLAY_GROUP_EVENT_REMOVED);
eventSeen(DISPLAY_GROUP_EVENT_REMOVED);
}
@Override
public void onDisplayGroupChanged(int groupId) {
mReceivedEvents.add(DISPLAY_GROUP_EVENT_CHANGED);
eventSeen(DISPLAY_GROUP_EVENT_CHANGED);
}
public void clear() {
mReceivedEvents.clear();
}
private String eventTypeToString(int eventType) {
switch (eventType) {
case DisplayManagerGlobal.EVENT_DISPLAY_ADDED:
return EVENT_DISPLAY_ADDED;
case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED:
return EVENT_DISPLAY_REMOVED;
case DisplayManagerGlobal.EVENT_DISPLAY_CHANGED:
return EVENT_DISPLAY_CHANGED;
case DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED:
return EVENT_DISPLAY_BRIGHTNESS_CHANGED;
case DisplayManagerGlobal.EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED:
return EVENT_DISPLAY_HDR_SDR_RATIO_CHANGED;
case DisplayManagerGlobal.EVENT_DISPLAY_CONNECTED:
return EVENT_DISPLAY_CONNECTED;
case DisplayManagerGlobal.EVENT_DISPLAY_DISCONNECTED:
return EVENT_DISPLAY_DISCONNECTED;
default:
return "UNKNOWN: " + eventType;
}
}
List<String> receivedEvents() {
return mReceivedEvents;
}
}
private class FakeDisplayDevice extends DisplayDevice {
private DisplayDeviceInfo mDisplayDeviceInfo;
FakeDisplayDevice() {
super(null, null, "", mContext);
}
public void setDisplayDeviceInfo(DisplayDeviceInfo displayDeviceInfo) {
mDisplayDeviceInfo = displayDeviceInfo;
}
@Override
public boolean hasStableUniqueId() {
return false;
}
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
return mDisplayDeviceInfo;
}
}
}