Add eventMask to DM.registerDisplayListener

Add a new parameter to DisplayManager.registDisplayListener
which clients can use to specify in which events
they are interested.

Test: atest DisplayManagerServiceTest
      atest DisplayManagerGlobalTest

Bug: 171240622
Change-Id: Icc71bdd9ddb390bc5406b298a557c84194a53c00
This commit is contained in:
Marin Shalamanov
2021-01-19 14:13:30 +01:00
parent d96c8193e2
commit 204eba6cdc
6 changed files with 488 additions and 68 deletions

View File

@@ -20,6 +20,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -376,6 +377,43 @@ public final class DisplayManager {
@TestApi
public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2;
/**
* @hide
*/
@LongDef(flag = true, prefix = {"EVENT_FLAG_"}, value = {
EVENT_FLAG_DISPLAY_ADDED,
EVENT_FLAG_DISPLAY_CHANGED,
EVENT_FLAG_DISPLAY_REMOVED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventsMask {}
/**
* Event type for when a new display is added.
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
* @hide
*/
public static final long EVENT_FLAG_DISPLAY_ADDED = 1L << 0;
/**
* Event type for when a display is removed.
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
* @hide
*/
public static final long EVENT_FLAG_DISPLAY_REMOVED = 1L << 1;
/**
* Event type for when a display is changed.
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
* @hide
*/
public static final long EVENT_FLAG_DISPLAY_CHANGED = 1L << 2;
/** @hide */
public DisplayManager(Context context) {
@@ -486,7 +524,7 @@ public final class DisplayManager {
}
/**
* Registers an display listener to receive notifications about when
* Registers a display listener to receive notifications about when
* displays are added, removed or changed.
*
* @param listener The listener to register.
@@ -496,7 +534,29 @@ public final class DisplayManager {
* @see #unregisterDisplayListener
*/
public void registerDisplayListener(DisplayListener listener, Handler handler) {
mGlobal.registerDisplayListener(listener, handler);
registerDisplayListener(listener, handler, EVENT_FLAG_DISPLAY_ADDED
| EVENT_FLAG_DISPLAY_CHANGED | EVENT_FLAG_DISPLAY_REMOVED);
}
/**
* Registers a display listener to receive notifications about given display event types.
*
* @param listener The listener to register.
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
* @param eventsMask A bitmask of the event types for which this listener is subscribed.
*
* @see #EVENT_FLAG_DISPLAY_ADDED
* @see #EVENT_FLAG_DISPLAY_CHANGED
* @see #EVENT_FLAG_DISPLAY_REMOVED
* @see #registerDisplayListener(DisplayListener, Handler)
* @see #unregisterDisplayListener
*
* @hide
*/
public void registerDisplayListener(@NonNull DisplayListener listener,
@Nullable Handler handler, @EventsMask long eventsMask) {
mGlobal.registerDisplayListener(listener, handler, eventsMask);
}
/**

View File

@@ -16,6 +16,9 @@
package android.hardware.display;
import static android.hardware.display.DisplayManager.EventsMask;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PropertyInvalidatedCache;
@@ -42,6 +45,10 @@ import android.view.DisplayAdjustments;
import android.view.DisplayInfo;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -66,6 +73,14 @@ public final class DisplayManagerGlobal {
// orientation change before the display info cache has actually been invalidated.
private static final boolean USE_CACHE = false;
@IntDef(prefix = {"SWITCHING_TYPE_"}, value = {
EVENT_DISPLAY_ADDED,
EVENT_DISPLAY_CHANGED,
EVENT_DISPLAY_REMOVED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DisplayEvent {}
public static final int EVENT_DISPLAY_ADDED = 1;
public static final int EVENT_DISPLAY_CHANGED = 2;
public static final int EVENT_DISPLAY_REMOVED = 3;
@@ -81,16 +96,17 @@ public final class DisplayManagerGlobal {
private final IDisplayManager mDm;
private DisplayManagerCallback mCallback;
private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
new ArrayList<DisplayListenerDelegate>();
private @EventsMask long mRegisteredEventsMask = 0;
private final ArrayList<DisplayListenerDelegate> mDisplayListeners = new ArrayList<>();
private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<>();
private final ColorSpace mWideColorSpace;
private int[] mDisplayIdCache;
private int mWifiDisplayScanNestCount;
private DisplayManagerGlobal(IDisplayManager dm) {
@VisibleForTesting
public DisplayManagerGlobal(IDisplayManager dm) {
mDm = dm;
try {
mWideColorSpace =
@@ -274,18 +290,25 @@ public final class DisplayManagerGlobal {
* If that is still null, a runtime exception will be thrown.
*/
public void registerDisplayListener(@NonNull DisplayListener listener,
@Nullable Handler handler) {
@Nullable Handler handler, @EventsMask long eventsMask) {
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
if (eventsMask == 0) {
throw new IllegalArgumentException("The set of events to listen to must not be empty.");
}
synchronized (mLock) {
int index = findDisplayListenerLocked(listener);
if (index < 0) {
Looper looper = getLooperForHandler(handler);
mDisplayListeners.add(new DisplayListenerDelegate(listener, looper));
mDisplayListeners.add(new DisplayListenerDelegate(listener, looper, eventsMask));
registerCallbackIfNeededLocked();
} else {
mDisplayListeners.get(index).setEventsMask(eventsMask);
}
updateCallbackIfNeededLocked();
}
}
@@ -300,6 +323,7 @@ public final class DisplayManagerGlobal {
DisplayListenerDelegate d = mDisplayListeners.get(index);
d.clearEvents();
mDisplayListeners.remove(index);
updateCallbackIfNeededLocked();
}
}
}
@@ -325,18 +349,36 @@ public final class DisplayManagerGlobal {
return -1;
}
@EventsMask
private int calculateEventsMaskLocked() {
int mask = 0;
final int numListeners = mDisplayListeners.size();
for (int i = 0; i < numListeners; i++) {
mask |= mDisplayListeners.get(i).mEventsMask;
}
return mask;
}
private void registerCallbackIfNeededLocked() {
if (mCallback == null) {
mCallback = new DisplayManagerCallback();
updateCallbackIfNeededLocked();
}
}
private void updateCallbackIfNeededLocked() {
int mask = calculateEventsMaskLocked();
if (mask != mRegisteredEventsMask) {
try {
mDm.registerCallback(mCallback);
mDm.registerCallbackWithEventMask(mCallback, mask);
mRegisteredEventsMask = mask;
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
private void handleDisplayEvent(int displayId, int event) {
private void handleDisplayEvent(int displayId, @DisplayEvent int event) {
synchronized (mLock) {
if (USE_CACHE) {
mDisplayInfoCache.remove(displayId);
@@ -754,7 +796,7 @@ public final class DisplayManagerGlobal {
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
@Override
public void onDisplayEvent(int displayId, int event) {
public void onDisplayEvent(int displayId, @DisplayEvent int event) {
if (DEBUG) {
Log.d(TAG, "onDisplayEvent: displayId=" + displayId + ", event=" + event);
}
@@ -764,13 +806,16 @@ public final class DisplayManagerGlobal {
private static final class DisplayListenerDelegate extends Handler {
public final DisplayListener mListener;
public long mEventsMask;
DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper) {
DisplayListenerDelegate(DisplayListener listener, @NonNull Looper looper,
@EventsMask long eventsMask) {
super(looper, null, true /*async*/);
mListener = listener;
mEventsMask = eventsMask;
}
public void sendDisplayEvent(int displayId, int event) {
public void sendDisplayEvent(int displayId, @DisplayEvent int event) {
Message msg = obtainMessage(event, displayId, 0);
sendMessage(msg);
}
@@ -779,17 +824,27 @@ public final class DisplayManagerGlobal {
removeCallbacksAndMessages(null);
}
public synchronized void setEventsMask(@EventsMask long newEventsMask) {
mEventsMask = newEventsMask;
}
@Override
public void handleMessage(Message msg) {
public synchronized void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_DISPLAY_ADDED:
mListener.onDisplayAdded(msg.arg1);
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
mListener.onDisplayAdded(msg.arg1);
}
break;
case EVENT_DISPLAY_CHANGED:
mListener.onDisplayChanged(msg.arg1);
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) {
mListener.onDisplayChanged(msg.arg1);
}
break;
case EVENT_DISPLAY_REMOVED:
mListener.onDisplayRemoved(msg.arg1);
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) {
mListener.onDisplayRemoved(msg.arg1);
}
break;
}
}

View File

@@ -38,6 +38,7 @@ interface IDisplayManager {
boolean isUidPresentOnDisplay(int uid, int displayId);
void registerCallback(in IDisplayManagerCallback callback);
void registerCallbackWithEventMask(in IDisplayManagerCallback callback, long eventsMask);
// Requires CONFIGURE_WIFI_DISPLAY permission.
// The process must have previously registered a callback.

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2021 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 android.hardware.display;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DisplayManagerGlobalTest {
private static final long ALL_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED
| DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
@Mock
private IDisplayManager mDisplayManager;
@Mock
private DisplayManager.DisplayListener mListener;
@Captor
private ArgumentCaptor<IDisplayManagerCallback> mCallbackCaptor;
private Context mContext;
private DisplayManagerGlobal mDisplayManagerGlobal;
private Handler mHandler;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
Mockito.when(mDisplayManager.getPreferredWideGamutColorSpaceId()).thenReturn(0);
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
mHandler = mContext.getMainThreadHandler();
mDisplayManagerGlobal = new DisplayManagerGlobal(mDisplayManager);
}
@Test
public void testDisplayListenerIsCalled_WhenDisplayEventOccurs() throws RemoteException {
mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, ALL_DISPLAY_EVENTS);
Mockito.verify(mDisplayManager)
.registerCallbackWithEventMask(mCallbackCaptor.capture(), anyLong());
IDisplayManagerCallback callback = mCallbackCaptor.getValue();
int displayId = 1;
callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
waitForHandler();
Mockito.verify(mListener).onDisplayAdded(eq(displayId));
Mockito.verifyNoMoreInteractions(mListener);
Mockito.reset(mListener);
callback.onDisplayEvent(1, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
waitForHandler();
Mockito.verify(mListener).onDisplayChanged(eq(displayId));
Mockito.verifyNoMoreInteractions(mListener);
Mockito.reset(mListener);
callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
waitForHandler();
Mockito.verify(mListener).onDisplayRemoved(eq(displayId));
Mockito.verifyNoMoreInteractions(mListener);
}
@Test
public void testDisplayListenerIsNotCalled_WhenClientIsNotSubscribed() throws RemoteException {
// First we subscribe to all events in order to test that the subsequent calls to
// registerDisplayListener will update the event mask.
mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler, ALL_DISPLAY_EVENTS);
Mockito.verify(mDisplayManager)
.registerCallbackWithEventMask(mCallbackCaptor.capture(), anyLong());
IDisplayManagerCallback callback = mCallbackCaptor.getValue();
int displayId = 1;
mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED);
callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
waitForHandler();
Mockito.verifyZeroInteractions(mListener);
mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
waitForHandler();
Mockito.verifyZeroInteractions(mListener);
mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
ALL_DISPLAY_EVENTS & ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
callback.onDisplayEvent(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
waitForHandler();
Mockito.verifyZeroInteractions(mListener);
}
private void waitForHandler() {
mHandler.runWithScissors(() -> { }, 0);
}
}

View File

@@ -20,6 +20,7 @@ import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT;
import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.hardware.display.DisplayManager.EventsMask;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
@@ -28,6 +29,7 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLI
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
import static android.hardware.display.DisplayManagerGlobal.DisplayEvent;
import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL;
import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL;
import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL;
@@ -125,6 +127,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
/**
@@ -820,14 +823,16 @@ public final class DisplayManagerService extends SystemService {
}
private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid,
int callingUid) {
int callingUid, @EventsMask long eventsMask) {
synchronized (mSyncRoot) {
if (mCallbacks.get(callingPid) != null) {
throw new SecurityException("The calling process has already "
+ "registered an IDisplayManagerCallback.");
CallbackRecord record = mCallbacks.get(callingPid);
if (record != null) {
record.updateEventsMask(eventsMask);
return;
}
CallbackRecord record = new CallbackRecord(callingPid, callingUid, callback);
record = new CallbackRecord(callingPid, callingUid, callback, eventsMask);
try {
IBinder binder = callback.asBinder();
binder.linkToDeath(record, 0);
@@ -1695,7 +1700,7 @@ public final class DisplayManagerService extends SystemService {
}
}
private void sendDisplayEventLocked(int displayId, int event) {
private void sendDisplayEventLocked(int displayId, @DisplayEvent int event) {
Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
mHandler.sendMessage(msg);
}
@@ -1724,7 +1729,8 @@ public final class DisplayManagerService extends SystemService {
// Runs on Handler thread.
// Delivers display event notifications to callbacks.
private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids, int event) {
private void deliverDisplayEvent(int displayId, ArraySet<Integer> uids,
@DisplayEvent int event) {
if (DEBUG) {
Slog.d(TAG, "Delivering display event: displayId="
+ displayId + ", event=" + event);
@@ -2059,13 +2065,20 @@ public final class DisplayManagerService extends SystemService {
public final int mPid;
public final int mUid;
private final IDisplayManagerCallback mCallback;
private @EventsMask AtomicLong mEventsMask;
public boolean mWifiDisplayScanRequested;
CallbackRecord(int pid, int uid, IDisplayManagerCallback callback) {
CallbackRecord(int pid, int uid, IDisplayManagerCallback callback,
@EventsMask long eventsMask) {
mPid = pid;
mUid = uid;
mCallback = callback;
mEventsMask = new AtomicLong(eventsMask);
}
public void updateEventsMask(@EventsMask long eventsMask) {
mEventsMask.set(eventsMask);
}
@Override
@@ -2076,7 +2089,11 @@ public final class DisplayManagerService extends SystemService {
onCallbackDied(this);
}
public void notifyDisplayEventAsync(int displayId, int event) {
public void notifyDisplayEventAsync(int displayId, @DisplayEvent int event) {
if (!shouldSendEvent(event)) {
return;
}
try {
mCallback.onDisplayEvent(displayId, event);
} catch (RemoteException ex) {
@@ -2085,6 +2102,22 @@ public final class DisplayManagerService extends SystemService {
binderDied();
}
}
private boolean shouldSendEvent(@DisplayEvent int event) {
final long mask = mEventsMask.get();
switch (event) {
case DisplayManagerGlobal.EVENT_DISPLAY_ADDED:
return (mask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0;
case DisplayManagerGlobal.EVENT_DISPLAY_CHANGED:
return (mask & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0;
case DisplayManagerGlobal.EVENT_DISPLAY_REMOVED:
return (mask & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0;
default:
// This should never happen.
Slog.e(TAG, "Unknown display event " + event);
return true;
}
}
}
@VisibleForTesting
@@ -2149,6 +2182,14 @@ public final class DisplayManagerService extends SystemService {
@Override // Binder call
public void registerCallback(IDisplayManagerCallback callback) {
registerCallbackWithEventMask(callback, DisplayManager.EVENT_FLAG_DISPLAY_ADDED
| DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
}
@Override // Binder call
public void registerCallbackWithEventMask(IDisplayManagerCallback callback,
@EventsMask long eventsMask) {
if (callback == null) {
throw new IllegalArgumentException("listener must not be null");
}
@@ -2157,7 +2198,7 @@ public final class DisplayManagerService extends SystemService {
final int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
registerCallbackInternal(callback, callingPid, callingUid);
registerCallbackInternal(callback, callingPid, callingUid, eventsMask);
} finally {
Binder.restoreCallingIdentity(token);
}

View File

@@ -93,7 +93,9 @@ public class DisplayManagerServiceTest {
private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10;
private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";
private static final String PACKAGE_NAME = "com.android.frameworks.servicestests";
private static final long ALL_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED
| DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -355,29 +357,13 @@ public class DisplayManagerServiceTest {
// Find the display id of the added FakeDisplayDevice
DisplayManagerService.BinderService bs = displayManager.new BinderService();
final int[] displayIds = bs.getDisplayIds();
assertTrue(displayIds.length > 0);
int displayId = Display.INVALID_DISPLAY;
for (int i = 0; i < displayIds.length; i++) {
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayIds[i]);
if (displayDeviceInfo.equals(ddi)) {
displayId = displayIds[i];
break;
}
}
assertFalse(displayId == Display.INVALID_DISPLAY);
int displayId = getDisplayIdForDisplayDevice(displayManager, bs, displayDevice);
// Setup override DisplayInfo
DisplayInfo overrideInfo = bs.getDisplayInfo(displayId);
displayManager.setDisplayInfoOverrideFromWindowManagerInternal(displayId, overrideInfo);
Handler handler = displayManager.getDisplayHandler();
handler.runWithScissors(() -> {
}, 0 /* now */);
// register display listener callback
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
bs.registerCallback(callback);
FakeDisplayManagerCallback callback = registerDisplayListenerCallback(
displayManager, bs, displayDevice);
// Simulate DisplayDevice change
DisplayDeviceInfo displayDeviceInfo2 = new DisplayDeviceInfo();
@@ -387,9 +373,9 @@ public class DisplayManagerServiceTest {
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);
handler.runWithScissors(() -> {
}, 0 /* now */);
assertTrue(callback.mCalled);
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
assertTrue(callback.mDisplayChangedCalled);
}
/**
@@ -400,7 +386,7 @@ public class DisplayManagerServiceTest {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
Handler handler = displayManager.getDisplayHandler();
handler.runWithScissors(() -> {}, 0 /* now */);
waitForIdleHandler(handler);
try {
displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
@@ -616,7 +602,7 @@ public class DisplayManagerServiceTest {
}
/**
* Tests that there should be a display change notification if the frame rate overrides
* Tests that there is a display change notification if the frame rate override
* list is updated.
*/
@Test
@@ -637,7 +623,7 @@ public class DisplayManagerServiceTest {
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
});
assertTrue(callback.mCalled);
assertTrue(callback.mDisplayChangedCalled);
callback.clear();
updateFrameRateOverride(displayManager, displayDevice,
@@ -645,7 +631,7 @@ public class DisplayManagerServiceTest {
new DisplayEventReceiver.FrameRateOverride(myUid, 30f),
new DisplayEventReceiver.FrameRateOverride(1234, 30f),
});
assertFalse(callback.mCalled);
assertFalse(callback.mDisplayChangedCalled);
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
@@ -653,7 +639,7 @@ public class DisplayManagerServiceTest {
new DisplayEventReceiver.FrameRateOverride(1234, 30f),
new DisplayEventReceiver.FrameRateOverride(5678, 30f),
});
assertTrue(callback.mCalled);
assertTrue(callback.mDisplayChangedCalled);
callback.clear();
updateFrameRateOverride(displayManager, displayDevice,
@@ -661,14 +647,14 @@ public class DisplayManagerServiceTest {
new DisplayEventReceiver.FrameRateOverride(1234, 30f),
new DisplayEventReceiver.FrameRateOverride(5678, 30f),
});
assertTrue(callback.mCalled);
assertTrue(callback.mDisplayChangedCalled);
callback.clear();
updateFrameRateOverride(displayManager, displayDevice,
new DisplayEventReceiver.FrameRateOverride[]{
new DisplayEventReceiver.FrameRateOverride(5678, 30f),
});
assertFalse(callback.mCalled);
assertFalse(callback.mDisplayChangedCalled);
}
/**
@@ -760,6 +746,136 @@ public class DisplayManagerServiceTest {
/*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, ALL_DISPLAY_EVENTS);
waitForIdleHandler(handler);
createFakeDisplayDevice(displayManager, new float[]{60f});
waitForIdleHandler(handler);
assertFalse(callback.mDisplayChangedCalled);
assertFalse(callback.mDisplayRemovedCalled);
assertTrue(callback.mDisplayAddedCalled);
}
/**
* 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 = ALL_DISPLAY_EVENTS
& ~DisplayManager.EVENT_FLAG_DISPLAY_ADDED;
displayManagerBinderService.registerCallbackWithEventMask(callback,
allEventsExceptDisplayAdded);
waitForIdleHandler(handler);
createFakeDisplayDevice(displayManager, new float[]{60f});
waitForIdleHandler(handler);
assertFalse(callback.mDisplayChangedCalled);
assertFalse(callback.mDisplayRemovedCalled);
assertFalse(callback.mDisplayAddedCalled);
}
/**
* 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();
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f});
waitForIdleHandler(handler);
FakeDisplayManagerCallback callback = registerDisplayListenerCallback(
displayManager, displayManagerBinderService, displayDevice);
waitForIdleHandler(handler);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
waitForIdleHandler(handler);
assertFalse(callback.mDisplayChangedCalled);
assertTrue(callback.mDisplayRemovedCalled);
assertFalse(callback.mDisplayAddedCalled);
}
/**
* 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();
Handler handler = displayManager.getDisplayHandler();
waitForIdleHandler(handler);
FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
new float[]{60f});
waitForIdleHandler(handler);
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
long allEventsExceptDisplayRemoved = ALL_DISPLAY_EVENTS
& ~DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
displayManagerBinderService.registerCallbackWithEventMask(callback,
allEventsExceptDisplayRemoved);
waitForIdleHandler(handler);
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
waitForIdleHandler(handler);
assertFalse(callback.mDisplayChangedCalled);
assertFalse(callback.mDisplayRemovedCalled);
assertFalse(callback.mDisplayAddedCalled);
}
private void testDisplayInfoFrameRateOverrideModeCompat(boolean compatChangeEnabled)
throws Exception {
DisplayManagerService displayManager =
@@ -879,8 +995,7 @@ public class DisplayManagerServiceTest {
displayManager.getDisplayDeviceRepository()
.onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);
Handler handler = displayManager.getDisplayHandler();
handler.runWithScissors(() -> {
}, 0 /* now */);
waitForIdleHandler(handler);
}
private void updateFrameRateOverride(DisplayManagerService displayManager,
@@ -906,18 +1021,15 @@ public class DisplayManagerServiceTest {
DisplayManagerService.BinderService displayManagerBinderService,
FakeDisplayDevice displayDevice) {
// Find the display id of the added FakeDisplayDevice
DisplayDeviceInfo displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
displayDevice);
Handler handler = displayManager.getDisplayHandler();
handler.runWithScissors(() -> {
}, 0 /* now */);
waitForIdleHandler(handler);
// register display listener callback
FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(displayId);
displayManagerBinderService.registerCallback(callback);
displayManagerBinderService.registerCallbackWithEventMask(callback, ALL_DISPLAY_EVENTS);
return callback;
}
@@ -951,6 +1063,10 @@ public class DisplayManagerServiceTest {
// 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));
}
@@ -971,21 +1087,41 @@ public class DisplayManagerServiceTest {
private class FakeDisplayManagerCallback extends IDisplayManagerCallback.Stub {
int mDisplayId;
boolean mCalled = false;
boolean mDisplayAddedCalled = false;
boolean mDisplayChangedCalled = false;
boolean mDisplayRemovedCalled = false;
FakeDisplayManagerCallback(int displayId) {
mDisplayId = displayId;
}
FakeDisplayManagerCallback() {
mDisplayId = -1;
}
@Override
public void onDisplayEvent(int displayId, int event) {
if (displayId == mDisplayId && event == DisplayManagerGlobal.EVENT_DISPLAY_CHANGED) {
mCalled = true;
if (mDisplayId != -1 && displayId != mDisplayId) {
return;
}
if (event == DisplayManagerGlobal.EVENT_DISPLAY_ADDED) {
mDisplayAddedCalled = true;
}
if (event == DisplayManagerGlobal.EVENT_DISPLAY_CHANGED) {
mDisplayChangedCalled = true;
}
if (event == DisplayManagerGlobal.EVENT_DISPLAY_REMOVED) {
mDisplayRemovedCalled = true;
}
}
public void clear() {
mCalled = false;
mDisplayAddedCalled = false;
mDisplayChangedCalled = false;
mDisplayRemovedCalled = false;
}
}