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:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user